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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp