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"
51#define DEBUG_TYPE "AnalysisConsumer"
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.");
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.");
77 typedef unsigned AnalysisMode;
80 AnalysisMode RecVisitorMode;
84 std::vector<std::function<void(
CheckerRegistry &)>> CheckerRegistrationFns;
89 const std::string OutDir;
110 std::unique_ptr<CheckerManager> checkerMgr;
111 std::unique_ptr<AnalysisManager> Mgr;
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;
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_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(
false);
148 if (Opts.ShouldDisplayMacroExpansions)
152 ~AnalysisConsumer()
override {
154 llvm::PrintStatistics();
158 void DigestAnalyzerOptions() {
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!");
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) {
188 llvm::errs() <<
" : " << llvm::format(
"%1.1f", Time.getWallTime() * 1000)
192 void DisplayFunction(
const Decl *
D, AnalysisMode Mode,
200 llvm::errs() <<
"ANALYZE";
202 if (Mode == AM_Syntax)
203 llvm::errs() <<
" (Syntax)";
204 else if (Mode == AM_Path) {
205 llvm::errs() <<
" (Path, ";
208 llvm::errs() <<
" Inline_Minimal";
211 llvm::errs() <<
" Inline_Regular";
216 assert(Mode == (AM_Syntax | AM_Path) &&
"Unexpected mode!");
218 llvm::errs() <<
": " <<
Loc.getFilename() <<
' '
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);
248 void HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize);
256 void HandleCode(
Decl *
D, AnalysisMode Mode,
260 void RunPathSensitiveChecks(
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)
297 Opts.DisplayCTUProgress);
299 if (!CTUDeclOrError) {
300 handleAllErrors(CTUDeclOrError.takeError(),
302 CTU.emitCrossTUDiagnostics(IE);
311 if (II && II->
getName().starts_with(
"__inline"))
318 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
319 HandleCode(FD, RecVisitorMode);
326 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
327 HandleCode(MD, RecVisitorMode);
334 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
338 HandleCode(BD, RecVisitorMode);
345 PathConsumers.push_back(Consumer);
349 CheckerRegistrationFns.push_back(std::move(Fn));
356 AnalysisMode getModeForDecl(
Decl *
D, AnalysisMode Mode);
360 void reportAnalyzerProgress(StringRef S);
368bool AnalysisConsumer::HandleTopLevelDecl(
DeclGroupRef DG) {
369 storeTopLevelDecls(DG);
373void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(
DeclGroupRef DG) {
374 storeTopLevelDecls(DG);
377void AnalysisConsumer::storeTopLevelDecls(
DeclGroupRef DG) {
382 if (isa<ObjCMethodDecl>(I))
385 LocalTUDecls.push_back(I);
392 if (VisitedAsTopLevel.count(
D))
398 if (
const auto *CD = dyn_cast<CXXConstructorDecl>(
D))
399 if (CD->isInheritingConstructor())
409 if (isa<ObjCMethodDecl>(
D))
414 if (
const auto *MD = dyn_cast<CXXMethodDecl>(
D)) {
415 if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())
424AnalysisConsumer::getInliningModeForFunction(
const Decl *
D,
429 if (
Visited.count(
D) && isa<ObjCMethodDecl>(
D)) {
438void AnalysisConsumer::HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize) {
444 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
456 llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
457 for (
auto &N : RPOT) {
458 NumFunctionTopLevel++;
460 Decl *
D = N->getDecl();
475 if (
const auto *FD = dyn_cast<FunctionDecl>(
D)) {
486 HandleCode(
D, AM_Path, getInliningModeForFunction(
D,
Visited),
487 (Mgr->options.InliningMode == All ?
nullptr : &VisitedCallees));
490 for (
const Decl *Callee : VisitedCallees)
493 Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
494 :
Callee->getCanonicalDecl());
495 VisitedAsTopLevel.insert(
D);
502 StringRef Buffer =
SM.getBufferOrFake(FID).getBuffer();
503 return Buffer.contains(Substring);
508 llvm::errs() <<
"Every top-level function was skipped.\n";
511 llvm::errs() <<
"Pass the -analyzer-display-progress for tracking which "
512 "functions are analyzed.\n";
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";
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();
541 RecVisitorMode = AM_Syntax;
542 if (!Mgr->shouldInlineCall())
543 RecVisitorMode |= AM_Path;
552 const unsigned LocalTUDeclsSize = LocalTUDecls.size();
553 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
554 TraverseDecl(LocalTUDecls[i]);
557 if (Mgr->shouldInlineCall())
558 HandleDeclsCallGraph(LocalTUDeclsSize);
561 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
564 RecVisitorBR =
nullptr;
575void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {
580void AnalysisConsumer::HandleTranslationUnit(
ASTContext &
C) {
590 const auto DiagFlusherScopeExit =
591 llvm::make_scope_exit([
this] { Mgr.reset(); });
593 if (Opts.ShouldIgnoreBisonGeneratedFiles &&
595 reportAnalyzerProgress(
"Skipping bison-generated file\n");
599 if (Opts.ShouldIgnoreFlexGeneratedFiles &&
601 reportAnalyzerProgress(
"Skipping flex-generated file\n");
608 reportAnalyzerProgress(
"All checks are disabled using a supplied option\n");
613 runAnalysisOnTranslationUnit(
C);
617 NumVisitedBlocksInAnalyzedFunctions =
619 if (NumBlocksInAnalyzedFunctions > 0)
620 PercentReachableBlocks =
622 NumBlocksInAnalyzedFunctions;
625AnalysisConsumer::AnalysisMode
626AnalysisConsumer::getModeForDecl(
Decl *
D, AnalysisMode Mode) {
644 return SM.getExpansionLoc(SL);
648 if (
Loc.isInvalid() ||
SM.isInSystemHeader(
Loc))
652 if (!Mgr->isInCodeFile(
Loc))
653 return Mode & ~AM_Path;
658void AnalysisConsumer::HandleCode(
Decl *
D, AnalysisMode Mode,
663 Mode = getModeForDecl(
D, Mode);
668 Mgr->ClearContexts();
670 if (Mgr->getAnalysisDeclContext(
D)->isBodyAutosynthesized())
673 CFG *DeclCFG = Mgr->getCFG(
D);
675 MaxCFGSize.updateMax(DeclCFG->
size());
677 DisplayFunction(
D, Mode, IMode);
679 BR.setAnalysisEntryPoint(
D);
681 if (Mode & AM_Syntax) {
682 llvm::TimeRecord CheckerStartTime;
683 if (SyntaxCheckTimer) {
684 CheckerStartTime = SyntaxCheckTimer->getTotalTime();
685 SyntaxCheckTimer->startTimer();
687 checkerMgr->runCheckersOnASTBody(
D, *Mgr, BR);
688 if (SyntaxCheckTimer) {
689 SyntaxCheckTimer->stopTimer();
690 llvm::TimeRecord CheckerEndTime = SyntaxCheckTimer->getTotalTime();
691 CheckerEndTime -= CheckerStartTime;
692 DisplayTime(CheckerEndTime);
698 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
699 RunPathSensitiveChecks(
D, IMode, VisitedCallees);
701 NumFunctionsAnalyzed++;
709void AnalysisConsumer::RunPathSensitiveChecks(
Decl *
D,
721 ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
724 llvm::TimeRecord ExprEngineStartTime;
725 if (ExprEngineTimer) {
726 ExprEngineStartTime = ExprEngineTimer->getTotalTime();
727 ExprEngineTimer->startTimer();
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);
738 if (!Mgr->options.DumpExplodedGraphTo.empty())
739 Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo);
742 if (Mgr->options.visualizeExplodedGraphWithGraphViz)
743 Eng.ViewGraph(Mgr->options.TrimGraph);
746 if (BugReporterTimer)
747 BugReporterTimer->startTimer();
748 Eng.getBugReporter().FlushReports();
749 if (BugReporterTimer)
750 BugReporterTimer->stopTimer();
757std::unique_ptr<AnalysisASTConsumer>
763 bool hasModelPath = analyzerOpts.
Config.count(
"model-path") > 0;
765 return std::make_unique<AnalysisConsumer>(
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
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.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool shouldWalkTypesOfTypeLocs() const
Return whether this visitor should recurse into the types of TypeLocs.
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.