36 #include "llvm/ADT/PostOrderIterator.h" 37 #include "llvm/ADT/Statistic.h" 38 #include "llvm/Support/FileSystem.h" 39 #include "llvm/Support/Path.h" 40 #include "llvm/Support/Program.h" 41 #include "llvm/Support/Timer.h" 42 #include "llvm/Support/raw_ostream.h" 47 using namespace clang;
50 #define DEBUG_TYPE "AnalysisConsumer" 52 static std::unique_ptr<ExplodedNode::Auditor>
CreateUbiViz();
54 STATISTIC(NumFunctionTopLevel,
"The # of functions at top level.");
56 "The # of functions and blocks analyzed (as top level " 57 "with inlining turned on).");
59 "The # of basic blocks in the analyzed functions.");
60 STATISTIC(PercentReachableBlocks,
"The % of reachable basic blocks.");
61 STATISTIC(MaxCFGSize,
"The maximum number of basic blocks in a function.");
67 void ento::createPlistHTMLDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
69 const std::string &prefix,
71 createHTMLDiagnosticConsumer(AnalyzerOpts, C,
72 llvm::sys::path::parent_path(prefix), PP);
73 createPlistDiagnosticConsumer(AnalyzerOpts, C, prefix, PP);
76 void ento::createTextPathDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
78 const std::string &Prefix,
80 llvm_unreachable(
"'text' consumer should be enabled on ClangDiags");
89 : Diag(Diag), IncludePath(
false) {}
90 ~ClangDiagPathDiagConsumer()
override {}
91 StringRef getName()
const override {
return "ClangDiags"; }
93 bool supportsLogicalOpControlFlow()
const override {
return true; }
94 bool supportsCrossFileDiagnostics()
const override {
return true; }
96 PathGenerationScheme getGenerationScheme()
const override {
97 return IncludePath ? Minimal : None;
104 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
105 FilesMade *filesMade)
override {
109 for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(),
110 E = Diags.end(); I != E; ++I) {
114 << PD->
path.back()->getRanges();
117 for (
const auto &Piece : PD->
path) {
118 if (!isa<PathDiagnosticNotePiece>(Piece.get()))
122 Diag.
Report(NoteLoc, NoteID) << Piece->getString()
123 << Piece->getRanges();
131 for (
const auto &Piece : FlatPath) {
132 if (isa<PathDiagnosticNotePiece>(Piece.get()))
136 Diag.
Report(NoteLoc, NoteID) << Piece->getString()
137 << Piece->getRanges();
157 typedef unsigned AnalysisMode;
160 AnalysisMode RecVisitorMode;
167 const std::string OutDir;
185 std::unique_ptr<CheckerManager> checkerMgr;
186 std::unique_ptr<AnalysisManager> Mgr;
189 static llvm::Timer* TUTotalTimer;
195 AnalysisConsumer(
const Preprocessor &pp,
const std::string &outdir,
198 : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr), PP(pp),
199 OutDir(outdir), Opts(
std::move(opts)), Plugins(plugins),
201 DigestAnalyzerOptions();
202 if (Opts->PrintStats) {
203 llvm::EnableStatistics(
false);
204 TUTotalTimer =
new llvm::Timer(
"time",
"Analyzer Total Time");
208 ~AnalysisConsumer()
override {
209 if (Opts->PrintStats) {
211 llvm::PrintStatistics();
215 void DigestAnalyzerOptions() {
216 if (Opts->AnalysisDiagOpt !=
PD_NONE) {
218 ClangDiagPathDiagConsumer *clangDiags =
220 PathConsumers.push_back(clangDiags);
222 if (Opts->AnalysisDiagOpt == PD_TEXT) {
223 clangDiags->enablePaths();
225 }
else if (!OutDir.empty()) {
226 switch (Opts->AnalysisDiagOpt) {
228 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ 230 CREATEFN(*Opts.get(), PathConsumers, OutDir, PP); \ 232 #include "clang/StaticAnalyzer/Core/Analyses.def" 238 switch (Opts->AnalysisStoreOpt) {
240 llvm_unreachable(
"Unknown store manager.");
241 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ 242 case NAME##Model: CreateStoreMgr = CREATEFN; break; 243 #include "clang/StaticAnalyzer/Core/Analyses.def" 246 switch (Opts->AnalysisConstraintsOpt) {
248 llvm_unreachable(
"Unknown constraint manager.");
249 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ 250 case NAME##Model: CreateConstraintMgr = CREATEFN; break; 251 #include "clang/StaticAnalyzer/Core/Analyses.def" 255 void DisplayFunction(
const Decl *D, AnalysisMode Mode,
257 if (!Opts->AnalyzerDisplayProgress)
263 llvm::errs() <<
"ANALYZE";
265 if (Mode == AM_Syntax)
266 llvm::errs() <<
" (Syntax)";
267 else if (Mode == AM_Path) {
268 llvm::errs() <<
" (Path, ";
271 llvm::errs() <<
" Inline_Minimal";
274 llvm::errs() <<
" Inline_Regular";
280 assert(Mode == (AM_Syntax | AM_Path) &&
"Unexpected mode!");
283 << getFunctionName(D) <<
'\n';
287 void Initialize(
ASTContext &Context)
override {
292 Mgr = llvm::make_unique<AnalysisManager>(
294 CreateStoreMgr, CreateConstraintMgr, checkerMgr.get(), *Opts, Injector);
300 void HandleTopLevelDeclInObjCContainer(
DeclGroupRef D)
override;
302 void HandleTranslationUnit(
ASTContext &C)
override;
312 void HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize);
320 void HandleCode(
Decl *D, AnalysisMode Mode,
324 void RunPathSensitiveChecks(
Decl *D,
327 void ActionExprEngine(
Decl *D,
bool ObjCGCEnabled,
332 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
335 bool VisitDecl(
Decl *D) {
336 AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
337 if (Mode & AM_Syntax)
338 checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
344 if (II && II->
getName().startswith(
"__inline"))
351 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
352 HandleCode(FD, RecVisitorMode);
359 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
360 HandleCode(MD, RecVisitorMode);
367 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
371 HandleCode(BD, RecVisitorMode);
378 PathConsumers.push_back(Consumer);
383 std::string getFunctionName(
const Decl *D);
386 AnalysisMode getModeForDecl(
Decl *D, AnalysisMode Mode);
395 llvm::Timer* AnalysisConsumer::TUTotalTimer =
nullptr;
397 bool AnalysisConsumer::HandleTopLevelDecl(
DeclGroupRef DG) {
398 storeTopLevelDecls(DG);
402 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(
DeclGroupRef DG) {
403 storeTopLevelDecls(DG);
406 void AnalysisConsumer::storeTopLevelDecls(
DeclGroupRef DG) {
411 if (isa<ObjCMethodDecl>(*I))
414 LocalTUDecls.push_back(*I);
421 if (VisitedAsTopLevel.count(D))
431 if (isa<ObjCMethodDecl>(D))
436 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
437 if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())
442 return Visited.count(D);
446 AnalysisConsumer::getInliningModeForFunction(
const Decl *D,
451 if (Visited.count(D) && isa<ObjCMethodDecl>(D)) {
460 void AnalysisConsumer::HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize) {
466 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
478 llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
479 for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator
480 I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
481 NumFunctionTopLevel++;
498 HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
499 (Mgr->options.InliningMode ==
All ?
nullptr : &VisitedCallees));
502 for (
const Decl *Callee : VisitedCallees)
505 Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
506 : Callee->getCanonicalDecl());
507 VisitedAsTopLevel.insert(D);
511 void AnalysisConsumer::HandleTranslationUnit(
ASTContext &C) {
519 if (Opts->DisableAllChecks)
523 if (TUTotalTimer) TUTotalTimer->startTimer();
528 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
533 RecVisitorMode = AM_Syntax;
534 if (!Mgr->shouldInlineCall())
535 RecVisitorMode |= AM_Path;
544 const unsigned LocalTUDeclsSize = LocalTUDecls.size();
545 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
546 TraverseDecl(LocalTUDecls[i]);
549 if (Mgr->shouldInlineCall())
550 HandleDeclsCallGraph(LocalTUDeclsSize);
553 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
555 RecVisitorBR =
nullptr;
564 if (TUTotalTimer) TUTotalTimer->stopTimer();
568 if (NumBlocksInAnalyzedFunctions > 0)
569 PercentReachableBlocks =
571 NumBlocksInAnalyzedFunctions;
575 std::string AnalysisConsumer::getFunctionName(
const Decl *D) {
577 llvm::raw_string_ostream OS(Str);
579 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
583 if (Ctx->getLangOpts().CPlusPlus) {
588 OS <<
P->getType().getAsString();
593 }
else if (isa<BlockDecl>(D)) {
601 }
else if (
const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
604 OS << (OMD->isInstanceMethod() ?
'-' :
'+') <<
'[';
606 if (
const auto *OID = dyn_cast<ObjCImplementationDecl>(DC)) {
607 OS << OID->getName();
608 }
else if (
const auto *OID = dyn_cast<ObjCInterfaceDecl>(DC)) {
609 OS << OID->getName();
610 }
else if (
const auto *OC = dyn_cast<ObjCCategoryDecl>(DC)) {
611 if (OC->IsClassExtension()) {
612 OS << OC->getClassInterface()->getName();
614 OS << OC->getIdentifier()->getNameStart() <<
'(' 615 << OC->getIdentifier()->getNameStart() <<
')';
617 }
else if (
const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
618 OS << OCD->getClassInterface()->getName() <<
'(' 619 << OCD->getName() <<
')';
620 }
else if (isa<ObjCProtocolDecl>(DC)) {
624 cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
628 OS <<
' ' << OMD->getSelector().getAsString() <<
']';
635 AnalysisConsumer::AnalysisMode
636 AnalysisConsumer::getModeForDecl(
Decl *D, AnalysisMode Mode) {
637 if (!Opts->AnalyzeSpecificFunction.empty() &&
638 getFunctionName(D) != Opts->AnalyzeSpecificFunction)
654 return Mode & ~AM_Path;
660 void AnalysisConsumer::HandleCode(
Decl *D, AnalysisMode Mode,
665 Mode = getModeForDecl(D, Mode);
670 Mgr->ClearContexts();
672 if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized())
675 DisplayFunction(D, Mode, IMode);
676 CFG *DeclCFG = Mgr->getCFG(D);
678 MaxCFGSize.updateMax(DeclCFG->
size());
682 if (Mode & AM_Syntax)
683 checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
684 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
685 RunPathSensitiveChecks(D, IMode, VisitedCallees);
687 NumFunctionsAnalyzed++;
695 void AnalysisConsumer::ActionExprEngine(
Decl *D,
bool ObjCGCEnabled,
707 ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode);
710 std::unique_ptr<ExplodedNode::Auditor> Auditor;
711 if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
717 Eng.
ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
718 Mgr->options.getMaxNodesPerTopLevelFunction());
725 if (Mgr->options.visualizeExplodedGraphWithGraphViz)
732 void AnalysisConsumer::RunPathSensitiveChecks(
Decl *D,
736 switch (Mgr->getLangOpts().getGC()) {
738 ActionExprEngine(D,
false, IMode, Visited);
742 ActionExprEngine(D,
true, IMode, Visited);
746 ActionExprEngine(D,
false, IMode, Visited);
747 ActionExprEngine(D,
true, IMode, Visited);
756 std::unique_ptr<AnalysisASTConsumer>
762 bool hasModelPath = analyzerOpts->Config.count(
"model-path") > 0;
764 return llvm::make_unique<AnalysisConsumer>(
777 std::unique_ptr<raw_ostream> Out;
781 typedef llvm::DenseMap<void*,unsigned> VMap;
785 UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef Filename);
787 ~UbigraphViz()
override;
797 llvm::sys::fs::createTemporaryFile(
"llvm_ubi",
"", FD, P);
798 llvm::errs() <<
"Writing '" << P <<
"'.\n";
800 auto Stream = llvm::make_unique<llvm::raw_fd_ostream>(FD,
true);
802 return llvm::make_unique<UbigraphViz>(std::move(Stream),
P);
807 assert (Src != Dst &&
"Self-edges are not allowed.");
810 VMap::iterator SrcI= M.find(Src);
813 if (SrcI == M.end()) {
814 M[Src] = SrcID = Cntr++;
815 *Out <<
"('vertex', " << SrcID <<
", ('color','#00ff00'))\n";
818 SrcID = SrcI->second;
821 VMap::iterator DstI= M.find(Dst);
824 if (DstI == M.end()) {
825 M[Dst] = DstID = Cntr++;
826 *Out <<
"('vertex', " << DstID <<
")\n";
830 DstID = DstI->second;
831 *Out <<
"('change_vertex_style', " << DstID <<
", 1)\n";
835 *Out <<
"('edge', " << SrcID <<
", " << DstID
836 <<
", ('arrow','true'), ('oriented', 'true'))\n";
839 UbigraphViz::UbigraphViz(std::unique_ptr<raw_ostream> OutStream,
841 : Out(std::move(OutStream)),
Filename(Filename), Cntr(0) {
843 *Out <<
"('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
844 *Out <<
"('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66')," 845 " ('size', '1.5'))\n";
848 UbigraphViz::~UbigraphViz() {
850 llvm::errs() <<
"Running 'ubiviz' program... ";
853 if (
auto Path = llvm::sys::findProgramByName(
"ubiviz"))
855 const char *args[] = {Ubiviz.c_str(), Filename.c_str(),
nullptr};
857 if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0],
nullptr, {}, 0, 0, &ErrMsg)) {
858 llvm::errs() <<
"Error viewing graph: " << ErrMsg <<
"\n";
862 llvm::sys::fs::remove(Filename);
The AST-based call graph.
std::string OutputFile
The output file, if any.
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.
bool isThisDeclarationADefinition() const
Returns whether this specific method is a definition.
bool hasErrorOccurred() const
A (possibly-)qualified type.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Stmt - This represents one statement.
unsigned size() const
size - Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlo...
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
ObjCMethodDecl - Represents an instance or class method declaration.
Describes how types, statements, expressions, and declarations should be printed. ...
PathDiagnosticLocation getLocation() const
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
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::unique_ptr< StoreManager >(* StoreManagerCreator)(ProgramStateManager &)
std::deque< Decl * > SetOfDecls
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
const LangOptions & getLangOpts() const
ArrayRef< ParmVarDecl * > parameters() const
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
FrontendOptions & getFrontendOpts()
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
Concrete class used by the front-end to report problems and issues.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
AnalyzerOptionsRef getAnalyzerOpts()
param_iterator param_begin()
std::unique_ptr< ConstraintManager >(* ConstraintManagerCreator)(ProgramStateManager &, SubEngine *)
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.
CFG - Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
unsigned getLine() const
Return the presumed line number of this location.
bool isThisDeclarationADefinition() const
Returns whether this specific declaration of the function is also a definition that does not contain ...
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.
This file defines the clang::ento::ModelInjector class which implements the clang::CodeInjector inter...
void FlushReports()
Generate and flush diagnostics for all bug reports.
Represents an unpacked "presumed" location which can be presented to the user.
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
PathPieces flatten(bool ShouldFlattenMacros) const
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
const char * getFilename() const
Return the presumed filename of this location.
BugReporter is a utility class for generating PathDiagnostics for analysis.
unsigned getColumn() const
Return the presumed column number of this location.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Encodes a location in the source.
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.")
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
unsigned getTotalNumBasicBlocks()
FullSourceLoc asLocation() const
BugReporter & getBugReporter()
Do minimal inlining of callees.
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
StringRef getName() const
Return the actual identifier string.
bool ExecuteWorkList(const LocationContext *L, unsigned Steps=150000)
Returns true if there is still simulation state on the worklist.
Dataflow Directional Tag Classes.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
CodeInjector is an interface which is responsible for injecting AST of function definitions that may ...
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.
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)
bool hasFatalErrorOccurred() const
Preprocessor & getPreprocessor() const
Return the current preprocessor.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
TranslationUnitDecl * getTranslationUnitDecl() const
DiagnosticsEngine & getDiagnostics() const
void addToCallGraph(Decl *D)
Populate the call graph with the functions in the given declaration.
std::string getQualifiedNameAsString() const
TranslationUnitDecl - The top declaration context.
unsigned getTotalNumVisitedBasicBlocks()
void ViewGraph(bool trim=false)
Visualize the ExplodedGraph created by executing the simulation.
SourceLocation getLocStart() const LLVM_READONLY
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.
SourceLocation getLocation() const
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
StringRef getShortDescription() const