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