diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp b/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp new file mode 100644 index 00000000000..bc5b35341f2 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp @@ -0,0 +1,77 @@ +//===--- SetLongJmpCheck.cpp - clang-tidy----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SetLongJmpCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +const char SetLongJmpCheck::DiagWording[] = + "do not call %0; consider using exception handling instead"; + +namespace { +class SetJmpMacroCallbacks : public PPCallbacks { + SetLongJmpCheck &Check; + +public: + explicit SetJmpMacroCallbacks(SetLongJmpCheck &Check) : Check(Check) {} + + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override { + const auto *II = MacroNameTok.getIdentifierInfo(); + if (!II) + return; + + if (II->getName() == "setjmp") + Check.diag(Range.getBegin(), Check.DiagWording) << II; + } +}; +} // namespace + +void SetLongJmpCheck::registerPPCallbacks(CompilerInstance &Compiler) { + // This checker only applies to C++, where exception handling is a superior + // solution to setjmp/longjmp calls. + if (!getLangOpts().CPlusPlus) + return; + + // Per [headers]p5, setjmp must be exposed as a macro instead of a function, + // despite the allowance in C for setjmp to also be an extern function. + Compiler.getPreprocessor().addPPCallbacks( + llvm::make_unique<SetJmpMacroCallbacks>(*this)); +} + +void SetLongJmpCheck::registerMatchers(MatchFinder *Finder) { + // This checker only applies to C++, where exception handling is a superior + // solution to setjmp/longjmp calls. + if (!getLangOpts().CPlusPlus) + return; + + // In case there is an implementation that happens to define setjmp as a + // function instead of a macro, this will also catch use of it. However, we + // are primarily searching for uses of longjmp. + Finder->addMatcher(callExpr(callee(functionDecl(anyOf(hasName("setjmp"), + hasName("longjmp"))))) + .bind("expr"), + this); +} + +void SetLongJmpCheck::check(const MatchFinder::MatchResult &Result) { + const auto *E = Result.Nodes.getNodeAs<CallExpr>("expr"); + diag(E->getExprLoc(), DiagWording) << cast<NamedDecl>(E->getCalleeDecl()); +} + +} // namespace tidy +} // namespace clang |

