1 //===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
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
7 //===----------------------------------------------------------------------===//
9 // "Meta" ASTConsumer for running different source analyses.
11 //===----------------------------------------------------------------------===//
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"
48 using namespace clang
;
51 #define DEBUG_TYPE "AnalysisConsumer"
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.");
64 //===----------------------------------------------------------------------===//
65 // AnalysisConsumer declaration.
66 //===----------------------------------------------------------------------===//
70 class AnalysisConsumer
: public AnalysisASTConsumer
,
71 public RecursiveASTVisitor
<AnalysisConsumer
> {
77 typedef unsigned AnalysisMode
;
79 /// Mode of the analyzes while recursively visiting Decls.
80 AnalysisMode RecVisitorMode
;
81 /// Bug Reporter to use while recursively visiting Decls.
82 BugReporter
*RecVisitorBR
;
84 std::vector
<std::function
<void(CheckerRegistry
&)>> CheckerRegistrationFns
;
89 const std::string OutDir
;
90 AnalyzerOptionsRef Opts
;
91 ArrayRef
<std::string
> Plugins
;
92 CodeInjector
*Injector
;
93 cross_tu::CrossTranslationUnitContext CTU
;
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
;
102 MacroExpansionContext MacroExpansions
;
104 // Set of PathDiagnosticConsumers. Owned by AnalysisManager.
105 PathDiagnosticConsumers PathConsumers
;
107 StoreManagerCreator CreateStoreMgr
;
108 ConstraintManagerCreator CreateConstraintMgr
;
110 std::unique_ptr
<CheckerManager
> checkerMgr
;
111 std::unique_ptr
<AnalysisManager
> Mgr
;
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
;
119 /// The information about analyzed functions shared throughout the
120 /// translation unit.
121 FunctionSummariesTy FunctionSummaries
;
123 AnalysisConsumer(CompilerInstance
&CI
, const std::string
&outdir
,
124 AnalyzerOptionsRef opts
, ArrayRef
<std::string
> plugins
,
125 CodeInjector
*injector
)
126 : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),
127 PP(CI
.getPreprocessor()), OutDir(outdir
), Opts(std::move(opts
)),
128 Plugins(plugins
), Injector(injector
), CTU(CI
),
129 MacroExpansions(CI
.getLangOpts()) {
130 DigestAnalyzerOptions();
131 if (Opts
->AnalyzerDisplayProgress
|| Opts
->PrintStats
||
132 Opts
->ShouldSerializeStats
) {
133 AnalyzerTimers
= std::make_unique
<llvm::TimerGroup
>(
134 "analyzer", "Analyzer timers");
135 SyntaxCheckTimer
= std::make_unique
<llvm::Timer
>(
136 "syntaxchecks", "Syntax-based analysis time", *AnalyzerTimers
);
137 ExprEngineTimer
= std::make_unique
<llvm::Timer
>(
138 "exprengine", "Path exploration time", *AnalyzerTimers
);
139 BugReporterTimer
= std::make_unique
<llvm::Timer
>(
140 "bugreporter", "Path-sensitive report post-processing time",
144 if (Opts
->PrintStats
|| Opts
->ShouldSerializeStats
) {
145 llvm::EnableStatistics(/* DoPrintOnExit= */ false);
148 if (Opts
->ShouldDisplayMacroExpansions
)
149 MacroExpansions
.registerForPreprocessor(PP
);
152 ~AnalysisConsumer() override
{
153 if (Opts
->PrintStats
) {
154 llvm::PrintStatistics();
158 void DigestAnalyzerOptions() {
159 switch (Opts
->AnalysisDiagOpt
) {
162 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
164 CREATEFN(Opts->getDiagOpts(), PathConsumers, OutDir, PP, CTU, \
167 #include "clang/StaticAnalyzer/Core/Analyses.def"
169 llvm_unreachable("Unknown analyzer output type!");
172 // Create the analyzer component creators.
173 CreateStoreMgr
= &CreateRegionStoreManager
;
175 switch (Opts
->AnalysisConstraintsOpt
) {
177 llvm_unreachable("Unknown constraint manager.");
178 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
179 case NAME##Model: CreateConstraintMgr = CREATEFN; break;
180 #include "clang/StaticAnalyzer/Core/Analyses.def"
184 void DisplayTime(llvm::TimeRecord
&Time
) {
185 if (!Opts
->AnalyzerDisplayProgress
) {
188 llvm::errs() << " : " << llvm::format("%1.1f", Time
.getWallTime() * 1000)
192 void DisplayFunction(const Decl
*D
, AnalysisMode Mode
,
193 ExprEngine::InliningModes IMode
) {
194 if (!Opts
->AnalyzerDisplayProgress
)
197 SourceManager
&SM
= Mgr
->getASTContext().getSourceManager();
198 PresumedLoc Loc
= SM
.getPresumedLoc(D
->getLocation());
200 llvm::errs() << "ANALYZE";
202 if (Mode
== AM_Syntax
)
203 llvm::errs() << " (Syntax)";
204 else if (Mode
== AM_Path
) {
205 llvm::errs() << " (Path, ";
207 case ExprEngine::Inline_Minimal
:
208 llvm::errs() << " Inline_Minimal";
210 case ExprEngine::Inline_Regular
:
211 llvm::errs() << " Inline_Regular";
216 assert(Mode
== (AM_Syntax
| AM_Path
) && "Unexpected mode!");
218 llvm::errs() << ": " << Loc
.getFilename() << ' '
219 << AnalysisDeclContext::getFunctionName(D
);
223 void Initialize(ASTContext
&Context
) override
{
225 checkerMgr
= std::make_unique
<CheckerManager
>(*Ctx
, *Opts
, PP
, Plugins
,
226 CheckerRegistrationFns
);
228 Mgr
= std::make_unique
<AnalysisManager
>(*Ctx
, PP
, PathConsumers
,
229 CreateStoreMgr
, CreateConstraintMgr
,
230 checkerMgr
.get(), *Opts
, Injector
);
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
;
238 void HandleTranslationUnit(ASTContext
&C
) override
;
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
);
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
);
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);
260 void RunPathSensitiveChecks(Decl
*D
,
261 ExprEngine::InliningModes IMode
,
262 SetOfConstDecls
*VisitedCallees
);
264 /// Visitors for the RecursiveASTVisitor.
265 bool shouldWalkTypesOfTypeLocs() const { return false; }
267 /// Handle callbacks for arbitrary Decls.
268 bool VisitDecl(Decl
*D
) {
269 AnalysisMode Mode
= getModeForDecl(D
, RecVisitorMode
);
270 if (Mode
& AM_Syntax
) {
271 if (SyntaxCheckTimer
)
272 SyntaxCheckTimer
->startTimer();
273 checkerMgr
->runCheckersOnASTDecl(D
, *Mgr
, *RecVisitorBR
);
274 if (SyntaxCheckTimer
)
275 SyntaxCheckTimer
->stopTimer();
280 bool VisitVarDecl(VarDecl
*VD
) {
281 if (!Opts
->IsNaiveCTUEnabled
)
284 if (VD
->hasExternalStorage() || VD
->isStaticDataMember()) {
285 if (!cross_tu::shouldImport(VD
, *Ctx
))
288 // Cannot be initialized in another TU.
292 if (VD
->getAnyInitializer())
295 llvm::Expected
<const VarDecl
*> CTUDeclOrError
=
296 CTU
.getCrossTUDefinition(VD
, Opts
->CTUDir
, Opts
->CTUIndexName
,
297 Opts
->DisplayCTUProgress
);
299 if (!CTUDeclOrError
) {
300 handleAllErrors(CTUDeclOrError
.takeError(),
301 [&](const cross_tu::IndexError
&IE
) {
302 CTU
.emitCrossTUDiagnostics(IE
);
309 bool VisitFunctionDecl(FunctionDecl
*FD
) {
310 IdentifierInfo
*II
= FD
->getIdentifier();
311 if (II
&& II
->getName().startswith("__inline"))
314 // We skip function template definitions, as their semantics is
315 // only determined when they are instantiated.
316 if (FD
->isThisDeclarationADefinition() &&
317 !FD
->isDependentContext()) {
318 assert(RecVisitorMode
== AM_Syntax
|| Mgr
->shouldInlineCall() == false);
319 HandleCode(FD
, RecVisitorMode
);
324 bool VisitObjCMethodDecl(ObjCMethodDecl
*MD
) {
325 if (MD
->isThisDeclarationADefinition()) {
326 assert(RecVisitorMode
== AM_Syntax
|| Mgr
->shouldInlineCall() == false);
327 HandleCode(MD
, RecVisitorMode
);
332 bool VisitBlockDecl(BlockDecl
*BD
) {
334 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 if (!BD
->isDependentContext()) {
338 HandleCode(BD
, RecVisitorMode
);
344 void AddDiagnosticConsumer(PathDiagnosticConsumer
*Consumer
) override
{
345 PathConsumers
.push_back(Consumer
);
348 void AddCheckerRegistrationFn(std::function
<void(CheckerRegistry
&)> Fn
) override
{
349 CheckerRegistrationFns
.push_back(std::move(Fn
));
353 void storeTopLevelDecls(DeclGroupRef DG
);
355 /// Check if we should skip (not analyze) the given function.
356 AnalysisMode
getModeForDecl(Decl
*D
, AnalysisMode Mode
);
357 void runAnalysisOnTranslationUnit(ASTContext
&C
);
359 /// Print \p S to stderr if \c Opts->AnalyzerDisplayProgress is set.
360 void reportAnalyzerProgress(StringRef S
);
362 } // end anonymous namespace
365 //===----------------------------------------------------------------------===//
366 // AnalysisConsumer implementation.
367 //===----------------------------------------------------------------------===//
368 bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG
) {
369 storeTopLevelDecls(DG
);
373 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG
) {
374 storeTopLevelDecls(DG
);
377 void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG
) {
380 // Skip ObjCMethodDecl, wait for the objc container to avoid
382 if (isa
<ObjCMethodDecl
>(I
))
385 LocalTUDecls
.push_back(I
);
389 static bool shouldSkipFunction(const Decl
*D
,
390 const SetOfConstDecls
&Visited
,
391 const SetOfConstDecls
&VisitedAsTopLevel
) {
392 if (VisitedAsTopLevel
.count(D
))
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 if (const auto *CD
= dyn_cast
<CXXConstructorDecl
>(D
))
399 if (CD
->isInheritingConstructor())
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 if (isa
<ObjCMethodDecl
>(D
))
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 if (const auto *MD
= dyn_cast
<CXXMethodDecl
>(D
)) {
415 if (MD
->isCopyAssignmentOperator() || MD
->isMoveAssignmentOperator())
419 // Otherwise, if we visited the function before, do not reanalyze it.
420 return Visited
.count(D
);
423 ExprEngine::InliningModes
424 AnalysisConsumer::getInliningModeForFunction(const Decl
*D
,
425 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 if (Visited
.count(D
) && isa
<ObjCMethodDecl
>(D
)) {
430 const ObjCMethodDecl
*ObjCM
= cast
<ObjCMethodDecl
>(D
);
431 if (ObjCM
->getMethodFamily() != OMF_init
)
432 return ExprEngine::Inline_Minimal
;
435 return ExprEngine::Inline_Regular
;
438 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.
444 for (unsigned i
= 0 ; i
< LocalTUDeclsSize
; ++i
) {
445 CG
.addToCallGraph(LocalTUDecls
[i
]);
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
454 SetOfConstDecls Visited
;
455 SetOfConstDecls VisitedAsTopLevel
;
456 llvm::ReversePostOrderTraversal
<clang::CallGraph
*> RPOT(&CG
);
457 for (auto &N
: RPOT
) {
458 NumFunctionTopLevel
++;
460 Decl
*D
= N
->getDecl();
462 // Skip the abstract root node.
466 // Skip the functions which have been processed already or previously
468 if (shouldSkipFunction(D
, Visited
, VisitedAsTopLevel
))
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 if (const auto *FD
= dyn_cast
<FunctionDecl
>(D
)) {
476 // Calling 'hasBody' replaces 'FD' in place with the FunctionDecl
477 // that has the body.
479 if (CTU
.isImportedAsNew(FD
))
483 // Analyze the function.
484 SetOfConstDecls VisitedCallees
;
486 HandleCode(D
, AM_Path
, getInliningModeForFunction(D
, Visited
),
487 (Mgr
->options
.InliningMode
== All
? nullptr : &VisitedCallees
));
489 // Add the visited callees to the global visited set.
490 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 Visited
.insert(isa
<ObjCMethodDecl
>(Callee
) ? Callee
494 : Callee
->getCanonicalDecl());
495 VisitedAsTopLevel
.insert(D
);
499 static bool fileContainsString(StringRef Substring
, ASTContext
&C
) {
500 const SourceManager
&SM
= C
.getSourceManager();
501 FileID FID
= SM
.getMainFileID();
502 StringRef Buffer
= SM
.getBufferOrFake(FID
).getBuffer();
503 return Buffer
.contains(Substring
);
506 static void reportAnalyzerFunctionMisuse(const AnalyzerOptions
&Opts
,
507 const ASTContext
&Ctx
) {
508 llvm::errs() << "Every top-level function was skipped.\n";
510 if (!Opts
.AnalyzerDisplayProgress
)
511 llvm::errs() << "Pass the -analyzer-display-progress for tracking which "
512 "functions are analyzed.\n";
515 Opts
.AnalyzeSpecificFunction
.find("(") != std::string::npos
;
517 if (Ctx
.getLangOpts().CPlusPlus
&& !HasBrackets
) {
519 << "For analyzing C++ code you need to pass the function parameter "
520 "list: -analyze-function=\"foobar(int, _Bool)\"\n";
521 } else if (!Ctx
.getLangOpts().CPlusPlus
&& HasBrackets
) {
522 llvm::errs() << "For analyzing C code you shouldn't pass the function "
523 "parameter list, only the name of the function: "
524 "-analyze-function=foobar\n";
528 void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext
&C
) {
529 BugReporter
BR(*Mgr
);
530 TranslationUnitDecl
*TU
= C
.getTranslationUnitDecl();
531 if (SyntaxCheckTimer
)
532 SyntaxCheckTimer
->startTimer();
533 checkerMgr
->runCheckersOnASTDecl(TU
, *Mgr
, BR
);
534 if (SyntaxCheckTimer
)
535 SyntaxCheckTimer
->stopTimer();
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 RecVisitorMode
= AM_Syntax
;
541 if (!Mgr
->shouldInlineCall())
542 RecVisitorMode
|= AM_Path
;
545 // Process all the top level declarations.
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 const unsigned LocalTUDeclsSize
= LocalTUDecls
.size();
552 for (unsigned i
= 0 ; i
< LocalTUDeclsSize
; ++i
) {
553 TraverseDecl(LocalTUDecls
[i
]);
556 if (Mgr
->shouldInlineCall())
557 HandleDeclsCallGraph(LocalTUDeclsSize
);
559 // After all decls handled, run checkers on the entire TranslationUnit.
560 checkerMgr
->runCheckersOnEndOfTranslationUnit(TU
, *Mgr
, BR
);
563 RecVisitorBR
= nullptr;
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
568 // FIXME: The user might have analyzed the requested function in Syntax mode,
569 // but we are unaware of that.
570 if (!Opts
->AnalyzeSpecificFunction
.empty() && NumFunctionsAnalyzed
== 0)
571 reportAnalyzerFunctionMisuse(*Opts
, *Ctx
);
574 void AnalysisConsumer::reportAnalyzerProgress(StringRef S
) {
575 if (Opts
->AnalyzerDisplayProgress
)
579 void AnalysisConsumer::HandleTranslationUnit(ASTContext
&C
) {
580 // Don't run the actions if an error has occurred with parsing the file.
581 DiagnosticsEngine
&Diags
= PP
.getDiagnostics();
582 if (Diags
.hasErrorOccurred() || Diags
.hasFatalErrorOccurred())
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 const auto DiagFlusherScopeExit
=
590 llvm::make_scope_exit([this] { Mgr
.reset(); });
592 if (Opts
->ShouldIgnoreBisonGeneratedFiles
&&
593 fileContainsString("/* A Bison parser, made by", C
)) {
594 reportAnalyzerProgress("Skipping bison-generated file\n");
598 if (Opts
->ShouldIgnoreFlexGeneratedFiles
&&
599 fileContainsString("/* A lexical scanner generated by flex", C
)) {
600 reportAnalyzerProgress("Skipping flex-generated file\n");
604 // Don't analyze if the user explicitly asked for no checks to be performed
606 if (Opts
->DisableAllCheckers
) {
607 reportAnalyzerProgress("All checks are disabled using a supplied option\n");
611 // Otherwise, just run the analysis.
612 runAnalysisOnTranslationUnit(C
);
614 // Count how many basic blocks we have not covered.
615 NumBlocksInAnalyzedFunctions
= FunctionSummaries
.getTotalNumBasicBlocks();
616 NumVisitedBlocksInAnalyzedFunctions
=
617 FunctionSummaries
.getTotalNumVisitedBasicBlocks();
618 if (NumBlocksInAnalyzedFunctions
> 0)
619 PercentReachableBlocks
=
620 (FunctionSummaries
.getTotalNumVisitedBasicBlocks() * 100) /
621 NumBlocksInAnalyzedFunctions
;
624 AnalysisConsumer::AnalysisMode
625 AnalysisConsumer::getModeForDecl(Decl
*D
, AnalysisMode Mode
) {
626 if (!Opts
->AnalyzeSpecificFunction
.empty() &&
627 AnalysisDeclContext::getFunctionName(D
) != Opts
->AnalyzeSpecificFunction
)
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 if (Opts
->AnalyzeAll
)
638 const SourceManager
&SM
= Ctx
->getSourceManager();
640 const SourceLocation Loc
= [&SM
](Decl
*D
) -> SourceLocation
{
641 const Stmt
*Body
= D
->getBody();
642 SourceLocation SL
= Body
? Body
->getBeginLoc() : D
->getLocation();
643 return SM
.getExpansionLoc(SL
);
646 // Ignore system headers.
647 if (Loc
.isInvalid() || SM
.isInSystemHeader(Loc
))
650 // Disable path sensitive analysis in user-headers.
651 if (!Mgr
->isInCodeFile(Loc
))
652 return Mode
& ~AM_Path
;
657 void AnalysisConsumer::HandleCode(Decl
*D
, AnalysisMode Mode
,
658 ExprEngine::InliningModes IMode
,
659 SetOfConstDecls
*VisitedCallees
) {
662 Mode
= getModeForDecl(D
, Mode
);
666 // Clear the AnalysisManager of old AnalysisDeclContexts.
667 Mgr
->ClearContexts();
668 // Ignore autosynthesized code.
669 if (Mgr
->getAnalysisDeclContext(D
)->isBodyAutosynthesized())
672 CFG
*DeclCFG
= Mgr
->getCFG(D
);
674 MaxCFGSize
.updateMax(DeclCFG
->size());
676 DisplayFunction(D
, Mode
, IMode
);
677 BugReporter
BR(*Mgr
);
679 if (Mode
& AM_Syntax
) {
680 llvm::TimeRecord CheckerStartTime
;
681 if (SyntaxCheckTimer
) {
682 CheckerStartTime
= SyntaxCheckTimer
->getTotalTime();
683 SyntaxCheckTimer
->startTimer();
685 checkerMgr
->runCheckersOnASTBody(D
, *Mgr
, BR
);
686 if (SyntaxCheckTimer
) {
687 SyntaxCheckTimer
->stopTimer();
688 llvm::TimeRecord CheckerEndTime
= SyntaxCheckTimer
->getTotalTime();
689 CheckerEndTime
-= CheckerStartTime
;
690 DisplayTime(CheckerEndTime
);
696 if ((Mode
& AM_Path
) && checkerMgr
->hasPathSensitiveCheckers()) {
697 RunPathSensitiveChecks(D
, IMode
, VisitedCallees
);
698 if (IMode
!= ExprEngine::Inline_Minimal
)
699 NumFunctionsAnalyzed
++;
703 //===----------------------------------------------------------------------===//
704 // Path-sensitive checking.
705 //===----------------------------------------------------------------------===//
707 void AnalysisConsumer::RunPathSensitiveChecks(Decl
*D
,
708 ExprEngine::InliningModes IMode
,
709 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.
715 // See if the LiveVariables analysis scales.
716 if (!Mgr
->getAnalysisDeclContext(D
)->getAnalysis
<RelaxedLiveVariables
>())
719 ExprEngine
Eng(CTU
, *Mgr
, VisitedCallees
, &FunctionSummaries
, IMode
);
721 // Execute the worklist algorithm.
722 llvm::TimeRecord ExprEngineStartTime
;
723 if (ExprEngineTimer
) {
724 ExprEngineStartTime
= ExprEngineTimer
->getTotalTime();
725 ExprEngineTimer
->startTimer();
727 Eng
.ExecuteWorkList(Mgr
->getAnalysisDeclContextManager().getStackFrame(D
),
728 Mgr
->options
.MaxNodesPerTopLevelFunction
);
729 if (ExprEngineTimer
) {
730 ExprEngineTimer
->stopTimer();
731 llvm::TimeRecord ExprEngineEndTime
= ExprEngineTimer
->getTotalTime();
732 ExprEngineEndTime
-= ExprEngineStartTime
;
733 DisplayTime(ExprEngineEndTime
);
736 if (!Mgr
->options
.DumpExplodedGraphTo
.empty())
737 Eng
.DumpGraph(Mgr
->options
.TrimGraph
, Mgr
->options
.DumpExplodedGraphTo
);
739 // Visualize the exploded graph.
740 if (Mgr
->options
.visualizeExplodedGraphWithGraphViz
)
741 Eng
.ViewGraph(Mgr
->options
.TrimGraph
);
744 if (BugReporterTimer
)
745 BugReporterTimer
->startTimer();
746 Eng
.getBugReporter().FlushReports();
747 if (BugReporterTimer
)
748 BugReporterTimer
->stopTimer();
751 //===----------------------------------------------------------------------===//
752 // AnalysisConsumer creation.
753 //===----------------------------------------------------------------------===//
755 std::unique_ptr
<AnalysisASTConsumer
>
756 ento::CreateAnalysisConsumer(CompilerInstance
&CI
) {
757 // Disable the effects of '-Werror' when using the AnalysisConsumer.
758 CI
.getPreprocessor().getDiagnostics().setWarningsAsErrors(false);
760 AnalyzerOptionsRef analyzerOpts
= CI
.getAnalyzerOpts();
761 bool hasModelPath
= analyzerOpts
->Config
.count("model-path") > 0;
763 return std::make_unique
<AnalysisConsumer
>(
764 CI
, CI
.getFrontendOpts().OutputFile
, analyzerOpts
,
765 CI
.getFrontendOpts().Plugins
,
766 hasModelPath
? new ModelInjector(CI
) : nullptr);