clang: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
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
45#include
46#include
47
48using namespace clang;
49using namespace ento;
50
51#define DEBUG_TYPE "AnalysisConsumer"
52
53STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
55 "The # of functions and blocks analyzed (as top level "
56 "with inlining turned on).");
58 "The # of basic blocks in the analyzed functions.");
59STATISTIC(NumVisitedBlocksInAnalyzedFunctions,
60 "The # of visited basic blocks in the analyzed functions.");
61STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
62STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
63
64
65
66
67
68namespace {
69
72 enum {
73 AM_None = 0,
74 AM_Syntax = 0x1,
75 AM_Path = 0x2
76 };
77 typedef unsigned AnalysisMode;
78
79
80 AnalysisMode RecVisitorMode;
81
83
84 std::vector<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns;
85
86public:
89 const std::string OutDir;
94
95
96
97
98
99
101
103
104
106
109
110 std::unique_ptr checkerMgr;
111 std::unique_ptr Mgr;
112
113
114 std::unique_ptrllvm::TimerGroup AnalyzerTimers;
115 std::unique_ptrllvm::Timer SyntaxCheckTimer;
116 std::unique_ptrllvm::Timer ExprEngineTimer;
117 std::unique_ptrllvm::Timer BugReporterTimer;
118
119
120
122
123 AnalysisConsumer(CompilerInstance &CI, const std::string &outdir,
126 : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),
127 PP(CI.getPreprocessor()), OutDir(outdir), Opts(opts),
128 Plugins(plugins), Injector(injector), CTU(CI),
129 MacroExpansions(CI.getLangOpts()) {
130 DigestAnalyzerOptions();
132 Opts.ShouldSerializeStats) {
133 AnalyzerTimers = std::make_uniquellvm::TimerGroup(
134 "analyzer", "Analyzer timers");
135 SyntaxCheckTimer = std::make_uniquellvm::Timer(
136 "syntaxchecks", "Syntax-based analysis time", *AnalyzerTimers);
137 ExprEngineTimer = std::make_uniquellvm::Timer(
138 "exprengine", "Path exploration time", *AnalyzerTimers);
139 BugReporterTimer = std::make_uniquellvm::Timer(
140 "bugreporter", "Path-sensitive report post-processing time",
141 *AnalyzerTimers);
142 }
143
144 if (Opts.PrintStats || Opts.ShouldSerializeStats) {
145 llvm::EnableStatistics( false);
146 }
147
148 if (Opts.ShouldDisplayMacroExpansions)
150
151
152 ShouldWalkTypesOfTypeLocs = false;
153 }
154
155 ~AnalysisConsumer() override {
157 llvm::PrintStatistics();
158 }
159 }
160
161 void DigestAnalyzerOptions() {
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
177
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) {
189 return;
190 }
191 llvm::errs() << " : " << llvm::format("%1.1f", Time.getWallTime() * 1000)
192 << " ms\n";
193 }
194
195 void DisplayFunction(const Decl *D, AnalysisMode Mode,
198 return;
199
200 SourceManager &SM = Mgr->getASTContext().getSourceManager();
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) {
211 llvm::errs() << " Inline_Minimal";
212 break;
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() << ' '
223 }
224 }
225
227 Ctx = &Context;
228 checkerMgr = std::make_unique(*Ctx, Opts, PP, Plugins,
229 CheckerRegistrationFns);
230
231 Mgr = std::make_unique(*Ctx, PP, PathConsumers,
232 CreateStoreMgr, CreateConstraintMgr,
233 checkerMgr.get(), Opts, Injector);
234 }
235
236
237
240
242
243
244
245
248
249
250
251 void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);
252
253
254
255
256
257
258
259 void HandleCode(Decl *D, AnalysisMode Mode,
262
263 void RunPathSensitiveChecks(Decl *D,
266
267
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();
276 }
277 return true;
278 }
279
280 bool VisitVarDecl(VarDecl *VD) override {
281 if (!Opts.IsNaiveCTUEnabled)
282 return true;
283
286 return true;
287 } else {
288
289 return true;
290 }
291
293 return true;
294
297 Opts.DisplayCTUProgress);
298
299 if (!CTUDeclOrError) {
300 handleAllErrors(CTUDeclOrError.takeError(),
302 CTU.emitCrossTUDiagnostics(IE);
303 });
304 }
305
306 return true;
307 }
308
309 bool VisitFunctionDecl(FunctionDecl *FD) override {
311 if (II && II->getName().starts_with("__inline"))
312 return true;
313
314
315
318 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
319 HandleCode(FD, RecVisitorMode);
320 }
321 return true;
322 }
323
324 bool VisitObjCMethodDecl(ObjCMethodDecl *MD) override {
326 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
327 HandleCode(MD, RecVisitorMode);
328 }
329 return true;
330 }
331
332 bool VisitBlockDecl(BlockDecl *BD) override {
334 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
335
336
338 HandleCode(BD, RecVisitorMode);
339 }
340 }
341 return true;
342 }
343
345 PathConsumers.push_back(Consumer);
346 }
347
349 CheckerRegistrationFns.push_back(std::move(Fn));
350 }
351
352private:
354
355
356 AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);
357 void runAnalysisOnTranslationUnit(ASTContext &C);
358
359
360 void reportAnalyzerProgress(StringRef S);
361};
362}
363
364
365
366
367
368bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
369 storeTopLevelDecls(DG);
370 return true;
371}
372
373void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
374 storeTopLevelDecls(DG);
375}
376
377void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
378 for (auto &I : DG) {
379
380
381
382 if (isa(I))
383 continue;
384
385 LocalTUDecls.push_back(I);
386 }
387}
388
392 if (VisitedAsTopLevel.count(D))
393 return true;
394
395
396
397
398 if (const auto *CD = dyn_cast(D))
399 if (CD->isInheritingConstructor())
400 return true;
401
402
403
404
405
406
407
408
409 if (isa(D))
410 return false;
411
412
413
414 if (const auto *MD = dyn_cast(D)) {
415 if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())
416 return false;
417 }
418
419
421}
422
424AnalysisConsumer::getInliningModeForFunction(const Decl *D,
426
427
428
429 if (Visited.count(D) && isa(D)) {
433 }
434
436}
437
438void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
439
440
441
442
444 for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
446 }
447
448
449
450
451
452
453
456 llvm::ReversePostOrderTraversalclang::CallGraph\* RPOT(&CG);
457 for (auto &N : RPOT) {
458 NumFunctionTopLevel++;
459
461
462
463 if ()
464 continue;
465
466
467
469 continue;
470
471
472
473
474
475 if (const auto *FD = dyn_cast(D)) {
476
477
480 continue;
481 }
482
483
485
486 HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
487 (Mgr->options.InliningMode == All ? nullptr : &VisitedCallees));
488
489
490 for (const Decl *Callee : VisitedCallees)
491
492
493 Visited.insert(isa(Callee) ? Callee
494 : Callee->getCanonicalDecl());
495 VisitedAsTopLevel.insert(D);
496 }
497}
498
501 FileID FID = SM.getMainFileID();
502 StringRef Buffer = SM.getBufferOrFake(FID).getBuffer();
503 return Buffer.contains(Substring);
504}
505
508 llvm::errs() << "Every top-level function was skipped.\n";
509
511 llvm::errs() << "Pass the -analyzer-display-progress for tracking which "
512 "functions are analyzed.\n";
513
514 bool HasBrackets =
516
517 if (Ctx.getLangOpts().CPlusPlus && !HasBrackets) {
518 llvm::errs()
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";
525 }
526}
527
528void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) {
531 BR.setAnalysisEntryPoint(TU);
532 if (SyntaxCheckTimer)
533 SyntaxCheckTimer->startTimer();
534 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
535 if (SyntaxCheckTimer)
536 SyntaxCheckTimer->stopTimer();
537
538
539
540
541 RecVisitorMode = AM_Syntax;
542 if (!Mgr->shouldInlineCall())
543 RecVisitorMode |= AM_Path;
544 RecVisitorBR = &BR;
545
546
547
548
549
550
551
552 const unsigned LocalTUDeclsSize = LocalTUDecls.size();
553 for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
554 TraverseDecl(LocalTUDecls[i]);
555 }
556
557 if (Mgr->shouldInlineCall())
558 HandleDeclsCallGraph(LocalTUDeclsSize);
559
560
561 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
562
563 BR.FlushReports();
564 RecVisitorBR = nullptr;
565
566
567
568
569
570
573}
574
575void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {
577 llvm::errs() << S;
578}
579
580void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
581
584 return;
585
586
587
588
589
590 const auto DiagFlusherScopeExit =
591 llvm::make_scope_exit([this] { Mgr.reset(); });
592
593 if (Opts.ShouldIgnoreBisonGeneratedFiles &&
595 reportAnalyzerProgress("Skipping bison-generated file\n");
596 return;
597 }
598
599 if (Opts.ShouldIgnoreFlexGeneratedFiles &&
601 reportAnalyzerProgress("Skipping flex-generated file\n");
602 return;
603 }
604
605
606
608 reportAnalyzerProgress("All checks are disabled using a supplied option\n");
609 return;
610 }
611
612
613 runAnalysisOnTranslationUnit(C);
614
615
617 NumVisitedBlocksInAnalyzedFunctions =
619 if (NumBlocksInAnalyzedFunctions > 0)
620 PercentReachableBlocks =
622 NumBlocksInAnalyzedFunctions;
623}
624
625AnalysisConsumer::AnalysisMode
626AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
629 return AM_None;
630
631
632
633
634
635
637 return Mode;
638
640
644 return SM.getExpansionLoc(SL);
645 }(D);
646
647
648 if (Loc.isInvalid() || SM.isInSystemHeader(Loc))
649 return AM_None;
650
651
652 if (!Mgr->isInCodeFile(Loc))
653 return Mode & ~AM_Path;
654
655 return Mode;
656}
657
658void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
662 return;
663 Mode = getModeForDecl(D, Mode);
664 if (Mode == AM_None)
665 return;
666
667
668 Mgr->ClearContexts();
669
670 if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized())
671 return;
672
673 CFG *DeclCFG = Mgr->getCFG(D);
674 if (DeclCFG)
675 MaxCFGSize.updateMax(DeclCFG->size());
676
677 DisplayFunction(D, Mode, IMode);
679 BR.setAnalysisEntryPoint(D);
680
681 if (Mode & AM_Syntax) {
682 llvm::TimeRecord CheckerStartTime;
683 if (SyntaxCheckTimer) {
684 CheckerStartTime = SyntaxCheckTimer->getTotalTime();
685 SyntaxCheckTimer->startTimer();
686 }
687 checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
688 if (SyntaxCheckTimer) {
689 SyntaxCheckTimer->stopTimer();
690 llvm::TimeRecord CheckerEndTime = SyntaxCheckTimer->getTotalTime();
691 CheckerEndTime -= CheckerStartTime;
692 DisplayTime(CheckerEndTime);
693 }
694 }
695
696 BR.FlushReports();
697
698 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
699 RunPathSensitiveChecks(D, IMode, VisitedCallees);
701 NumFunctionsAnalyzed++;
702 }
703}
704
705
706
707
708
709void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
712
713
714 if (!Mgr->getCFG(D))
715 return;
716
717
719 return;
720
721 ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
722
723
724 llvm::TimeRecord ExprEngineStartTime;
725 if (ExprEngineTimer) {
726 ExprEngineStartTime = ExprEngineTimer->getTotalTime();
727 ExprEngineTimer->startTimer();
728 }
729 Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
730 Mgr->options.MaxNodesPerTopLevelFunction);
731 if (ExprEngineTimer) {
732 ExprEngineTimer->stopTimer();
733 llvm::TimeRecord ExprEngineEndTime = ExprEngineTimer->getTotalTime();
734 ExprEngineEndTime -= ExprEngineStartTime;
735 DisplayTime(ExprEngineEndTime);
736 }
737
738 if (!Mgr->options.DumpExplodedGraphTo.empty())
739 Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo);
740
741
742 if (Mgr->options.visualizeExplodedGraphWithGraphViz)
743 Eng.ViewGraph(Mgr->options.TrimGraph);
744
745
746 if (BugReporterTimer)
747 BugReporterTimer->startTimer();
748 Eng.getBugReporter().FlushReports();
749 if (BugReporterTimer)
750 BugReporterTimer->stopTimer();
751}
752
753
754
755
756
757std::unique_ptr
759
761
763 bool hasModelPath = analyzerOpts.Config.count("model-path") > 0;
764
765 return std::make_unique(
769}
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.")
static bool shouldSkipFunction(const Decl *D, const SetOfConstDecls &Visited, const SetOfConstDecls &VisitedAsTopLevel)
static bool fileContainsString(StringRef Substring, ASTContext &C)
static void reportAnalyzerFunctionMisuse(const AnalyzerOptions &Opts, const ASTContext &Ctx)
Defines the clang::CodeInjector interface which is responsible for injecting AST of function definiti...
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
llvm::DenseSet< const void * > Visited
This file defines the clang::ento::ModelInjector class which implements the clang::CodeInjector inter...
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
virtual void HandleTranslationUnit(ASTContext &Ctx)
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D)
Handle the specified top-level declaration that occurred inside and ObjC container.
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
virtual void Initialize(ASTContext &Context)
Initialize - This is called to initialize the consumer, providing the ASTContext.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
const LangOptions & getLangOpts() const
static std::string getFunctionName(const Decl *D)
Stores options for the analyzer from the command line.
unsigned DisableAllCheckers
Disable all analyzer checkers.
AnalysisDiagClients AnalysisDiagOpt
AnalysisConstraints AnalysisConstraintsOpt
ConfigTable Config
A key-value table of use-specified configuration values.
std::string AnalyzeSpecificFunction
unsigned AnalyzerDisplayProgress
Represents a block literal declaration, which is like an unnamed FunctionDecl.
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned size() const
Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...
The AST-based call graph.
void addToCallGraph(Decl *D)
Populate the call graph with the functions in the given declaration.
CodeInjector is an interface which is responsible for injecting AST of function definitions that may ...
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
AnalyzerOptions & getAnalyzerOpts()
Preprocessor & getPreprocessor() const
Return the current preprocessor.
FrontendOptions & getFrontendOpts()
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
Decl - This represents one declaration (or definition), e.g.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
SourceLocation getLocation() const
Concrete class used by the front-end to report problems and issues.
bool hasErrorOccurred() const
void setWarningsAsErrors(bool Val)
When set to true, any warnings reported are issued as errors.
bool hasFatalErrorOccurred() const
Recursive AST visitor that supports extension via dynamic dispatch.
virtual bool VisitDecl(Decl *D)
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
std::string OutputFile
The output file, if any.
std::vector< std::string > Plugins
The list of plugins to load.
Represents a function declaration or definition.
bool isThisDeclarationADefinition() const
Returns whether this specific declaration of the function is also a definition that does not contain ...
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
MacroExpansionContext tracks the macro expansions processed by the Preprocessor.
void registerForPreprocessor(Preprocessor &PP)
Register the necessary callbacks to the Preprocessor to record the expansion events and the generated...
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
ObjCMethodDecl - Represents an instance or class method declaration.
bool isThisDeclarationADefinition() const
Returns whether this specific method is a definition.
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
DiagnosticsEngine & getDiagnostics() const
Represents an unpacked "presumed" location which can be presented to the user.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
Stmt - This represents one statement.
SourceLocation getBeginLoc() const LLVM_READONLY
The top declaration context.
Represents a variable declaration or definition.
bool isStaticDataMember() const
Determines whether this is a static data member.
bool hasExternalStorage() const
Returns true if a variable has extern or private_extern storage.
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
This class is used for tools that requires cross translation unit capability.
llvm::Expected< const FunctionDecl * > getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress=false)
This function loads a function or variable definition from an external AST file and merges it into th...
bool isImportedAsNew(const Decl *ToDecl) const
Returns true if the given Decl is newly created during the import.
virtual void AddCheckerRegistrationFn(std::function< void(CheckerRegistry &)> Fn)=0
This method allows registering statically linked custom checkers that are not a part of the Clang tre...
virtual void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer)=0
BugReporter is a utility class for generating PathDiagnostics for analysis.
Manages a set of available checkers for running a static analysis.
bool isValid() const =delete
InliningModes
The modes of inlining, which override the default analysis-wide settings.
@ Inline_Minimal
Do minimal inlining of callees.
@ Inline_Regular
Follow the default settings for inlining callees.
unsigned getTotalNumBasicBlocks()
unsigned getTotalNumVisitedBasicBlocks()
bool shouldImport(const VarDecl *VD, const ASTContext &ACtx)
Returns true if it makes sense to import a foreign variable definition.
std::unique_ptr< AnalysisASTConsumer > CreateAnalysisConsumer(CompilerInstance &CI)
CreateAnalysisConsumer - Creates an ASTConsumer to run various code analysis passes.
llvm::DenseSet< const Decl * > SetOfConstDecls
std::unique_ptr< ConstraintManager >(* ConstraintManagerCreator)(ProgramStateManager &, ExprEngine *)
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
std::unique_ptr< StoreManager >(* StoreManagerCreator)(ProgramStateManager &)
std::deque< Decl * > SetOfDecls
std::unique_ptr< StoreManager > CreateRegionStoreManager(ProgramStateManager &StMgr)
The JSON file list parser is used to communicate input to InstallAPI.