1 | //===--- StaticObjectExceptionCheck.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 "StaticObjectExceptionCheck.h" |
10 | #include "../utils/Matchers.h" |
11 | #include "clang/AST/ASTContext.h" |
12 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
13 | |
14 | using namespace clang::ast_matchers; |
15 | |
16 | namespace clang::tidy::cert { |
17 | |
18 | void StaticObjectExceptionCheck::registerMatchers(MatchFinder *Finder) { |
19 | // Match any static or thread_local variable declaration that has an |
20 | // initializer that can throw. |
21 | Finder->addMatcher( |
22 | NodeMatch: traverse( |
23 | TK: TK_AsIs, |
24 | InnerMatcher: varDecl( |
25 | anyOf(hasThreadStorageDuration(), hasStaticStorageDuration()), |
26 | unless(anyOf(isConstexpr(), hasType(InnerMatcher: cxxRecordDecl(isLambda())), |
27 | hasAncestor(functionDecl()))), |
28 | anyOf(hasDescendant(cxxConstructExpr(hasDeclaration( |
29 | InnerMatcher: cxxConstructorDecl(unless(isNoThrow())).bind(ID: "func" )))), |
30 | hasDescendant(cxxNewExpr(hasDeclaration( |
31 | InnerMatcher: functionDecl(unless(isNoThrow())).bind(ID: "func" )))), |
32 | hasDescendant(callExpr(hasDeclaration( |
33 | InnerMatcher: functionDecl(unless(isNoThrow())).bind(ID: "func" )))))) |
34 | .bind(ID: "var" )), |
35 | Action: this); |
36 | } |
37 | |
38 | void StaticObjectExceptionCheck::check(const MatchFinder::MatchResult &Result) { |
39 | const auto *VD = Result.Nodes.getNodeAs<VarDecl>(ID: "var" ); |
40 | const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>(ID: "func" ); |
41 | |
42 | diag(VD->getLocation(), |
43 | "initialization of %0 with %select{static|thread_local}1 storage " |
44 | "duration may throw an exception that cannot be caught" ) |
45 | << VD << (VD->getStorageDuration() == SD_Static ? 0 : 1); |
46 | |
47 | SourceLocation FuncLocation = Func->getLocation(); |
48 | if (FuncLocation.isValid()) { |
49 | diag(Loc: FuncLocation, |
50 | Description: "possibly throwing %select{constructor|function}0 declared here" , |
51 | Level: DiagnosticIDs::Note) |
52 | << (isa<CXXConstructorDecl>(Val: Func) ? 0 : 1); |
53 | } |
54 | } |
55 | |
56 | } // namespace clang::tidy::cert |
57 | |