1 | //===--- SetLongJmpCheck.cpp - clang-tidy----------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "SetLongJmpCheck.h" |
10 | #include "clang/AST/ASTContext.h" |
11 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
12 | #include "clang/Frontend/CompilerInstance.h" |
13 | #include "clang/Lex/PPCallbacks.h" |
14 | #include "clang/Lex/Preprocessor.h" |
15 | |
16 | using namespace clang::ast_matchers; |
17 | |
18 | namespace clang::tidy::cert { |
19 | |
20 | namespace { |
21 | const char DiagWording[] = |
22 | "do not call %0; consider using exception handling instead" ; |
23 | |
24 | class SetJmpMacroCallbacks : public PPCallbacks { |
25 | SetLongJmpCheck &Check; |
26 | |
27 | public: |
28 | explicit SetJmpMacroCallbacks(SetLongJmpCheck &Check) : Check(Check) {} |
29 | |
30 | void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, |
31 | SourceRange Range, const MacroArgs *Args) override { |
32 | const auto *II = MacroNameTok.getIdentifierInfo(); |
33 | if (!II) |
34 | return; |
35 | |
36 | if (II->getName() == "setjmp" ) |
37 | Check.diag(Loc: Range.getBegin(), Description: DiagWording) << II; |
38 | } |
39 | }; |
40 | } // namespace |
41 | |
42 | void SetLongJmpCheck::registerPPCallbacks(const SourceManager &SM, |
43 | Preprocessor *PP, |
44 | Preprocessor *ModuleExpanderPP) { |
45 | // Per [headers]p5, setjmp must be exposed as a macro instead of a function, |
46 | // despite the allowance in C for setjmp to also be an extern function. |
47 | PP->addPPCallbacks(C: std::make_unique<SetJmpMacroCallbacks>(args&: *this)); |
48 | } |
49 | |
50 | void SetLongJmpCheck::registerMatchers(MatchFinder *Finder) { |
51 | // In case there is an implementation that happens to define setjmp as a |
52 | // function instead of a macro, this will also catch use of it. However, we |
53 | // are primarily searching for uses of longjmp. |
54 | Finder->addMatcher( |
55 | NodeMatch: callExpr(callee(InnerMatcher: functionDecl(hasAnyName("setjmp" , "longjmp" )))) |
56 | .bind(ID: "expr" ), |
57 | Action: this); |
58 | } |
59 | |
60 | void SetLongJmpCheck::check(const MatchFinder::MatchResult &Result) { |
61 | const auto *E = Result.Nodes.getNodeAs<CallExpr>(ID: "expr" ); |
62 | diag(E->getExprLoc(), DiagWording) << cast<NamedDecl>(Val: E->getCalleeDecl()); |
63 | } |
64 | |
65 | } // namespace clang::tidy::cert |
66 | |