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 {
114 for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(),
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();
144 public DataRecursiveASTVisitor<AnalysisConsumer> {
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);
371 HandleCode(BD, RecVisitorMode);
377 PathConsumers.push_back(Consumer);
384 AnalysisMode getModeForDecl(
Decl *D, AnalysisMode Mode);
393 llvm::Timer* AnalysisConsumer::TUTotalTimer =
nullptr;
395 bool AnalysisConsumer::HandleTopLevelDecl(
DeclGroupRef DG) {
396 storeTopLevelDecls(DG);
400 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(
DeclGroupRef DG) {
401 storeTopLevelDecls(DG);
404 void AnalysisConsumer::storeTopLevelDecls(
DeclGroupRef DG) {
409 if (isa<ObjCMethodDecl>(*I))
412 LocalTUDecls.push_back(*I);
419 if (VisitedAsTopLevel.count(D))
429 if (isa<ObjCMethodDecl>(D))
433 return Visited.count(D);
437 AnalysisConsumer::getInliningModeForFunction(
const Decl *D,
442 if (Visited.count(D)) {
443 assert(isa<ObjCMethodDecl>(D) &&
444 "We are only reanalyzing ObjCMethods.");
453 void AnalysisConsumer::HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize) {
459 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
471 llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
472 for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator
473 I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
474 NumFunctionTopLevel++;
491 HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
492 (Mgr->options.InliningMode == All ?
nullptr : &VisitedCallees));
495 for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
496 E = VisitedCallees.end(); I != E; ++I) {
499 VisitedAsTopLevel.insert(D);
503 void AnalysisConsumer::HandleTranslationUnit(
ASTContext &C) {
511 if (Opts->DisableAllChecks)
515 if (TUTotalTimer) TUTotalTimer->startTimer();
520 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
525 RecVisitorMode = AM_Syntax;
526 if (!Mgr->shouldInlineCall())
527 RecVisitorMode |= AM_Path;
536 const unsigned LocalTUDeclsSize = LocalTUDecls.size();
537 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
538 TraverseDecl(LocalTUDecls[i]);
541 if (Mgr->shouldInlineCall())
542 HandleDeclsCallGraph(LocalTUDeclsSize);
545 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
547 RecVisitorBR =
nullptr;
556 if (TUTotalTimer) TUTotalTimer->stopTimer();
559 NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
560 if (NumBlocksInAnalyzedFunctions > 0)
561 PercentReachableBlocks =
562 (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
563 NumBlocksInAnalyzedFunctions;
569 return ID->getSelector().getAsString();
571 if (
const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
579 AnalysisConsumer::AnalysisMode
580 AnalysisConsumer::getModeForDecl(
Decl *D, AnalysisMode Mode) {
581 if (!Opts->AnalyzeSpecificFunction.empty() &&
598 return Mode & ~AM_Path;
604 void AnalysisConsumer::HandleCode(
Decl *D, AnalysisMode Mode,
609 Mode = getModeForDecl(D, Mode);
613 DisplayFunction(D, Mode, IMode);
614 CFG *DeclCFG = Mgr->getCFG(D);
616 unsigned CFGSize = DeclCFG->
size();
617 MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize;
621 Mgr->ClearContexts();
624 if (Mode & AM_Syntax)
625 checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
626 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
627 RunPathSensitiveChecks(D, IMode, VisitedCallees);
629 NumFunctionsAnalyzed++;
637 void AnalysisConsumer::ActionExprEngine(
Decl *D,
bool ObjCGCEnabled,
649 ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode);
652 std::unique_ptr<ExplodedNode::Auditor> Auditor;
653 if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
659 Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
660 Mgr->options.getMaxNodesPerTopLevelFunction());
667 if (Mgr->options.visualizeExplodedGraphWithGraphViz)
668 Eng.ViewGraph(Mgr->options.TrimGraph);
671 Eng.getBugReporter().FlushReports();
674 void AnalysisConsumer::RunPathSensitiveChecks(
Decl *D,
678 switch (Mgr->getLangOpts().getGC()) {
680 ActionExprEngine(D,
false, IMode, Visited);
684 ActionExprEngine(D,
true, IMode, Visited);
688 ActionExprEngine(D,
false, IMode, Visited);
689 ActionExprEngine(D,
true, IMode, Visited);
698 std::unique_ptr<AnalysisASTConsumer>
704 bool hasModelPath = analyzerOpts->Config.count(
"model-path") > 0;
706 return llvm::make_unique<AnalysisConsumer>(
719 std::unique_ptr<raw_ostream> Out;
720 std::string Filename;
723 typedef llvm::DenseMap<void*,unsigned> VMap;
727 UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef Filename);
729 ~UbigraphViz()
override;
739 llvm::sys::fs::createTemporaryFile(
"llvm_ubi",
"", FD, P);
740 llvm::errs() <<
"Writing '" << P <<
"'.\n";
742 auto Stream = llvm::make_unique<llvm::raw_fd_ostream>(FD,
true);
744 return llvm::make_unique<UbigraphViz>(std::move(Stream),
P);
749 assert (Src != Dst &&
"Self-edges are not allowed.");
752 VMap::iterator SrcI= M.find(Src);
755 if (SrcI == M.end()) {
756 M[Src] = SrcID = Cntr++;
757 *Out <<
"('vertex', " << SrcID <<
", ('color','#00ff00'))\n";
760 SrcID = SrcI->second;
763 VMap::iterator DstI= M.find(Dst);
766 if (DstI == M.end()) {
767 M[Dst] = DstID = Cntr++;
768 *Out <<
"('vertex', " << DstID <<
")\n";
772 DstID = DstI->second;
773 *Out <<
"('change_vertex_style', " << DstID <<
", 1)\n";
777 *Out <<
"('edge', " << SrcID <<
", " << DstID
778 <<
", ('arrow','true'), ('oriented', 'true'))\n";
781 UbigraphViz::UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef Filename)
782 : Out(std::move(Out)), Filename(Filename), Cntr(0) {
784 *Out <<
"('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
785 *Out <<
"('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
786 " ('size', '1.5'))\n";
789 UbigraphViz::~UbigraphViz() {
791 llvm::errs() <<
"Running 'ubiviz' program... ";
794 if (
auto Path = llvm::sys::findProgramByName(
"ubiviz"))
796 std::vector<const char*> args;
797 args.push_back(Ubiviz.c_str());
798 args.push_back(Filename.c_str());
799 args.push_back(
nullptr);
801 if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0],
nullptr,
nullptr, 0, 0,
803 llvm::errs() <<
"Error viewing graph: " << ErrMsg <<
"\n";
807 llvm::sys::fs::remove(Filename);
The AST-based call graph.
std::string OutputFile
The output file, if any.
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
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
std::unique_ptr< ConstraintManager >(* ConstraintManagerCreator)(ProgramStateManager &, SubEngine *)
FullSourceLoc asLocation() const
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.
Concrete class used by the front-end to report problems and issues.
unsigned getLine() const
Return the presumed line number of this location.
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.
std::vector< std::string > Plugins
The list of plugins to load.
StringRef getName() const
Return the actual identifier string.
bool hasFatalErrorOccurred() const
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.
const char * getFilename() const
Return the presumed filename of this location.
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
virtual Stmt * getBody() const
std::string getAsString() const
Derive the full selector name (e.g. "foo:bar:") and return it as an std::string.
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
std::unique_ptr< AnalysisASTConsumer > CreateAnalysisConsumer(CompilerInstance &CI)
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
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.