39 #include "llvm/ADT/DepthFirstIterator.h"
40 #include "llvm/ADT/PostOrderIterator.h"
41 #include "llvm/ADT/SmallPtrSet.h"
42 #include "llvm/ADT/Statistic.h"
43 #include "llvm/Support/FileSystem.h"
44 #include "llvm/Support/Path.h"
45 #include "llvm/Support/Program.h"
46 #include "llvm/Support/Timer.h"
47 #include "llvm/Support/raw_ostream.h"
52 using namespace clang;
55 #define DEBUG_TYPE "AnalysisConsumer"
57 static std::unique_ptr<ExplodedNode::Auditor>
CreateUbiViz();
59 STATISTIC(NumFunctionTopLevel,
"The # of functions at top level.");
61 "The # of functions and blocks analyzed (as top level "
62 "with inlining turned on).");
64 "The # of basic blocks in the analyzed functions.");
65 STATISTIC(PercentReachableBlocks,
"The % of reachable basic blocks.");
66 STATISTIC(MaxCFGSize,
"The maximum number of basic blocks in a function.");
72 void ento::createPlistHTMLDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
74 const std::string &prefix,
76 createHTMLDiagnosticConsumer(AnalyzerOpts, C,
77 llvm::sys::path::parent_path(prefix), PP);
78 createPlistDiagnosticConsumer(AnalyzerOpts, C, prefix, PP);
81 void ento::createTextPathDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
83 const std::string &Prefix,
85 llvm_unreachable(
"'text' consumer should be enabled on ClangDiags");
94 : Diag(Diag), IncludePath(
false) {}
95 ~ClangDiagPathDiagConsumer()
override {}
96 StringRef getName()
const override {
return "ClangDiags"; }
98 bool supportsLogicalOpControlFlow()
const override {
return true; }
99 bool supportsCrossFileDiagnostics()
const override {
return true; }
101 PathGenerationScheme getGenerationScheme()
const override {
102 return IncludePath ? Minimal :
None;
109 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
110 FilesMade *filesMade)
override {
115 E = Diags.end();
I !=
E; ++
I) {
119 << PD->
path.back()->getRanges();
125 for (PathPieces::const_iterator PI = FlatPath.begin(),
129 Diag.Report(NoteLoc, NoteID) << (*PI)->getString()
130 << (*PI)->getRanges();
150 typedef unsigned AnalysisMode;
153 AnalysisMode RecVisitorMode;
160 const std::string OutDir;
178 std::unique_ptr<CheckerManager> checkerMgr;
179 std::unique_ptr<AnalysisManager> Mgr;
182 static llvm::Timer* TUTotalTimer;
188 AnalysisConsumer(
const Preprocessor &pp,
const std::string &outdir,
191 : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr), PP(pp),
192 OutDir(outdir), Opts(std::move(opts)), Plugins(plugins),
194 DigestAnalyzerOptions();
195 if (Opts->PrintStats) {
196 llvm::EnableStatistics();
197 TUTotalTimer =
new llvm::Timer(
"Analyzer Total Time");
201 ~AnalysisConsumer()
override {
202 if (Opts->PrintStats)
206 void DigestAnalyzerOptions() {
207 if (Opts->AnalysisDiagOpt !=
PD_NONE) {
209 ClangDiagPathDiagConsumer *clangDiags =
211 PathConsumers.push_back(clangDiags);
213 if (Opts->AnalysisDiagOpt == PD_TEXT) {
214 clangDiags->enablePaths();
216 }
else if (!OutDir.empty()) {
217 switch (Opts->AnalysisDiagOpt) {
219 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
221 CREATEFN(*Opts.get(), PathConsumers, OutDir, PP); \
223 #include "clang/StaticAnalyzer/Core/Analyses.def"
229 switch (Opts->AnalysisStoreOpt) {
231 llvm_unreachable(
"Unknown store manager.");
232 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
233 case NAME##Model: CreateStoreMgr = CREATEFN; break;
234 #include "clang/StaticAnalyzer/Core/Analyses.def"
237 switch (Opts->AnalysisConstraintsOpt) {
239 llvm_unreachable(
"Unknown constraint manager.");
240 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
241 case NAME##Model: CreateConstraintMgr = CREATEFN; break;
242 #include "clang/StaticAnalyzer/Core/Analyses.def"
246 void DisplayFunction(
const Decl *D, AnalysisMode Mode,
248 if (!Opts->AnalyzerDisplayProgress)
254 llvm::errs() <<
"ANALYZE";
256 if (Mode == AM_Syntax)
257 llvm::errs() <<
" (Syntax)";
258 else if (Mode == AM_Path) {
259 llvm::errs() <<
" (Path, ";
262 llvm::errs() <<
" Inline_Minimal";
265 llvm::errs() <<
" Inline_Regular";
271 assert(Mode == (AM_Syntax | AM_Path) &&
"Unexpected mode!");
274 if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
275 const NamedDecl *ND = cast<NamedDecl>(D);
278 else if (isa<BlockDecl>(D)) {
279 llvm::errs() <<
' ' <<
"block(line:" << Loc.
getLine() <<
",col:"
282 else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
294 Mgr = llvm::make_unique<AnalysisManager>(
296 CreateStoreMgr, CreateConstraintMgr, checkerMgr.get(), *Opts, Injector);
302 void HandleTopLevelDeclInObjCContainer(
DeclGroupRef D)
override;
304 void HandleTranslationUnit(
ASTContext &C)
override;
314 void HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize);
322 void HandleCode(
Decl *D, AnalysisMode Mode,
326 void RunPathSensitiveChecks(
Decl *D,
329 void ActionExprEngine(
Decl *D,
bool ObjCGCEnabled,
334 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
337 bool VisitDecl(
Decl *D) {
338 AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
339 if (Mode & AM_Syntax)
340 checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
346 if (II && II->
getName().startswith(
"__inline"))
353 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
354 HandleCode(FD, RecVisitorMode);
361 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
362 HandleCode(MD, RecVisitorMode);
369 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
373 HandleCode(BD, RecVisitorMode);
380 PathConsumers.push_back(Consumer);
387 AnalysisMode getModeForDecl(
Decl *D, AnalysisMode Mode);
396 llvm::Timer* AnalysisConsumer::TUTotalTimer =
nullptr;
398 bool AnalysisConsumer::HandleTopLevelDecl(
DeclGroupRef DG) {
399 storeTopLevelDecls(DG);
403 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(
DeclGroupRef DG) {
404 storeTopLevelDecls(DG);
407 void AnalysisConsumer::storeTopLevelDecls(
DeclGroupRef DG) {
412 if (isa<ObjCMethodDecl>(*
I))
415 LocalTUDecls.push_back(*
I);
422 if (VisitedAsTopLevel.count(D))
432 if (isa<ObjCMethodDecl>(D))
436 return Visited.count(D);
440 AnalysisConsumer::getInliningModeForFunction(
const Decl *D,
445 if (Visited.count(D)) {
446 assert(isa<ObjCMethodDecl>(D) &&
447 "We are only reanalyzing ObjCMethods.");
456 void AnalysisConsumer::HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize) {
462 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
474 llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
475 for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator
476 I = RPOT.begin(),
E = RPOT.end();
I !=
E; ++
I) {
477 NumFunctionTopLevel++;
494 HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
495 (Mgr->options.InliningMode == All ?
nullptr : &VisitedCallees));
498 for (
const Decl *Callee : VisitedCallees)
501 Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
502 : Callee->getCanonicalDecl());
503 VisitedAsTopLevel.insert(D);
507 void AnalysisConsumer::HandleTranslationUnit(
ASTContext &C) {
515 if (Opts->DisableAllChecks)
519 if (TUTotalTimer) TUTotalTimer->startTimer();
524 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
529 RecVisitorMode = AM_Syntax;
530 if (!Mgr->shouldInlineCall())
531 RecVisitorMode |= AM_Path;
540 const unsigned LocalTUDeclsSize = LocalTUDecls.size();
541 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
542 TraverseDecl(LocalTUDecls[i]);
545 if (Mgr->shouldInlineCall())
546 HandleDeclsCallGraph(LocalTUDeclsSize);
549 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
551 RecVisitorBR =
nullptr;
560 if (TUTotalTimer) TUTotalTimer->stopTimer();
563 NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
564 if (NumBlocksInAnalyzedFunctions > 0)
565 PercentReachableBlocks =
566 (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
567 NumBlocksInAnalyzedFunctions;
573 return ID->getSelector().getAsString();
575 if (
const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
583 AnalysisConsumer::AnalysisMode
584 AnalysisConsumer::getModeForDecl(
Decl *D, AnalysisMode Mode) {
585 if (!Opts->AnalyzeSpecificFunction.empty() &&
595 const Stmt *Body = D->getBody();
596 SourceLocation SL = Body ? Body->getLocStart() : D->getLocation();
602 return Mode & ~AM_Path;
608 void AnalysisConsumer::HandleCode(
Decl *D, AnalysisMode Mode,
613 Mode = getModeForDecl(D, Mode);
617 DisplayFunction(D, Mode, IMode);
618 CFG *DeclCFG = Mgr->getCFG(D);
620 unsigned CFGSize = DeclCFG->
size();
621 MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize;
625 Mgr->ClearContexts();
628 if (Mode & AM_Syntax)
629 checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
630 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
631 RunPathSensitiveChecks(D, IMode, VisitedCallees);
633 NumFunctionsAnalyzed++;
641 void AnalysisConsumer::ActionExprEngine(
Decl *D,
bool ObjCGCEnabled,
653 ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode);
656 std::unique_ptr<ExplodedNode::Auditor> Auditor;
657 if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
663 Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
664 Mgr->options.getMaxNodesPerTopLevelFunction());
671 if (Mgr->options.visualizeExplodedGraphWithGraphViz)
672 Eng.ViewGraph(Mgr->options.TrimGraph);
675 Eng.getBugReporter().FlushReports();
678 void AnalysisConsumer::RunPathSensitiveChecks(
Decl *D,
682 switch (Mgr->getLangOpts().getGC()) {
684 ActionExprEngine(D,
false, IMode, Visited);
688 ActionExprEngine(D,
true, IMode, Visited);
692 ActionExprEngine(D,
false, IMode, Visited);
693 ActionExprEngine(D,
true, IMode, Visited);
702 std::unique_ptr<AnalysisASTConsumer>
708 bool hasModelPath = analyzerOpts->Config.count(
"model-path") > 0;
710 return llvm::make_unique<AnalysisConsumer>(
723 std::unique_ptr<raw_ostream> Out;
727 typedef llvm::DenseMap<void*,unsigned> VMap;
731 UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef
Filename);
733 ~UbigraphViz()
override;
743 llvm::sys::fs::createTemporaryFile(
"llvm_ubi",
"", FD, P);
744 llvm::errs() <<
"Writing '" << P <<
"'.\n";
746 auto Stream = llvm::make_unique<llvm::raw_fd_ostream>(FD,
true);
748 return llvm::make_unique<UbigraphViz>(std::move(Stream),
P);
753 assert (Src != Dst &&
"Self-edges are not allowed.");
759 if (SrcI == M.end()) {
760 M[Src] = SrcID = Cntr++;
761 *Out <<
"('vertex', " << SrcID <<
", ('color','#00ff00'))\n";
764 SrcID = SrcI->second;
770 if (DstI == M.end()) {
771 M[Dst] = DstID = Cntr++;
772 *Out <<
"('vertex', " << DstID <<
")\n";
776 DstID = DstI->second;
777 *Out <<
"('change_vertex_style', " << DstID <<
", 1)\n";
781 *Out <<
"('edge', " << SrcID <<
", " << DstID
782 <<
", ('arrow','true'), ('oriented', 'true'))\n";
785 UbigraphViz::UbigraphViz(std::unique_ptr<raw_ostream> OutStream,
787 : Out(std::move(OutStream)), Filename(Filename), Cntr(0) {
789 *Out <<
"('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
790 *Out <<
"('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
791 " ('size', '1.5'))\n";
794 UbigraphViz::~UbigraphViz() {
796 llvm::errs() <<
"Running 'ubiviz' program... ";
799 if (
auto Path = llvm::sys::findProgramByName(
"ubiviz"))
801 const char *args[] = {Ubiviz.c_str(),
Filename.c_str(),
nullptr};
803 if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0],
nullptr,
nullptr, 0, 0,
805 llvm::errs() <<
"Error viewing graph: " << ErrMsg <<
"\n";
The AST-based call graph.
std::string OutputFile
The output file, if any.
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
Smart pointer class that efficiently represents Objective-C method names.
unsigned getColumn() const
Return the presumed column number of this location.
Defines the clang::FileManager interface and associated types.
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
STATISTIC(NumFunctionTopLevel,"The # of functions at top level.")
Defines the SourceManager interface.
PathPieces flatten(bool ShouldFlattenMacros) const
bool hasErrorOccurred() const
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
PathDiagnosticLocation getLocation() const
ObjCMethodDecl - Represents an instance or class method declaration.
std::unique_ptr< ConstraintManager >(* ConstraintManagerCreator)(ProgramStateManager &, SubEngine *)
FullSourceLoc asLocation() const
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
One of these records is kept for each identifier that is lexed.
Follow the default settings for inlining callees.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Defines the clang::CodeInjector interface which is responsible for injecting AST of function definiti...
std::deque< Decl * > SetOfDecls
const LangOptions & getLangOpts() const
bool isThisDeclarationADefinition() const
Returns whether this specific method is a definition.
FrontendOptions & getFrontendOpts()
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
unsigned size() const
size - Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlo...
Concrete class used by the front-end to report problems and issues.
unsigned getLine() const
Return the presumed line number of this location.
A class that does preordor or postorder depth-first traversal on the entire Clang AST and visits each...
detail::InMemoryDirectory::const_iterator I
Preprocessor & getPreprocessor() const
Return the current preprocessor.
AnalyzerOptionsRef getAnalyzerOpts()
static bool shouldSkipFunction(const Decl *D, const SetOfConstDecls &Visited, const SetOfConstDecls &VisitedAsTopLevel)
InliningModes
The modes of inlining, which override the default analysis-wide settings.
BlockDecl - This represents a block literal declaration, which is like an unnamed FunctionDecl...
std::vector< std::string > Plugins
The list of plugins to load.
StringRef getName() const
Return the actual identifier string.
bool hasFatalErrorOccurred() const
CFG - Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
StringRef getShortDescription() const
TranslationUnitDecl * getTranslationUnitDecl() const
Defines the clang::Preprocessor interface.
bool isWrittenInMainFile(SourceLocation Loc) const
Returns true if the spelling location for the given location is in the main file buffer.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
This file defines the clang::ento::ModelInjector class which implements the clang::CodeInjector inter...
Represents an unpacked "presumed" location which can be presented to the user.
BugReporter is a utility class for generating PathDiagnostics for analysis.
const char * getFilename() const
Return the presumed filename of this location.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Encodes a location in the source.
const TemplateArgument * iterator
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
std::string getAsString() const
Derive the full selector name (e.g.
Do minimal inlining of callees.
DiagnosticsEngine & getDiagnostics() const
static std::string getFunctionName(const Decl *D)
CodeInjector is an interface which is responsible for injecting AST of function definitions that may ...
bool isThisDeclarationADefinition() const
isThisDeclarationADefinition - Returns whether this specific declaration of the function is also a de...
detail::InMemoryDirectory::const_iterator E
std::unique_ptr< AnalysisASTConsumer > CreateAnalysisConsumer(CompilerInstance &CI)
CreateAnalysisConsumer - Creates an ASTConsumer to run various code analysis passes.
void setWarningsAsErrors(bool Val)
When set to true, any warnings reported are issued as errors.
static std::unique_ptr< ExplodedNode::Auditor > CreateUbiViz()
static void SetAuditor(Auditor *A)
std::string getQualifiedNameAsString() const
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
void addToCallGraph(Decl *D)
Populate the call graph with the functions in the given declaration.
TranslationUnitDecl - The top declaration context.
NamedDecl - This represents a decl with a name.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
std::unique_ptr< CheckerManager > createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, ArrayRef< std::string > plugins, DiagnosticsEngine &diags)
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
std::unique_ptr< StoreManager >(* StoreManagerCreator)(ProgramStateManager &)
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.