37 #include "llvm/ADT/PostOrderIterator.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" 48 using namespace clang;
51 #define DEBUG_TYPE "AnalysisConsumer" 53 STATISTIC(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.");
59 STATISTIC(NumVisitedBlocksInAnalyzedFunctions,
60 "The # of visited basic blocks in the analyzed functions.");
61 STATISTIC(PercentReachableBlocks,
"The % of reachable basic blocks.");
62 STATISTIC(MaxCFGSize,
"The maximum number of basic blocks in a function.");
68 void ento::createPlistHTMLDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
70 const std::string &prefix,
72 createHTMLDiagnosticConsumer(AnalyzerOpts, C,
73 llvm::sys::path::parent_path(prefix), PP);
74 createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP);
77 void ento::createTextPathDiagnosticConsumer(
AnalyzerOptions &AnalyzerOpts,
79 const std::string &Prefix,
81 llvm_unreachable(
"'text' consumer should be enabled on ClangDiags");
85 class ClangDiagPathDiagConsumer :
public PathDiagnosticConsumer {
90 : Diag(Diag), IncludePath(
false) {}
91 ~ClangDiagPathDiagConsumer()
override {}
92 StringRef
getName()
const override {
return "ClangDiags"; }
94 bool supportsLogicalOpControlFlow()
const override {
return true; }
95 bool supportsCrossFileDiagnostics()
const override {
return true; }
97 PathGenerationScheme getGenerationScheme()
const override {
98 return IncludePath ?
Minimal : None;
105 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
106 FilesMade *filesMade)
override {
110 for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(),
111 E = Diags.end(); I != E; ++I) {
112 const PathDiagnostic *PD = *I;
114 Diag.
Report(WarnLoc, WarnID) << PD->getShortDescription()
115 << PD->path.back()->getRanges();
118 for (
const auto &Piece : PD->path) {
119 if (!isa<PathDiagnosticNotePiece>(Piece.get()))
123 Diag.
Report(NoteLoc, NoteID) << Piece->getString()
124 << Piece->getRanges();
131 PathPieces FlatPath = PD->path.flatten(
true);
132 for (
const auto &Piece : FlatPath) {
133 if (isa<PathDiagnosticNotePiece>(Piece.get()))
137 Diag.
Report(NoteLoc, NoteID) << Piece->getString()
138 << Piece->getRanges();
151 class AnalysisConsumer :
public AnalysisASTConsumer,
158 typedef unsigned AnalysisMode;
161 AnalysisMode RecVisitorMode;
163 BugReporter *RecVisitorBR;
165 std::vector<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns;
170 const std::string OutDir;
189 std::unique_ptr<CheckerManager> checkerMgr;
190 std::unique_ptr<AnalysisManager> Mgr;
193 std::unique_ptr<llvm::TimerGroup> AnalyzerTimers;
194 std::unique_ptr<llvm::Timer> TUTotalTimer;
198 FunctionSummariesTy FunctionSummaries;
203 : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),
204 PP(CI.getPreprocessor()), OutDir(outdir), Opts(
std::move(opts)),
205 Plugins(plugins), Injector(injector), CTU(CI) {
206 DigestAnalyzerOptions();
207 if (Opts->PrintStats || Opts->ShouldSerializeStats) {
208 AnalyzerTimers = llvm::make_unique<llvm::TimerGroup>(
209 "analyzer",
"Analyzer timers");
210 TUTotalTimer = llvm::make_unique<llvm::Timer>(
211 "time",
"Analyzer total time", *AnalyzerTimers);
212 llvm::EnableStatistics(
false);
216 ~AnalysisConsumer()
override {
217 if (Opts->PrintStats) {
218 llvm::PrintStatistics();
222 void DigestAnalyzerOptions() {
223 if (Opts->AnalysisDiagOpt !=
PD_NONE) {
225 ClangDiagPathDiagConsumer *clangDiags =
227 PathConsumers.push_back(clangDiags);
229 if (Opts->AnalysisDiagOpt == PD_TEXT) {
230 clangDiags->enablePaths();
232 }
else if (!OutDir.empty()) {
233 switch (Opts->AnalysisDiagOpt) {
235 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ 237 CREATEFN(*Opts.get(), PathConsumers, OutDir, PP); \ 239 #include "clang/StaticAnalyzer/Core/Analyses.def" 245 switch (Opts->AnalysisStoreOpt) {
247 llvm_unreachable(
"Unknown store manager.");
248 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ 249 case NAME##Model: CreateStoreMgr = CREATEFN; break; 250 #include "clang/StaticAnalyzer/Core/Analyses.def" 253 switch (Opts->AnalysisConstraintsOpt) {
255 llvm_unreachable(
"Unknown constraint manager.");
256 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ 257 case NAME##Model: CreateConstraintMgr = CREATEFN; break; 258 #include "clang/StaticAnalyzer/Core/Analyses.def" 262 void DisplayFunction(
const Decl *D, AnalysisMode Mode,
264 if (!Opts->AnalyzerDisplayProgress)
270 llvm::errs() <<
"ANALYZE";
272 if (Mode == AM_Syntax)
273 llvm::errs() <<
" (Syntax)";
274 else if (Mode == AM_Path) {
275 llvm::errs() <<
" (Path, ";
278 llvm::errs() <<
" Inline_Minimal";
281 llvm::errs() <<
" Inline_Regular";
287 assert(Mode == (AM_Syntax | AM_Path) &&
"Unexpected mode!");
290 << getFunctionName(D) <<
'\n';
294 void Initialize(
ASTContext &Context)
override {
297 *Ctx, *Opts, Plugins, CheckerRegistrationFns, PP.
getDiagnostics());
299 Mgr = llvm::make_unique<AnalysisManager>(
301 CreateConstraintMgr, checkerMgr.get(), *Opts, Injector);
307 void HandleTopLevelDeclInObjCContainer(
DeclGroupRef D)
override;
309 void HandleTranslationUnit(
ASTContext &C)
override;
319 void HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize);
327 void HandleCode(
Decl *D, AnalysisMode Mode,
331 void RunPathSensitiveChecks(
Decl *D,
336 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
339 bool VisitDecl(
Decl *D) {
340 AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
341 if (Mode & AM_Syntax)
342 checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
348 if (II && II->
getName().startswith(
"__inline"))
355 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
356 HandleCode(FD, RecVisitorMode);
363 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
364 HandleCode(MD, RecVisitorMode);
371 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() ==
false);
375 HandleCode(BD, RecVisitorMode);
381 void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer)
override {
382 PathConsumers.push_back(Consumer);
385 void AddCheckerRegistrationFn(std::function<
void(CheckerRegistry&)> Fn)
override {
386 CheckerRegistrationFns.push_back(std::move(Fn));
391 std::string getFunctionName(
const Decl *D);
394 AnalysisMode getModeForDecl(
Decl *D, AnalysisMode Mode);
395 void runAnalysisOnTranslationUnit(
ASTContext &C);
398 void reportAnalyzerProgress(StringRef S);
406 bool AnalysisConsumer::HandleTopLevelDecl(
DeclGroupRef DG) {
407 storeTopLevelDecls(DG);
411 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(
DeclGroupRef DG) {
412 storeTopLevelDecls(DG);
415 void AnalysisConsumer::storeTopLevelDecls(
DeclGroupRef DG) {
420 if (isa<ObjCMethodDecl>(*I))
423 LocalTUDecls.push_back(*I);
430 if (VisitedAsTopLevel.count(D))
440 if (isa<ObjCMethodDecl>(D))
445 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
446 if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())
451 return Visited.count(D);
455 AnalysisConsumer::getInliningModeForFunction(
const Decl *D,
460 if (Visited.count(D) && isa<ObjCMethodDecl>(D)) {
469 void AnalysisConsumer::HandleDeclsCallGraph(
const unsigned LocalTUDeclsSize) {
475 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
487 llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
488 for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator
489 I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
490 NumFunctionTopLevel++;
507 HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
508 (Mgr->options.InliningMode == All ?
nullptr : &VisitedCallees));
511 for (
const Decl *Callee : VisitedCallees)
514 Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
515 : Callee->getCanonicalDecl());
516 VisitedAsTopLevel.insert(D);
523 StringRef Buffer = SM.
getBuffer(FID)->getBuffer();
524 if (Buffer.startswith(
"/* A Bison parser, made by"))
529 void AnalysisConsumer::runAnalysisOnTranslationUnit(
ASTContext &C) {
530 BugReporter BR(*Mgr);
532 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
537 RecVisitorMode = AM_Syntax;
538 if (!Mgr->shouldInlineCall())
539 RecVisitorMode |= AM_Path;
548 const unsigned LocalTUDeclsSize = LocalTUDecls.size();
549 for (
unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
550 TraverseDecl(LocalTUDecls[i]);
553 if (Mgr->shouldInlineCall())
554 HandleDeclsCallGraph(LocalTUDeclsSize);
557 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
559 RecVisitorBR =
nullptr;
562 void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {
563 if (Opts->AnalyzerDisplayProgress)
567 void AnalysisConsumer::HandleTranslationUnit(
ASTContext &C) {
574 if (TUTotalTimer) TUTotalTimer->startTimer();
577 reportAnalyzerProgress(
"Skipping bison-generated file\n");
578 }
else if (Opts->DisableAllChecks) {
582 reportAnalyzerProgress(
"All checks are disabled using a supplied option\n");
585 runAnalysisOnTranslationUnit(C);
588 if (TUTotalTimer) TUTotalTimer->stopTimer();
591 NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
592 NumVisitedBlocksInAnalyzedFunctions =
593 FunctionSummaries.getTotalNumVisitedBasicBlocks();
594 if (NumBlocksInAnalyzedFunctions > 0)
595 PercentReachableBlocks =
596 (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
597 NumBlocksInAnalyzedFunctions;
606 std::string AnalysisConsumer::getFunctionName(
const Decl *D) {
608 llvm::raw_string_ostream
OS(Str);
610 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
614 if (Ctx->getLangOpts().CPlusPlus) {
619 OS <<
P->getType().getAsString();
624 }
else if (isa<BlockDecl>(D)) {
632 }
else if (
const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
635 OS << (OMD->isInstanceMethod() ?
'-' :
'+') <<
'[';
637 if (
const auto *OID = dyn_cast<ObjCImplementationDecl>(DC)) {
638 OS << OID->getName();
639 }
else if (
const auto *OID = dyn_cast<ObjCInterfaceDecl>(DC)) {
640 OS << OID->getName();
641 }
else if (
const auto *OC = dyn_cast<ObjCCategoryDecl>(DC)) {
642 if (OC->IsClassExtension()) {
643 OS << OC->getClassInterface()->getName();
645 OS << OC->getIdentifier()->getNameStart() <<
'(' 646 << OC->getIdentifier()->getNameStart() <<
')';
648 }
else if (
const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
649 OS << OCD->getClassInterface()->getName() <<
'(' 650 << OCD->getName() <<
')';
651 }
else if (isa<ObjCProtocolDecl>(DC)) {
655 cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
659 OS <<
' ' << OMD->getSelector().getAsString() <<
']';
666 AnalysisConsumer::AnalysisMode
667 AnalysisConsumer::getModeForDecl(
Decl *D, AnalysisMode Mode) {
668 if (!Opts->AnalyzeSpecificFunction.empty() &&
669 getFunctionName(D) != Opts->AnalyzeSpecificFunction)
682 if (!Opts->AnalyzeAll && !Mgr->isInCodeFile(SL)) {
685 return Mode & ~AM_Path;
691 void AnalysisConsumer::HandleCode(
Decl *D, AnalysisMode Mode,
696 Mode = getModeForDecl(D, Mode);
701 Mgr->ClearContexts();
703 if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized())
706 DisplayFunction(D, Mode, IMode);
707 CFG *DeclCFG = Mgr->getCFG(D);
709 MaxCFGSize.updateMax(DeclCFG->
size());
711 BugReporter BR(*Mgr);
713 if (Mode & AM_Syntax)
714 checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
715 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
716 RunPathSensitiveChecks(D, IMode, VisitedCallees);
718 NumFunctionsAnalyzed++;
726 void AnalysisConsumer::RunPathSensitiveChecks(
Decl *D,
738 ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
741 Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
742 Mgr->options.MaxNodesPerTopLevelFunction);
744 if (!Mgr->options.DumpExplodedGraphTo.empty())
745 Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo);
748 if (Mgr->options.visualizeExplodedGraphWithGraphViz)
749 Eng.ViewGraph(Mgr->options.TrimGraph);
752 Eng.getBugReporter().FlushReports();
759 std::unique_ptr<AnalysisASTConsumer>
765 bool hasModelPath = analyzerOpts->Config.count(
"model-path") > 0;
767 return llvm::make_unique<AnalysisConsumer>(
769 CI.getFrontendOpts().Plugins,
The AST-based call graph.
std::string OutputFile
The output file, if any.
Represents 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.
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
Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...
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.
std::unique_ptr< CheckerManager > createCheckerManager(ASTContext &context, AnalyzerOptions &opts, ArrayRef< std::string > plugins, ArrayRef< std::function< void(CheckerRegistry &)>> checkerRegistrationFns, DiagnosticsEngine &diags)
ObjCMethodDecl - Represents an instance or class method declaration.
Describes how types, statements, expressions, and declarations should be printed. ...
std::string getName(ArrayRef< StringRef > Parts) const
Get the platform-specific name separator.
IdentifierInfo * getIdentifier() const
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...
SourceLocation getBeginLoc() const LLVM_READONLY
std::unique_ptr< StoreManager >(* StoreManagerCreator)(ProgramStateManager &)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
ArrayRef< ParmVarDecl * > parameters() const
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
FrontendOptions & getFrontendOpts()
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
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()
llvm::DenseSet< const Decl * > SetOfConstDecls
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.
Pepresents 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...
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.
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.
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
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.
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
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
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.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
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 ...
FileID getMainFileID() const
Returns the FileID of the main source file.
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.
This class is used for tools that requires cross translation unit capability.
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.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
Stores options for the analyzer from the command line.
SourceManager & getSourceManager()
bool hasFatalErrorOccurred() const
Preprocessor & getPreprocessor() const
Return the current preprocessor.
static bool isBisonFile(ASTContext &C)
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
The top declaration context.
std::deque< Decl * > SetOfDecls
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.