/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- AnalysisOrderChecker - Print callbacks called ------------*- C++ -*-===// |
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 | | // This checker prints callbacks that are called during analysis. |
10 | | // This is required to ensure that callbacks are fired in order |
11 | | // and do not duplicate or get lost. |
12 | | // Feel free to extend this checker with any callback you need to check. |
13 | | // |
14 | | //===----------------------------------------------------------------------===// |
15 | | |
16 | | #include "clang/AST/ExprCXX.h" |
17 | | #include "clang/Analysis/CFGStmtMap.h" |
18 | | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
19 | | #include "clang/StaticAnalyzer/Core/Checker.h" |
20 | | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
21 | | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
22 | | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
23 | | #include "llvm/Support/ErrorHandling.h" |
24 | | |
25 | | using namespace clang; |
26 | | using namespace ento; |
27 | | |
28 | | namespace { |
29 | | |
30 | | class AnalysisOrderChecker |
31 | | : public Checker< |
32 | | check::PreStmt<CastExpr>, check::PostStmt<CastExpr>, |
33 | | check::PreStmt<ArraySubscriptExpr>, |
34 | | check::PostStmt<ArraySubscriptExpr>, check::PreStmt<CXXNewExpr>, |
35 | | check::PostStmt<CXXNewExpr>, check::PreStmt<CXXDeleteExpr>, |
36 | | check::PostStmt<CXXDeleteExpr>, check::PreStmt<CXXConstructExpr>, |
37 | | check::PostStmt<CXXConstructExpr>, check::PreStmt<OffsetOfExpr>, |
38 | | check::PostStmt<OffsetOfExpr>, check::PreCall, check::PostCall, |
39 | | check::EndFunction, check::EndAnalysis, check::NewAllocator, |
40 | | check::Bind, check::PointerEscape, check::RegionChanges, |
41 | | check::LiveSymbols, eval::Call> { |
42 | | |
43 | | bool isCallbackEnabled(const AnalyzerOptions &Opts, |
44 | 727 | StringRef CallbackName) const { |
45 | 727 | return Opts.getCheckerBooleanOption(this, "*") || |
46 | 727 | Opts.getCheckerBooleanOption(this, CallbackName); |
47 | 727 | } |
48 | | |
49 | 462 | bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const { |
50 | 462 | AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions(); |
51 | 462 | return isCallbackEnabled(Opts, CallbackName); |
52 | 462 | } |
53 | | |
54 | 244 | bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const { |
55 | 244 | AnalyzerOptions &Opts = State->getStateManager().getOwningEngine() |
56 | 244 | .getAnalysisManager().getAnalyzerOptions(); |
57 | 244 | return isCallbackEnabled(Opts, CallbackName); |
58 | 244 | } |
59 | | |
60 | | public: |
61 | 71 | void checkPreStmt(const CastExpr *CE, CheckerContext &C) const { |
62 | 71 | if (isCallbackEnabled(C, "PreStmtCastExpr")) |
63 | 2 | llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName() |
64 | 2 | << ")\n"; |
65 | 71 | } |
66 | | |
67 | 71 | void checkPostStmt(const CastExpr *CE, CheckerContext &C) const { |
68 | 71 | if (isCallbackEnabled(C, "PostStmtCastExpr")) |
69 | 2 | llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName() |
70 | 2 | << ")\n"; |
71 | 71 | } |
72 | | |
73 | | void checkPreStmt(const ArraySubscriptExpr *SubExpr, |
74 | 0 | CheckerContext &C) const { |
75 | 0 | if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr")) |
76 | 0 | llvm::errs() << "PreStmt<ArraySubscriptExpr>\n"; |
77 | 0 | } |
78 | | |
79 | | void checkPostStmt(const ArraySubscriptExpr *SubExpr, |
80 | 0 | CheckerContext &C) const { |
81 | 0 | if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr")) |
82 | 0 | llvm::errs() << "PostStmt<ArraySubscriptExpr>\n"; |
83 | 0 | } |
84 | | |
85 | 10 | void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const { |
86 | 10 | if (isCallbackEnabled(C, "PreStmtCXXNewExpr")) |
87 | 8 | llvm::errs() << "PreStmt<CXXNewExpr>\n"; |
88 | 10 | } |
89 | | |
90 | 10 | void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const { |
91 | 10 | if (isCallbackEnabled(C, "PostStmtCXXNewExpr")) |
92 | 8 | llvm::errs() << "PostStmt<CXXNewExpr>\n"; |
93 | 10 | } |
94 | | |
95 | 4 | void checkPreStmt(const CXXDeleteExpr *NE, CheckerContext &C) const { |
96 | 4 | if (isCallbackEnabled(C, "PreStmtCXXDeleteExpr")) |
97 | 2 | llvm::errs() << "PreStmt<CXXDeleteExpr>\n"; |
98 | 4 | } |
99 | | |
100 | 5 | void checkPostStmt(const CXXDeleteExpr *NE, CheckerContext &C) const { |
101 | 5 | if (isCallbackEnabled(C, "PostStmtCXXDeleteExpr")) |
102 | 2 | llvm::errs() << "PostStmt<CXXDeleteExpr>\n"; |
103 | 5 | } |
104 | | |
105 | 21 | void checkPreStmt(const CXXConstructExpr *NE, CheckerContext &C) const { |
106 | 21 | if (isCallbackEnabled(C, "PreStmtCXXConstructExpr")) |
107 | 0 | llvm::errs() << "PreStmt<CXXConstructExpr>\n"; |
108 | 21 | } |
109 | | |
110 | 21 | void checkPostStmt(const CXXConstructExpr *NE, CheckerContext &C) const { |
111 | 21 | if (isCallbackEnabled(C, "PostStmtCXXConstructExpr")) |
112 | 0 | llvm::errs() << "PostStmt<CXXConstructExpr>\n"; |
113 | 21 | } |
114 | | |
115 | 1 | void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { |
116 | 1 | if (isCallbackEnabled(C, "PreStmtOffsetOfExpr")) |
117 | 1 | llvm::errs() << "PreStmt<OffsetOfExpr>\n"; |
118 | 1 | } |
119 | | |
120 | 1 | void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { |
121 | 1 | if (isCallbackEnabled(C, "PostStmtOffsetOfExpr")) |
122 | 1 | llvm::errs() << "PostStmt<OffsetOfExpr>\n"; |
123 | 1 | } |
124 | | |
125 | 48 | bool evalCall(const CallEvent &Call, CheckerContext &C) const { |
126 | 48 | if (isCallbackEnabled(C, "EvalCall")) { |
127 | 3 | llvm::errs() << "EvalCall"; |
128 | 3 | if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) |
129 | 3 | llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; |
130 | 3 | llvm::errs() << " {argno: " << Call.getNumArgs() << '}'; |
131 | 3 | llvm::errs() << " [" << Call.getKindAsString() << ']'; |
132 | 3 | llvm::errs() << '\n'; |
133 | 3 | return true; |
134 | 3 | } |
135 | 45 | return false; |
136 | 48 | } |
137 | | |
138 | 64 | void checkPreCall(const CallEvent &Call, CheckerContext &C) const { |
139 | 64 | if (isCallbackEnabled(C, "PreCall")) { |
140 | 56 | llvm::errs() << "PreCall"; |
141 | 56 | if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) |
142 | 56 | llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; |
143 | 56 | llvm::errs() << " [" << Call.getKindAsString() << ']'; |
144 | 56 | llvm::errs() << '\n'; |
145 | 56 | } |
146 | 64 | } |
147 | | |
148 | 64 | void checkPostCall(const CallEvent &Call, CheckerContext &C) const { |
149 | 64 | if (isCallbackEnabled(C, "PostCall")) { |
150 | 58 | llvm::errs() << "PostCall"; |
151 | 58 | if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) |
152 | 58 | llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; |
153 | 58 | llvm::errs() << " [" << Call.getKindAsString() << ']'; |
154 | 58 | llvm::errs() << '\n'; |
155 | 58 | } |
156 | 64 | } |
157 | | |
158 | 43 | void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const { |
159 | 43 | if (isCallbackEnabled(C, "EndFunction")) { |
160 | 3 | llvm::errs() << "EndFunction\nReturnStmt: " << (S ? "yes"2 : "no"1 ) << "\n"; |
161 | 3 | if (!S) |
162 | 1 | return; |
163 | | |
164 | 2 | llvm::errs() << "CFGElement: "; |
165 | 2 | CFGStmtMap *Map = C.getCurrentAnalysisDeclContext()->getCFGStmtMap(); |
166 | 2 | CFGElement LastElement = Map->getBlock(S)->back(); |
167 | | |
168 | 2 | if (LastElement.getAs<CFGStmt>()) |
169 | 1 | llvm::errs() << "CFGStmt\n"; |
170 | 1 | else if (LastElement.getAs<CFGAutomaticObjDtor>()) |
171 | 1 | llvm::errs() << "CFGAutomaticObjDtor\n"; |
172 | 2 | } |
173 | 43 | } |
174 | | |
175 | | void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, |
176 | 21 | ExprEngine &Eng) const { |
177 | 21 | if (isCallbackEnabled(BR.getAnalyzerOptions(), "EndAnalysis")) |
178 | 0 | llvm::errs() << "EndAnalysis\n"; |
179 | 21 | } |
180 | | |
181 | | void checkNewAllocator(const CXXAllocatorCall &Call, |
182 | 9 | CheckerContext &C) const { |
183 | 9 | if (isCallbackEnabled(C, "NewAllocator")) |
184 | 1 | llvm::errs() << "NewAllocator\n"; |
185 | 9 | } |
186 | | |
187 | 19 | void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const { |
188 | 19 | if (isCallbackEnabled(C, "Bind")) |
189 | 1 | llvm::errs() << "Bind\n"; |
190 | 19 | } |
191 | | |
192 | 123 | void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const { |
193 | 123 | if (isCallbackEnabled(State, "LiveSymbols")) |
194 | 10 | llvm::errs() << "LiveSymbols\n"; |
195 | 123 | } |
196 | | |
197 | | ProgramStateRef |
198 | | checkRegionChanges(ProgramStateRef State, |
199 | | const InvalidatedSymbols *Invalidated, |
200 | | ArrayRef<const MemRegion *> ExplicitRegions, |
201 | | ArrayRef<const MemRegion *> Regions, |
202 | 76 | const LocationContext *LCtx, const CallEvent *Call) const { |
203 | 76 | if (isCallbackEnabled(State, "RegionChanges")) |
204 | 2 | llvm::errs() << "RegionChanges\n"; |
205 | 76 | return State; |
206 | 76 | } |
207 | | |
208 | | ProgramStateRef checkPointerEscape(ProgramStateRef State, |
209 | | const InvalidatedSymbols &Escaped, |
210 | | const CallEvent *Call, |
211 | 45 | PointerEscapeKind Kind) const { |
212 | 45 | if (isCallbackEnabled(State, "PointerEscape")) |
213 | 3 | llvm::errs() << "PointerEscape\n"; |
214 | 45 | return State; |
215 | 45 | } |
216 | | }; |
217 | | } // end anonymous namespace |
218 | | |
219 | | //===----------------------------------------------------------------------===// |
220 | | // Registration. |
221 | | //===----------------------------------------------------------------------===// |
222 | | |
223 | 12 | void ento::registerAnalysisOrderChecker(CheckerManager &mgr) { |
224 | 12 | mgr.registerChecker<AnalysisOrderChecker>(); |
225 | 12 | } |
226 | | |
227 | 24 | bool ento::shouldRegisterAnalysisOrderChecker(const CheckerManager &mgr) { |
228 | 24 | return true; |
229 | 24 | } |