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"
51 using namespace clang;
53 using llvm::SmallPtrSet;
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;
189 const std::string& outdir,
193 : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr), PP(pp),
194 OutDir(outdir), Opts(opts), Plugins(plugins), Injector(injector) {
195 DigestAnalyzerOptions();
196 if (Opts->PrintStats) {
197 llvm::EnableStatistics();
198 TUTotalTimer =
new llvm::Timer(
"Analyzer Total Time");
202 ~AnalysisConsumer()
override {
203 if (Opts->PrintStats)
207 void DigestAnalyzerOptions() {
208 if (Opts->AnalysisDiagOpt !=
PD_NONE) {
210 ClangDiagPathDiagConsumer *clangDiags =
212 PathConsumers.push_back(clangDiags);
214 if (Opts->AnalysisDiagOpt == PD_TEXT) {
215 clangDiags->enablePaths();
217 }
else if (!OutDir.empty()) {
218 switch (Opts->AnalysisDiagOpt) {
220 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
222 CREATEFN(*Opts.get(), PathConsumers, OutDir, PP); \
224 #include "clang/StaticAnalyzer/Core/Analyses.def"
230 switch (Opts->AnalysisStoreOpt) {
232 llvm_unreachable(
"Unknown store manager.");
233 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
234 case NAME##Model: CreateStoreMgr = CREATEFN; break;
235 #include "clang/StaticAnalyzer/Core/Analyses.def"
238 switch (Opts->AnalysisConstraintsOpt) {
240 llvm_unreachable(
"Unknown constraint manager.");
241 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
242 case NAME##Model: CreateConstraintMgr = CREATEFN; break;
243 #include "clang/StaticAnalyzer/Core/Analyses.def"
247 void DisplayFunction(
const Decl *D, AnalysisMode Mode,
249 if (!Opts->AnalyzerDisplayProgress)
255 llvm::errs() <<
"ANALYZE";
257 if (Mode == AM_Syntax)
258 llvm::errs() <<
" (Syntax)";
259 else if (Mode == AM_Path) {
260 llvm::errs() <<
" (Path, ";
263 llvm::errs() <<
" Inline_Minimal";
266 llvm::errs() <<
" Inline_Regular";
272 assert(Mode == (AM_Syntax | AM_Path) &&
"Unexpected mode!");
275 if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
276 const NamedDecl *ND = cast<NamedDecl>(D);
277 llvm::errs() <<
' ' << *ND <<
'\n';
279 else if (isa<BlockDecl>(D)) {
280 llvm::errs() <<
' ' <<
"block(line:" << Loc.
getLine() <<
",col:"
283 else if (
const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
295 Mgr = llvm::make_unique<AnalysisManager>(
297 CreateStoreMgr, CreateConstraintMgr, checkerMgr.get(), *Opts, Injector);
303 void HandleTopLevelDeclInObjCContainer(
DeclGroupRef D)
override;
305 void HandleTranslationUnit(
ASTContext &C)
override;
315 void HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize);
323 void HandleCode(
Decl *D, AnalysisMode Mode,
327 void RunPathSensitiveChecks(
Decl *D,
330 void ActionExprEngine(
Decl *D,
bool ObjCGCEnabled,
335 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
338 bool VisitDecl(
Decl *D) {
339 AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
340 if (Mode & AM_Syntax)
341 checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
347 if (II && II->
getName().startswith(
"__inline"))
354 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
355 HandleCode(FD, RecVisitorMode);
362 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
363 HandleCode(MD, RecVisitorMode);
370 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
374 HandleCode(BD, RecVisitorMode);
381 PathConsumers.push_back(Consumer);
388 AnalysisMode getModeForDecl(
Decl *D, AnalysisMode Mode);
397 llvm::Timer* AnalysisConsumer::TUTotalTimer =
nullptr;
399 bool AnalysisConsumer::HandleTopLevelDecl(
DeclGroupRef DG) {
400 storeTopLevelDecls(DG);
404 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(
DeclGroupRef DG) {
405 storeTopLevelDecls(DG);
408 void AnalysisConsumer::storeTopLevelDecls(
DeclGroupRef DG) {
413 if (isa<ObjCMethodDecl>(*
I))
416 LocalTUDecls.push_back(*
I);
423 if (VisitedAsTopLevel.count(D))
433 if (isa<ObjCMethodDecl>(D))
437 return Visited.count(D);
441 AnalysisConsumer::getInliningModeForFunction(
const Decl *D,
446 if (Visited.count(D)) {
447 assert(isa<ObjCMethodDecl>(D) &&
448 "We are only reanalyzing ObjCMethods.");
457 void AnalysisConsumer::HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize) {
463 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
475 llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
476 for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator
477 I = RPOT.begin(),
E = RPOT.end();
I !=
E; ++
I) {
478 NumFunctionTopLevel++;
495 HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
496 (Mgr->options.InliningMode == All ?
nullptr : &VisitedCallees));
499 for (
const Decl *Callee : VisitedCallees)
502 Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
503 : Callee->getCanonicalDecl());
504 VisitedAsTopLevel.insert(D);
508 void AnalysisConsumer::HandleTranslationUnit(
ASTContext &C) {
516 if (Opts->DisableAllChecks)
520 if (TUTotalTimer) TUTotalTimer->startTimer();
525 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
530 RecVisitorMode = AM_Syntax;
531 if (!Mgr->shouldInlineCall())
532 RecVisitorMode |= AM_Path;
541 const unsigned LocalTUDeclsSize = LocalTUDecls.size();
542 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
543 TraverseDecl(LocalTUDecls[i]);
546 if (Mgr->shouldInlineCall())
547 HandleDeclsCallGraph(LocalTUDeclsSize);
550 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
552 RecVisitorBR =
nullptr;
561 if (TUTotalTimer) TUTotalTimer->stopTimer();
564 NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
565 if (NumBlocksInAnalyzedFunctions > 0)
566 PercentReachableBlocks =
567 (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
568 NumBlocksInAnalyzedFunctions;
574 return ID->getSelector().getAsString();
576 if (
const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
584 AnalysisConsumer::AnalysisMode
585 AnalysisConsumer::getModeForDecl(
Decl *D, AnalysisMode Mode) {
586 if (!Opts->AnalyzeSpecificFunction.empty() &&
603 return Mode & ~AM_Path;
609 void AnalysisConsumer::HandleCode(
Decl *D, AnalysisMode Mode,
614 Mode = getModeForDecl(D, Mode);
618 DisplayFunction(D, Mode, IMode);
619 CFG *DeclCFG = Mgr->getCFG(D);
621 unsigned CFGSize = DeclCFG->
size();
622 MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize;
626 Mgr->ClearContexts();
629 if (Mode & AM_Syntax)
630 checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
631 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
632 RunPathSensitiveChecks(D, IMode, VisitedCallees);
634 NumFunctionsAnalyzed++;
642 void AnalysisConsumer::ActionExprEngine(
Decl *D,
bool ObjCGCEnabled,
654 ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode);
657 std::unique_ptr<ExplodedNode::Auditor> Auditor;
658 if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
664 Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
665 Mgr->options.getMaxNodesPerTopLevelFunction());
672 if (Mgr->options.visualizeExplodedGraphWithGraphViz)
673 Eng.ViewGraph(Mgr->options.TrimGraph);
676 Eng.getBugReporter().FlushReports();
679 void AnalysisConsumer::RunPathSensitiveChecks(
Decl *D,
683 switch (Mgr->getLangOpts().getGC()) {
685 ActionExprEngine(D,
false, IMode, Visited);
689 ActionExprEngine(D,
true, IMode, Visited);
693 ActionExprEngine(D,
false, IMode, Visited);
694 ActionExprEngine(D,
true, IMode, Visited);
703 std::unique_ptr<AnalysisASTConsumer>
709 bool hasModelPath = analyzerOpts->Config.count(
"model-path") > 0;
711 return llvm::make_unique<AnalysisConsumer>(
724 std::unique_ptr<raw_ostream> Out;
728 typedef llvm::DenseMap<void*,unsigned> VMap;
732 UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef
Filename);
734 ~UbigraphViz()
override;
744 llvm::sys::fs::createTemporaryFile(
"llvm_ubi",
"", FD, P);
745 llvm::errs() <<
"Writing '" << P <<
"'.\n";
747 auto Stream = llvm::make_unique<llvm::raw_fd_ostream>(FD,
true);
749 return llvm::make_unique<UbigraphViz>(std::move(Stream),
P);
754 assert (Src != Dst &&
"Self-edges are not allowed.");
760 if (SrcI == M.end()) {
761 M[Src] = SrcID = Cntr++;
762 *Out <<
"('vertex', " << SrcID <<
", ('color','#00ff00'))\n";
765 SrcID = SrcI->second;
771 if (DstI == M.end()) {
772 M[Dst] = DstID = Cntr++;
773 *Out <<
"('vertex', " << DstID <<
")\n";
777 DstID = DstI->second;
778 *Out <<
"('change_vertex_style', " << DstID <<
", 1)\n";
782 *Out <<
"('edge', " << SrcID <<
", " << DstID
783 <<
", ('arrow','true'), ('oriented', 'true'))\n";
786 UbigraphViz::UbigraphViz(std::unique_ptr<raw_ostream> OutStream,
788 : Out(std::move(OutStream)), Filename(Filename), Cntr(0) {
790 *Out <<
"('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
791 *Out <<
"('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
792 " ('size', '1.5'))\n";
795 UbigraphViz::~UbigraphViz() {
797 llvm::errs() <<
"Running 'ubiviz' program... ";
800 if (
auto Path = llvm::sys::findProgramByName(
"ubiviz"))
802 std::vector<const char*> args;
803 args.push_back(Ubiviz.c_str());
805 args.push_back(
nullptr);
807 if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0],
nullptr,
nullptr, 0, 0,
809 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.
Decl - This represents one declaration (or definition), e.g.
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 preorder depth-first traversal on the entire Clang AST and visits each node...
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)
ID
Defines the set of possible language-specific address spaces.
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
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
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)
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.
SourceLocation getLocation() const
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...
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
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.