/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===// |
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 | | // "Meta" ASTConsumer for running different source analyses. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" |
14 | | #include "ModelInjector.h" |
15 | | #include "clang/AST/Decl.h" |
16 | | #include "clang/AST/DeclCXX.h" |
17 | | #include "clang/AST/DeclObjC.h" |
18 | | #include "clang/AST/RecursiveASTVisitor.h" |
19 | | #include "clang/Analysis/Analyses/LiveVariables.h" |
20 | | #include "clang/Analysis/CFG.h" |
21 | | #include "clang/Analysis/CallGraph.h" |
22 | | #include "clang/Analysis/CodeInjector.h" |
23 | | #include "clang/Analysis/PathDiagnostic.h" |
24 | | #include "clang/Basic/SourceManager.h" |
25 | | #include "clang/CrossTU/CrossTranslationUnit.h" |
26 | | #include "clang/Frontend/CompilerInstance.h" |
27 | | #include "clang/Lex/Preprocessor.h" |
28 | | #include "clang/Rewrite/Core/Rewriter.h" |
29 | | #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" |
30 | | #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" |
31 | | #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" |
32 | | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
33 | | #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" |
34 | | #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" |
35 | | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" |
36 | | #include "llvm/ADT/PostOrderIterator.h" |
37 | | #include "llvm/ADT/Statistic.h" |
38 | | #include "llvm/Support/FileSystem.h" |
39 | | #include "llvm/Support/Path.h" |
40 | | #include "llvm/Support/Program.h" |
41 | | #include "llvm/Support/Timer.h" |
42 | | #include "llvm/Support/raw_ostream.h" |
43 | | #include <memory> |
44 | | #include <queue> |
45 | | #include <utility> |
46 | | |
47 | | using namespace clang; |
48 | | using namespace ento; |
49 | | |
50 | | #define DEBUG_TYPE "AnalysisConsumer" |
51 | | |
52 | | STATISTIC(NumFunctionTopLevel, "The # of functions at top level."); |
53 | | STATISTIC(NumFunctionsAnalyzed, |
54 | | "The # of functions and blocks analyzed (as top level " |
55 | | "with inlining turned on)."); |
56 | | STATISTIC(NumBlocksInAnalyzedFunctions, |
57 | | "The # of basic blocks in the analyzed functions."); |
58 | | STATISTIC(NumVisitedBlocksInAnalyzedFunctions, |
59 | | "The # of visited basic blocks in the analyzed functions."); |
60 | | STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks."); |
61 | | STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function."); |
62 | | |
63 | | //===----------------------------------------------------------------------===// |
64 | | // AnalysisConsumer declaration. |
65 | | //===----------------------------------------------------------------------===// |
66 | | |
67 | | namespace { |
68 | | |
69 | | class AnalysisConsumer : public AnalysisASTConsumer, |
70 | | public RecursiveASTVisitor<AnalysisConsumer> { |
71 | | enum { |
72 | | AM_None = 0, |
73 | | AM_Syntax = 0x1, |
74 | | AM_Path = 0x2 |
75 | | }; |
76 | | typedef unsigned AnalysisMode; |
77 | | |
78 | | /// Mode of the analyzes while recursively visiting Decls. |
79 | | AnalysisMode RecVisitorMode; |
80 | | /// Bug Reporter to use while recursively visiting Decls. |
81 | | BugReporter *RecVisitorBR; |
82 | | |
83 | | std::vector<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns; |
84 | | |
85 | | public: |
86 | | ASTContext *Ctx; |
87 | | Preprocessor &PP; |
88 | | const std::string OutDir; |
89 | | AnalyzerOptionsRef Opts; |
90 | | ArrayRef<std::string> Plugins; |
91 | | CodeInjector *Injector; |
92 | | cross_tu::CrossTranslationUnitContext CTU; |
93 | | |
94 | | /// Stores the declarations from the local translation unit. |
95 | | /// Note, we pre-compute the local declarations at parse time as an |
96 | | /// optimization to make sure we do not deserialize everything from disk. |
97 | | /// The local declaration to all declarations ratio might be very small when |
98 | | /// working with a PCH file. |
99 | | SetOfDecls LocalTUDecls; |
100 | | |
101 | | // Set of PathDiagnosticConsumers. Owned by AnalysisManager. |
102 | | PathDiagnosticConsumers PathConsumers; |
103 | | |
104 | | StoreManagerCreator CreateStoreMgr; |
105 | | ConstraintManagerCreator CreateConstraintMgr; |
106 | | |
107 | | std::unique_ptr<CheckerManager> checkerMgr; |
108 | | std::unique_ptr<AnalysisManager> Mgr; |
109 | | |
110 | | /// Time the analyzes time of each translation unit. |
111 | | std::unique_ptr<llvm::TimerGroup> AnalyzerTimers; |
112 | | std::unique_ptr<llvm::Timer> SyntaxCheckTimer; |
113 | | std::unique_ptr<llvm::Timer> ExprEngineTimer; |
114 | | std::unique_ptr<llvm::Timer> BugReporterTimer; |
115 | | |
116 | | /// The information about analyzed functions shared throughout the |
117 | | /// translation unit. |
118 | | FunctionSummariesTy FunctionSummaries; |
119 | | |
120 | | AnalysisConsumer(CompilerInstance &CI, const std::string &outdir, |
121 | | AnalyzerOptionsRef opts, ArrayRef<std::string> plugins, |
122 | | CodeInjector *injector) |
123 | | : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr), |
124 | | PP(CI.getPreprocessor()), OutDir(outdir), Opts(std::move(opts)), |
125 | 1.33k | Plugins(plugins), Injector(injector), CTU(CI) { |
126 | 1.33k | DigestAnalyzerOptions(); |
127 | 1.33k | if (Opts->PrintStats || Opts->ShouldSerializeStats1.33k ) { |
128 | 3 | AnalyzerTimers = std::make_unique<llvm::TimerGroup>( |
129 | 3 | "analyzer", "Analyzer timers"); |
130 | 3 | SyntaxCheckTimer = std::make_unique<llvm::Timer>( |
131 | 3 | "syntaxchecks", "Syntax-based analysis time", *AnalyzerTimers); |
132 | 3 | ExprEngineTimer = std::make_unique<llvm::Timer>( |
133 | 3 | "exprengine", "Path exploration time", *AnalyzerTimers); |
134 | 3 | BugReporterTimer = std::make_unique<llvm::Timer>( |
135 | 3 | "bugreporter", "Path-sensitive report post-processing time", |
136 | 3 | *AnalyzerTimers); |
137 | 3 | llvm::EnableStatistics(/* PrintOnExit= */ false); |
138 | 3 | } |
139 | 1.33k | } |
140 | | |
141 | 1.33k | ~AnalysisConsumer() override { |
142 | 1.33k | if (Opts->PrintStats) { |
143 | 2 | llvm::PrintStatistics(); |
144 | 2 | } |
145 | 1.33k | } |
146 | | |
147 | 1.33k | void DigestAnalyzerOptions() { |
148 | 1.33k | switch (Opts->AnalysisDiagOpt) { |
149 | 0 | case PD_NONE: |
150 | 0 | break; |
151 | 0 | #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ |
152 | 1.33k | case PD_##NAME: \ |
153 | 1.33k | CREATEFN(Opts->getDiagOpts(), PathConsumers, OutDir, PP, CTU); \ |
154 | 1.33k | break; |
155 | 0 | #include "clang/StaticAnalyzer/Core/Analyses.def" |
156 | 0 | default: |
157 | 0 | llvm_unreachable("Unknown analyzer output type!"); |
158 | 1.33k | } |
159 | | |
160 | | // Create the analyzer component creators. |
161 | 1.33k | switch (Opts->AnalysisStoreOpt) { |
162 | 0 | default: |
163 | 0 | llvm_unreachable("Unknown store manager."); |
164 | 0 | #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ |
165 | 1.33k | case NAME##Model: CreateStoreMgr = CREATEFN; break; |
166 | 0 | #include "clang/StaticAnalyzer/Core/Analyses.def" |
167 | 1.33k | } |
168 | | |
169 | 1.33k | switch (Opts->AnalysisConstraintsOpt) { |
170 | 0 | default: |
171 | 0 | llvm_unreachable("Unknown constraint manager."); |
172 | 0 | #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ |
173 | 1.33k | case NAME##Model: CreateConstraintMgr = CREATEFN; break; |
174 | 0 | #include "clang/StaticAnalyzer/Core/Analyses.def" |
175 | 1.33k | } |
176 | 1.33k | } |
177 | | |
178 | | void DisplayFunction(const Decl *D, AnalysisMode Mode, |
179 | 32.5k | ExprEngine::InliningModes IMode) { |
180 | 32.5k | if (!Opts->AnalyzerDisplayProgress) |
181 | 32.5k | return; |
182 | | |
183 | 33 | SourceManager &SM = Mgr->getASTContext().getSourceManager(); |
184 | 33 | PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); |
185 | 33 | if (Loc.isValid()) { |
186 | 33 | llvm::errs() << "ANALYZE"; |
187 | | |
188 | 33 | if (Mode == AM_Syntax) |
189 | 17 | llvm::errs() << " (Syntax)"; |
190 | 16 | else if (Mode == AM_Path) { |
191 | 16 | llvm::errs() << " (Path, "; |
192 | 16 | switch (IMode) { |
193 | 0 | case ExprEngine::Inline_Minimal: |
194 | 0 | llvm::errs() << " Inline_Minimal"; |
195 | 0 | break; |
196 | 16 | case ExprEngine::Inline_Regular: |
197 | 16 | llvm::errs() << " Inline_Regular"; |
198 | 16 | break; |
199 | 16 | } |
200 | 16 | llvm::errs() << ")"; |
201 | 16 | } else |
202 | 16 | assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!"); |
203 | | |
204 | 33 | llvm::errs() << ": " << Loc.getFilename() << ' ' << getFunctionName(D) |
205 | 33 | << '\n'; |
206 | 33 | } |
207 | 33 | } |
208 | | |
209 | 1.33k | void Initialize(ASTContext &Context) override { |
210 | 1.33k | Ctx = &Context; |
211 | 1.33k | checkerMgr = std::make_unique<CheckerManager>(*Ctx, *Opts, PP, Plugins, |
212 | 1.33k | CheckerRegistrationFns); |
213 | | |
214 | 1.33k | Mgr = std::make_unique<AnalysisManager>(*Ctx, PP, PathConsumers, |
215 | 1.33k | CreateStoreMgr, CreateConstraintMgr, |
216 | 1.33k | checkerMgr.get(), *Opts, Injector); |
217 | 1.33k | } |
218 | | |
219 | | /// Store the top level decls in the set to be processed later on. |
220 | | /// (Doing this pre-processing avoids deserialization of data from PCH.) |
221 | | bool HandleTopLevelDecl(DeclGroupRef D) override; |
222 | | void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override; |
223 | | |
224 | | void HandleTranslationUnit(ASTContext &C) override; |
225 | | |
226 | | /// Determine which inlining mode should be used when this function is |
227 | | /// analyzed. This allows to redefine the default inlining policies when |
228 | | /// analyzing a given function. |
229 | | ExprEngine::InliningModes |
230 | | getInliningModeForFunction(const Decl *D, const SetOfConstDecls &Visited); |
231 | | |
232 | | /// Build the call graph for all the top level decls of this TU and |
233 | | /// use it to define the order in which the functions should be visited. |
234 | | void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize); |
235 | | |
236 | | /// Run analyzes(syntax or path sensitive) on the given function. |
237 | | /// \param Mode - determines if we are requesting syntax only or path |
238 | | /// sensitive only analysis. |
239 | | /// \param VisitedCallees - The output parameter, which is populated with the |
240 | | /// set of functions which should be considered analyzed after analyzing the |
241 | | /// given root function. |
242 | | void HandleCode(Decl *D, AnalysisMode Mode, |
243 | | ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal, |
244 | | SetOfConstDecls *VisitedCallees = nullptr); |
245 | | |
246 | | void RunPathSensitiveChecks(Decl *D, |
247 | | ExprEngine::InliningModes IMode, |
248 | | SetOfConstDecls *VisitedCallees); |
249 | | |
250 | | /// Visitors for the RecursiveASTVisitor. |
251 | 380k | bool shouldWalkTypesOfTypeLocs() const { return false; } |
252 | | |
253 | | /// Handle callbacks for arbitrary Decls. |
254 | 248k | bool VisitDecl(Decl *D) { |
255 | 248k | AnalysisMode Mode = getModeForDecl(D, RecVisitorMode); |
256 | 248k | if (Mode & AM_Syntax) { |
257 | 79.4k | if (SyntaxCheckTimer) |
258 | 7 | SyntaxCheckTimer->startTimer(); |
259 | 79.4k | checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR); |
260 | 79.4k | if (SyntaxCheckTimer) |
261 | 7 | SyntaxCheckTimer->stopTimer(); |
262 | 79.4k | } |
263 | 248k | return true; |
264 | 248k | } |
265 | | |
266 | 97.0k | bool VisitVarDecl(VarDecl *VD) { |
267 | 97.0k | if (!Opts->IsNaiveCTUEnabled) |
268 | 96.9k | return true; |
269 | | |
270 | 99 | if (VD->hasExternalStorage() || VD->isStaticDataMember()78 ) { |
271 | 33 | if (!cross_tu::containsConst(VD, *Ctx)) |
272 | 1 | return true; |
273 | 66 | } else { |
274 | | // Cannot be initialized in another TU. |
275 | 66 | return true; |
276 | 66 | } |
277 | | |
278 | 32 | if (VD->getAnyInitializer()) |
279 | 10 | return true; |
280 | | |
281 | 22 | llvm::Expected<const VarDecl *> CTUDeclOrError = |
282 | 22 | CTU.getCrossTUDefinition(VD, Opts->CTUDir, Opts->CTUIndexName, |
283 | 22 | Opts->DisplayCTUProgress); |
284 | | |
285 | 22 | if (!CTUDeclOrError) { |
286 | 0 | handleAllErrors(CTUDeclOrError.takeError(), |
287 | 0 | [&](const cross_tu::IndexError &IE) { |
288 | 0 | CTU.emitCrossTUDiagnostics(IE); |
289 | 0 | }); |
290 | 0 | } |
291 | | |
292 | 22 | return true; |
293 | 22 | } |
294 | | |
295 | 65.2k | bool VisitFunctionDecl(FunctionDecl *FD) { |
296 | 65.2k | IdentifierInfo *II = FD->getIdentifier(); |
297 | 65.2k | if (II && II->getName().startswith("__inline")43.6k ) |
298 | 3 | return true; |
299 | | |
300 | | // We skip function template definitions, as their semantics is |
301 | | // only determined when they are instantiated. |
302 | 65.2k | if (FD->isThisDeclarationADefinition() && |
303 | 35.3k | !FD->isDependentContext()) { |
304 | 17.4k | assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false); |
305 | 17.4k | HandleCode(FD, RecVisitorMode); |
306 | 17.4k | } |
307 | 65.2k | return true; |
308 | 65.2k | } |
309 | | |
310 | 4.29k | bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { |
311 | 4.29k | if (MD->isThisDeclarationADefinition()) { |
312 | 1.15k | assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false); |
313 | 1.15k | HandleCode(MD, RecVisitorMode); |
314 | 1.15k | } |
315 | 4.29k | return true; |
316 | 4.29k | } |
317 | | |
318 | 373 | bool VisitBlockDecl(BlockDecl *BD) { |
319 | 373 | if (BD->hasBody()) { |
320 | 373 | assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false); |
321 | | // Since we skip function template definitions, we should skip blocks |
322 | | // declared in those functions as well. |
323 | 373 | if (!BD->isDependentContext()) { |
324 | 364 | HandleCode(BD, RecVisitorMode); |
325 | 364 | } |
326 | 373 | } |
327 | 373 | return true; |
328 | 373 | } |
329 | | |
330 | 19 | void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) override { |
331 | 19 | PathConsumers.push_back(Consumer); |
332 | 19 | } |
333 | | |
334 | 19 | void AddCheckerRegistrationFn(std::function<void(CheckerRegistry&)> Fn) override { |
335 | 19 | CheckerRegistrationFns.push_back(std::move(Fn)); |
336 | 19 | } |
337 | | |
338 | | private: |
339 | | void storeTopLevelDecls(DeclGroupRef DG); |
340 | | std::string getFunctionName(const Decl *D); |
341 | | |
342 | | /// Check if we should skip (not analyze) the given function. |
343 | | AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode); |
344 | | void runAnalysisOnTranslationUnit(ASTContext &C); |
345 | | |
346 | | /// Print \p S to stderr if \c Opts->AnalyzerDisplayProgress is set. |
347 | | void reportAnalyzerProgress(StringRef S); |
348 | | }; // namespace |
349 | | } // end anonymous namespace |
350 | | |
351 | | |
352 | | //===----------------------------------------------------------------------===// |
353 | | // AnalysisConsumer implementation. |
354 | | //===----------------------------------------------------------------------===// |
355 | 33.0k | bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) { |
356 | 33.0k | storeTopLevelDecls(DG); |
357 | 33.0k | return true; |
358 | 33.0k | } |
359 | | |
360 | 13 | void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) { |
361 | 13 | storeTopLevelDecls(DG); |
362 | 13 | } |
363 | | |
364 | 33.0k | void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) { |
365 | 68.7k | for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I35.7k ) { |
366 | | |
367 | | // Skip ObjCMethodDecl, wait for the objc container to avoid |
368 | | // analyzing twice. |
369 | 35.7k | if (isa<ObjCMethodDecl>(*I)) |
370 | 1.15k | continue; |
371 | | |
372 | 34.5k | LocalTUDecls.push_back(*I); |
373 | 34.5k | } |
374 | 33.0k | } |
375 | | |
376 | | static bool shouldSkipFunction(const Decl *D, |
377 | | const SetOfConstDecls &Visited, |
378 | 26.3k | const SetOfConstDecls &VisitedAsTopLevel) { |
379 | 26.3k | if (VisitedAsTopLevel.count(D)) |
380 | 0 | return true; |
381 | | |
382 | | // Skip analysis of inheriting constructors as top-level functions. These |
383 | | // constructors don't even have a body written down in the code, so even if |
384 | | // we find a bug, we won't be able to display it. |
385 | 26.3k | if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) |
386 | 3.19k | if (CD->isInheritingConstructor()) |
387 | 6 | return true; |
388 | | |
389 | | // We want to re-analyse the functions as top level in the following cases: |
390 | | // - The 'init' methods should be reanalyzed because |
391 | | // ObjCNonNilReturnValueChecker assumes that '[super init]' never returns |
392 | | // 'nil' and unless we analyze the 'init' functions as top level, we will |
393 | | // not catch errors within defensive code. |
394 | | // - We want to reanalyze all ObjC methods as top level to report Retain |
395 | | // Count naming convention errors more aggressively. |
396 | 26.3k | if (isa<ObjCMethodDecl>(D)) |
397 | 1.26k | return false; |
398 | | // We also want to reanalyze all C++ copy and move assignment operators to |
399 | | // separately check the two cases where 'this' aliases with the parameter and |
400 | | // where it may not. (cplusplus.SelfAssignmentChecker) |
401 | 25.0k | if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { |
402 | 6.33k | if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()6.18k ) |
403 | 246 | return false; |
404 | 24.8k | } |
405 | | |
406 | | // Otherwise, if we visited the function before, do not reanalyze it. |
407 | 24.8k | return Visited.count(D); |
408 | 24.8k | } |
409 | | |
410 | | ExprEngine::InliningModes |
411 | | AnalysisConsumer::getInliningModeForFunction(const Decl *D, |
412 | 22.0k | const SetOfConstDecls &Visited) { |
413 | | // We want to reanalyze all ObjC methods as top level to report Retain |
414 | | // Count naming convention errors more aggressively. But we should tune down |
415 | | // inlining when reanalyzing an already inlined function. |
416 | 22.0k | if (Visited.count(D) && isa<ObjCMethodDecl>(D)303 ) { |
417 | 210 | const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D); |
418 | 210 | if (ObjCM->getMethodFamily() != OMF_init) |
419 | 173 | return ExprEngine::Inline_Minimal; |
420 | 21.9k | } |
421 | | |
422 | 21.9k | return ExprEngine::Inline_Regular; |
423 | 21.9k | } |
424 | | |
425 | 1.30k | void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) { |
426 | | // Build the Call Graph by adding all the top level declarations to the graph. |
427 | | // Note: CallGraph can trigger deserialization of more items from a pch |
428 | | // (though HandleInterestingDecl); triggering additions to LocalTUDecls. |
429 | | // We rely on random access to add the initially processed Decls to CG. |
430 | 1.30k | CallGraph CG; |
431 | 35.3k | for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i34.0k ) { |
432 | 34.0k | CG.addToCallGraph(LocalTUDecls[i]); |
433 | 34.0k | } |
434 | | |
435 | | // Walk over all of the call graph nodes in topological order, so that we |
436 | | // analyze parents before the children. Skip the functions inlined into |
437 | | // the previously processed functions. Use external Visited set to identify |
438 | | // inlined functions. The topological order allows the "do not reanalyze |
439 | | // previously inlined function" performance heuristic to be triggered more |
440 | | // often. |
441 | 1.30k | SetOfConstDecls Visited; |
442 | 1.30k | SetOfConstDecls VisitedAsTopLevel; |
443 | 1.30k | llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG); |
444 | 1.30k | for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator |
445 | 28.9k | I = RPOT.begin(), E = RPOT.end(); I != E; ++I27.6k ) { |
446 | 27.6k | NumFunctionTopLevel++; |
447 | | |
448 | 27.6k | CallGraphNode *N = *I; |
449 | 27.6k | Decl *D = N->getDecl(); |
450 | | |
451 | | // Skip the abstract root node. |
452 | 27.6k | if (!D) |
453 | 1.30k | continue; |
454 | | |
455 | | // Skip the functions which have been processed already or previously |
456 | | // inlined. |
457 | 26.3k | if (shouldSkipFunction(D, Visited, VisitedAsTopLevel)) |
458 | 4.27k | continue; |
459 | | |
460 | | // Analyze the function. |
461 | 22.0k | SetOfConstDecls VisitedCallees; |
462 | | |
463 | 22.0k | HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited), |
464 | 22.0k | (Mgr->options.InliningMode == All ? nullptr0 : &VisitedCallees)); |
465 | | |
466 | | // Add the visited callees to the global visited set. |
467 | 22.0k | for (const Decl *Callee : VisitedCallees) |
468 | | // Decls from CallGraph are already canonical. But Decls coming from |
469 | | // CallExprs may be not. We should canonicalize them manually. |
470 | 11.2k | Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee368 |
471 | 10.8k | : Callee->getCanonicalDecl()); |
472 | 22.0k | VisitedAsTopLevel.insert(D); |
473 | 22.0k | } |
474 | 1.30k | } |
475 | | |
476 | 1.31k | static bool isBisonFile(ASTContext &C) { |
477 | 1.31k | const SourceManager &SM = C.getSourceManager(); |
478 | 1.31k | FileID FID = SM.getMainFileID(); |
479 | 1.31k | StringRef Buffer = SM.getBufferOrFake(FID).getBuffer(); |
480 | 1.31k | if (Buffer.startswith("/* A Bison parser, made by")) |
481 | 1 | return true; |
482 | 1.31k | return false; |
483 | 1.31k | } |
484 | | |
485 | 1.31k | void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) { |
486 | 1.31k | BugReporter BR(*Mgr); |
487 | 1.31k | TranslationUnitDecl *TU = C.getTranslationUnitDecl(); |
488 | 1.31k | if (SyntaxCheckTimer) |
489 | 3 | SyntaxCheckTimer->startTimer(); |
490 | 1.31k | checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR); |
491 | 1.31k | if (SyntaxCheckTimer) |
492 | 3 | SyntaxCheckTimer->stopTimer(); |
493 | | |
494 | | // Run the AST-only checks using the order in which functions are defined. |
495 | | // If inlining is not turned on, use the simplest function order for path |
496 | | // sensitive analyzes as well. |
497 | 1.31k | RecVisitorMode = AM_Syntax; |
498 | 1.31k | if (!Mgr->shouldInlineCall()) |
499 | 4 | RecVisitorMode |= AM_Path; |
500 | 1.31k | RecVisitorBR = &BR; |
501 | | |
502 | | // Process all the top level declarations. |
503 | | // |
504 | | // Note: TraverseDecl may modify LocalTUDecls, but only by appending more |
505 | | // entries. Thus we don't use an iterator, but rely on LocalTUDecls |
506 | | // random access. By doing so, we automatically compensate for iterators |
507 | | // possibly being invalidated, although this is a bit slower. |
508 | 1.31k | const unsigned LocalTUDeclsSize = LocalTUDecls.size(); |
509 | 35.4k | for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i34.1k ) { |
510 | 34.1k | TraverseDecl(LocalTUDecls[i]); |
511 | 34.1k | } |
512 | | |
513 | 1.31k | if (Mgr->shouldInlineCall()) |
514 | 1.30k | HandleDeclsCallGraph(LocalTUDeclsSize); |
515 | | |
516 | | // After all decls handled, run checkers on the entire TranslationUnit. |
517 | 1.31k | checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR); |
518 | | |
519 | 1.31k | BR.FlushReports(); |
520 | 1.31k | RecVisitorBR = nullptr; |
521 | 1.31k | } |
522 | | |
523 | 4 | void AnalysisConsumer::reportAnalyzerProgress(StringRef S) { |
524 | 4 | if (Opts->AnalyzerDisplayProgress) |
525 | 0 | llvm::errs() << S; |
526 | 4 | } |
527 | | |
528 | 1.33k | void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { |
529 | | |
530 | | // Don't run the actions if an error has occurred with parsing the file. |
531 | 1.33k | DiagnosticsEngine &Diags = PP.getDiagnostics(); |
532 | 1.33k | if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()1.31k ) |
533 | 23 | return; |
534 | | |
535 | 1.31k | if (isBisonFile(C)) { |
536 | 1 | reportAnalyzerProgress("Skipping bison-generated file\n"); |
537 | 1.31k | } else if (Opts->DisableAllCheckers) { |
538 | | |
539 | | // Don't analyze if the user explicitly asked for no checks to be performed |
540 | | // on this file. |
541 | 3 | reportAnalyzerProgress("All checks are disabled using a supplied option\n"); |
542 | 1.31k | } else { |
543 | | // Otherwise, just run the analysis. |
544 | 1.31k | runAnalysisOnTranslationUnit(C); |
545 | 1.31k | } |
546 | | |
547 | | // Count how many basic blocks we have not covered. |
548 | 1.31k | NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks(); |
549 | 1.31k | NumVisitedBlocksInAnalyzedFunctions = |
550 | 1.31k | FunctionSummaries.getTotalNumVisitedBasicBlocks(); |
551 | 1.31k | if (NumBlocksInAnalyzedFunctions > 0) |
552 | 1.17k | PercentReachableBlocks = |
553 | 1.17k | (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) / |
554 | 1.17k | NumBlocksInAnalyzedFunctions; |
555 | | |
556 | | // Explicitly destroy the PathDiagnosticConsumer. This will flush its output. |
557 | | // FIXME: This should be replaced with something that doesn't rely on |
558 | | // side-effects in PathDiagnosticConsumer's destructor. This is required when |
559 | | // used with option -disable-free. |
560 | 1.31k | Mgr.reset(); |
561 | 1.31k | } |
562 | | |
563 | 104 | std::string AnalysisConsumer::getFunctionName(const Decl *D) { |
564 | 104 | std::string Str; |
565 | 104 | llvm::raw_string_ostream OS(Str); |
566 | | |
567 | 104 | if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { |
568 | 38 | OS << FD->getQualifiedNameAsString(); |
569 | | |
570 | | // In C++, there are overloads. |
571 | 38 | if (Ctx->getLangOpts().CPlusPlus) { |
572 | 26 | OS << '('; |
573 | 13 | for (const auto &P : FD->parameters()) { |
574 | 13 | if (P != *FD->param_begin()) |
575 | 4 | OS << ", "; |
576 | 13 | OS << P->getType().getAsString(); |
577 | 13 | } |
578 | 26 | OS << ')'; |
579 | 26 | } |
580 | | |
581 | 66 | } else if (isa<BlockDecl>(D)) { |
582 | 2 | PresumedLoc Loc = Ctx->getSourceManager().getPresumedLoc(D->getLocation()); |
583 | | |
584 | 2 | if (Loc.isValid()) { |
585 | 2 | OS << "block (line: " << Loc.getLine() << ", col: " << Loc.getColumn() |
586 | 2 | << ')'; |
587 | 2 | } |
588 | | |
589 | 64 | } else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) { |
590 | | |
591 | | // FIXME: copy-pasted from CGDebugInfo.cpp. |
592 | 21 | OS << (OMD->isInstanceMethod() ? '-' : '+'4 ) << '['; |
593 | 25 | const DeclContext *DC = OMD->getDeclContext(); |
594 | 25 | if (const auto *OID = dyn_cast<ObjCImplementationDecl>(DC)) { |
595 | 10 | OS << OID->getName(); |
596 | 15 | } else if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(DC)) { |
597 | 11 | OS << OID->getName(); |
598 | 4 | } else if (const auto *OC = dyn_cast<ObjCCategoryDecl>(DC)) { |
599 | 0 | if (OC->IsClassExtension()) { |
600 | 0 | OS << OC->getClassInterface()->getName(); |
601 | 0 | } else { |
602 | 0 | OS << OC->getIdentifier()->getNameStart() << '(' |
603 | 0 | << OC->getIdentifier()->getNameStart() << ')'; |
604 | 0 | } |
605 | 4 | } else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) { |
606 | 0 | OS << OCD->getClassInterface()->getName() << '(' |
607 | 0 | << OCD->getName() << ')'; |
608 | 0 | } |
609 | 25 | OS << ' ' << OMD->getSelector().getAsString() << ']'; |
610 | | |
611 | 25 | } |
612 | | |
613 | 104 | return OS.str(); |
614 | 104 | } |
615 | | |
616 | | AnalysisConsumer::AnalysisMode |
617 | 284k | AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) { |
618 | 284k | if (!Opts->AnalyzeSpecificFunction.empty() && |
619 | 71 | getFunctionName(D) != Opts->AnalyzeSpecificFunction) |
620 | 61 | return AM_None; |
621 | | |
622 | | // Unless -analyze-all is specified, treat decls differently depending on |
623 | | // where they came from: |
624 | | // - Main source file: run both path-sensitive and non-path-sensitive checks. |
625 | | // - Header files: run non-path-sensitive checks only. |
626 | | // - System headers: don't run any checks. |
627 | 284k | SourceManager &SM = Ctx->getSourceManager(); |
628 | 284k | const Stmt *Body = D->getBody(); |
629 | 211k | SourceLocation SL = Body ? Body->getBeginLoc()72.6k : D->getLocation(); |
630 | 284k | SL = SM.getExpansionLoc(SL); |
631 | | |
632 | 284k | if (!Opts->AnalyzeAll && !Mgr->isInCodeFile(SL)284k ) { |
633 | 173k | if (SL.isInvalid() || SM.isInSystemHeader(SL)173k ) |
634 | 171k | return AM_None; |
635 | 1.60k | return Mode & ~AM_Path; |
636 | 1.60k | } |
637 | | |
638 | 110k | return Mode; |
639 | 110k | } |
640 | | |
641 | | void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, |
642 | | ExprEngine::InliningModes IMode, |
643 | 41.0k | SetOfConstDecls *VisitedCallees) { |
644 | 41.0k | if (!D->hasBody()) |
645 | 5.49k | return; |
646 | 35.5k | Mode = getModeForDecl(D, Mode); |
647 | 35.5k | if (Mode == AM_None) |
648 | 2.98k | return; |
649 | | |
650 | | // Clear the AnalysisManager of old AnalysisDeclContexts. |
651 | 32.5k | Mgr->ClearContexts(); |
652 | | // Ignore autosynthesized code. |
653 | 32.5k | if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized()) |
654 | 51 | return; |
655 | | |
656 | 32.5k | DisplayFunction(D, Mode, IMode); |
657 | 32.5k | CFG *DeclCFG = Mgr->getCFG(D); |
658 | 32.5k | if (DeclCFG) |
659 | 32.5k | MaxCFGSize.updateMax(DeclCFG->size()); |
660 | | |
661 | 32.5k | BugReporter BR(*Mgr); |
662 | | |
663 | 32.5k | if (Mode & AM_Syntax) { |
664 | 17.2k | if (SyntaxCheckTimer) |
665 | 4 | SyntaxCheckTimer->startTimer(); |
666 | 17.2k | checkerMgr->runCheckersOnASTBody(D, *Mgr, BR); |
667 | 17.2k | if (SyntaxCheckTimer) |
668 | 4 | SyntaxCheckTimer->stopTimer(); |
669 | 17.2k | } |
670 | | |
671 | 32.5k | BR.FlushReports(); |
672 | | |
673 | 32.5k | if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()15.2k ) { |
674 | 13.6k | RunPathSensitiveChecks(D, IMode, VisitedCallees); |
675 | 13.6k | if (IMode != ExprEngine::Inline_Minimal) |
676 | 13.4k | NumFunctionsAnalyzed++; |
677 | 13.6k | } |
678 | 32.5k | } |
679 | | |
680 | | //===----------------------------------------------------------------------===// |
681 | | // Path-sensitive checking. |
682 | | //===----------------------------------------------------------------------===// |
683 | | |
684 | | void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, |
685 | | ExprEngine::InliningModes IMode, |
686 | 13.6k | SetOfConstDecls *VisitedCallees) { |
687 | | // Construct the analysis engine. First check if the CFG is valid. |
688 | | // FIXME: Inter-procedural analysis will need to handle invalid CFGs. |
689 | 13.6k | if (!Mgr->getCFG(D)) |
690 | 0 | return; |
691 | | |
692 | | // See if the LiveVariables analysis scales. |
693 | 13.6k | if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>()) |
694 | 0 | return; |
695 | | |
696 | 13.6k | ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode); |
697 | | |
698 | | // Execute the worklist algorithm. |
699 | 13.6k | if (ExprEngineTimer) |
700 | 4 | ExprEngineTimer->startTimer(); |
701 | 13.6k | Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D), |
702 | 13.6k | Mgr->options.MaxNodesPerTopLevelFunction); |
703 | 13.6k | if (ExprEngineTimer) |
704 | 4 | ExprEngineTimer->stopTimer(); |
705 | | |
706 | 13.6k | if (!Mgr->options.DumpExplodedGraphTo.empty()) |
707 | 9 | Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo); |
708 | | |
709 | | // Visualize the exploded graph. |
710 | 13.6k | if (Mgr->options.visualizeExplodedGraphWithGraphViz) |
711 | 0 | Eng.ViewGraph(Mgr->options.TrimGraph); |
712 | | |
713 | | // Display warnings. |
714 | 13.6k | if (BugReporterTimer) |
715 | 4 | BugReporterTimer->startTimer(); |
716 | 13.6k | Eng.getBugReporter().FlushReports(); |
717 | 13.6k | if (BugReporterTimer) |
718 | 4 | BugReporterTimer->stopTimer(); |
719 | 13.6k | } |
720 | | |
721 | | //===----------------------------------------------------------------------===// |
722 | | // AnalysisConsumer creation. |
723 | | //===----------------------------------------------------------------------===// |
724 | | |
725 | | std::unique_ptr<AnalysisASTConsumer> |
726 | 1.33k | ento::CreateAnalysisConsumer(CompilerInstance &CI) { |
727 | | // Disable the effects of '-Werror' when using the AnalysisConsumer. |
728 | 1.33k | CI.getPreprocessor().getDiagnostics().setWarningsAsErrors(false); |
729 | | |
730 | 1.33k | AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts(); |
731 | 1.33k | bool hasModelPath = analyzerOpts->Config.count("model-path") > 0; |
732 | | |
733 | 1.33k | return std::make_unique<AnalysisConsumer>( |
734 | 1.33k | CI, CI.getFrontendOpts().OutputFile, analyzerOpts, |
735 | 1.33k | CI.getFrontendOpts().Plugins, |
736 | 1.33k | hasModelPath ? new ModelInjector(CI) : nullptr0 ); |
737 | 1.33k | } |