Path: blob/main/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
35266 views
//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// "Meta" ASTConsumer for running different source analyses.9//10//===----------------------------------------------------------------------===//1112#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"13#include "ModelInjector.h"14#include "clang/AST/Decl.h"15#include "clang/AST/DeclCXX.h"16#include "clang/AST/DeclObjC.h"17#include "clang/AST/RecursiveASTVisitor.h"18#include "clang/Analysis/Analyses/LiveVariables.h"19#include "clang/Analysis/CFG.h"20#include "clang/Analysis/CallGraph.h"21#include "clang/Analysis/CodeInjector.h"22#include "clang/Analysis/MacroExpansionContext.h"23#include "clang/Analysis/PathDiagnostic.h"24#include "clang/Basic/SourceManager.h"25#include "clang/CrossTU/CrossTranslationUnit.h"26#include "clang/Frontend/CompilerInstance.h"27#include "clang/Lex/Preprocessor.h"28#include "clang/Rewrite/Core/Rewriter.h"29#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"30#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"31#include "clang/StaticAnalyzer/Core/CheckerManager.h"32#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"33#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"34#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"35#include "llvm/ADT/PostOrderIterator.h"36#include "llvm/ADT/ScopeExit.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"43#include <memory>44#include <queue>45#include <utility>4647using namespace clang;48using namespace ento;4950#define DEBUG_TYPE "AnalysisConsumer"5152STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");53STATISTIC(NumFunctionsAnalyzed,54"The # of functions and blocks analyzed (as top level "55"with inlining turned on).");56STATISTIC(NumBlocksInAnalyzedFunctions,57"The # of basic blocks in the analyzed functions.");58STATISTIC(NumVisitedBlocksInAnalyzedFunctions,59"The # of visited basic blocks in the analyzed functions.");60STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");61STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");6263//===----------------------------------------------------------------------===//64// AnalysisConsumer declaration.65//===----------------------------------------------------------------------===//6667namespace {6869class AnalysisConsumer : public AnalysisASTConsumer,70public RecursiveASTVisitor<AnalysisConsumer> {71enum {72AM_None = 0,73AM_Syntax = 0x1,74AM_Path = 0x275};76typedef unsigned AnalysisMode;7778/// Mode of the analyzes while recursively visiting Decls.79AnalysisMode RecVisitorMode;80/// Bug Reporter to use while recursively visiting Decls.81BugReporter *RecVisitorBR;8283std::vector<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns;8485public:86ASTContext *Ctx;87Preprocessor &PP;88const std::string OutDir;89AnalyzerOptions &Opts;90ArrayRef<std::string> Plugins;91CodeInjector *Injector;92cross_tu::CrossTranslationUnitContext CTU;9394/// Stores the declarations from the local translation unit.95/// Note, we pre-compute the local declarations at parse time as an96/// optimization to make sure we do not deserialize everything from disk.97/// The local declaration to all declarations ratio might be very small when98/// working with a PCH file.99SetOfDecls LocalTUDecls;100101MacroExpansionContext MacroExpansions;102103// Set of PathDiagnosticConsumers. Owned by AnalysisManager.104PathDiagnosticConsumers PathConsumers;105106StoreManagerCreator CreateStoreMgr;107ConstraintManagerCreator CreateConstraintMgr;108109std::unique_ptr<CheckerManager> checkerMgr;110std::unique_ptr<AnalysisManager> Mgr;111112/// Time the analyzes time of each translation unit.113std::unique_ptr<llvm::TimerGroup> AnalyzerTimers;114std::unique_ptr<llvm::Timer> SyntaxCheckTimer;115std::unique_ptr<llvm::Timer> ExprEngineTimer;116std::unique_ptr<llvm::Timer> BugReporterTimer;117118/// The information about analyzed functions shared throughout the119/// translation unit.120FunctionSummariesTy FunctionSummaries;121122AnalysisConsumer(CompilerInstance &CI, const std::string &outdir,123AnalyzerOptions &opts, ArrayRef<std::string> plugins,124CodeInjector *injector)125: RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),126PP(CI.getPreprocessor()), OutDir(outdir), Opts(opts),127Plugins(plugins), Injector(injector), CTU(CI),128MacroExpansions(CI.getLangOpts()) {129DigestAnalyzerOptions();130if (Opts.AnalyzerDisplayProgress || Opts.PrintStats ||131Opts.ShouldSerializeStats) {132AnalyzerTimers = std::make_unique<llvm::TimerGroup>(133"analyzer", "Analyzer timers");134SyntaxCheckTimer = std::make_unique<llvm::Timer>(135"syntaxchecks", "Syntax-based analysis time", *AnalyzerTimers);136ExprEngineTimer = std::make_unique<llvm::Timer>(137"exprengine", "Path exploration time", *AnalyzerTimers);138BugReporterTimer = std::make_unique<llvm::Timer>(139"bugreporter", "Path-sensitive report post-processing time",140*AnalyzerTimers);141}142143if (Opts.PrintStats || Opts.ShouldSerializeStats) {144llvm::EnableStatistics(/* DoPrintOnExit= */ false);145}146147if (Opts.ShouldDisplayMacroExpansions)148MacroExpansions.registerForPreprocessor(PP);149}150151~AnalysisConsumer() override {152if (Opts.PrintStats) {153llvm::PrintStatistics();154}155}156157void DigestAnalyzerOptions() {158switch (Opts.AnalysisDiagOpt) {159case PD_NONE:160break;161#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \162case PD_##NAME: \163CREATEFN(Opts.getDiagOpts(), PathConsumers, OutDir, PP, CTU, \164MacroExpansions); \165break;166#include "clang/StaticAnalyzer/Core/Analyses.def"167default:168llvm_unreachable("Unknown analyzer output type!");169}170171// Create the analyzer component creators.172CreateStoreMgr = &CreateRegionStoreManager;173174switch (Opts.AnalysisConstraintsOpt) {175default:176llvm_unreachable("Unknown constraint manager.");177#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \178case NAME##Model: CreateConstraintMgr = CREATEFN; break;179#include "clang/StaticAnalyzer/Core/Analyses.def"180}181}182183void DisplayTime(llvm::TimeRecord &Time) {184if (!Opts.AnalyzerDisplayProgress) {185return;186}187llvm::errs() << " : " << llvm::format("%1.1f", Time.getWallTime() * 1000)188<< " ms\n";189}190191void DisplayFunction(const Decl *D, AnalysisMode Mode,192ExprEngine::InliningModes IMode) {193if (!Opts.AnalyzerDisplayProgress)194return;195196SourceManager &SM = Mgr->getASTContext().getSourceManager();197PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());198if (Loc.isValid()) {199llvm::errs() << "ANALYZE";200201if (Mode == AM_Syntax)202llvm::errs() << " (Syntax)";203else if (Mode == AM_Path) {204llvm::errs() << " (Path, ";205switch (IMode) {206case ExprEngine::Inline_Minimal:207llvm::errs() << " Inline_Minimal";208break;209case ExprEngine::Inline_Regular:210llvm::errs() << " Inline_Regular";211break;212}213llvm::errs() << ")";214} else215assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");216217llvm::errs() << ": " << Loc.getFilename() << ' '218<< AnalysisDeclContext::getFunctionName(D);219}220}221222void Initialize(ASTContext &Context) override {223Ctx = &Context;224checkerMgr = std::make_unique<CheckerManager>(*Ctx, Opts, PP, Plugins,225CheckerRegistrationFns);226227Mgr = std::make_unique<AnalysisManager>(*Ctx, PP, PathConsumers,228CreateStoreMgr, CreateConstraintMgr,229checkerMgr.get(), Opts, Injector);230}231232/// Store the top level decls in the set to be processed later on.233/// (Doing this pre-processing avoids deserialization of data from PCH.)234bool HandleTopLevelDecl(DeclGroupRef D) override;235void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;236237void HandleTranslationUnit(ASTContext &C) override;238239/// Determine which inlining mode should be used when this function is240/// analyzed. This allows to redefine the default inlining policies when241/// analyzing a given function.242ExprEngine::InliningModes243getInliningModeForFunction(const Decl *D, const SetOfConstDecls &Visited);244245/// Build the call graph for all the top level decls of this TU and246/// use it to define the order in which the functions should be visited.247void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);248249/// Run analyzes(syntax or path sensitive) on the given function.250/// \param Mode - determines if we are requesting syntax only or path251/// sensitive only analysis.252/// \param VisitedCallees - The output parameter, which is populated with the253/// set of functions which should be considered analyzed after analyzing the254/// given root function.255void HandleCode(Decl *D, AnalysisMode Mode,256ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal,257SetOfConstDecls *VisitedCallees = nullptr);258259void RunPathSensitiveChecks(Decl *D,260ExprEngine::InliningModes IMode,261SetOfConstDecls *VisitedCallees);262263/// Visitors for the RecursiveASTVisitor.264bool shouldWalkTypesOfTypeLocs() const { return false; }265266/// Handle callbacks for arbitrary Decls.267bool VisitDecl(Decl *D) {268AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);269if (Mode & AM_Syntax) {270if (SyntaxCheckTimer)271SyntaxCheckTimer->startTimer();272checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);273if (SyntaxCheckTimer)274SyntaxCheckTimer->stopTimer();275}276return true;277}278279bool VisitVarDecl(VarDecl *VD) {280if (!Opts.IsNaiveCTUEnabled)281return true;282283if (VD->hasExternalStorage() || VD->isStaticDataMember()) {284if (!cross_tu::shouldImport(VD, *Ctx))285return true;286} else {287// Cannot be initialized in another TU.288return true;289}290291if (VD->getAnyInitializer())292return true;293294llvm::Expected<const VarDecl *> CTUDeclOrError =295CTU.getCrossTUDefinition(VD, Opts.CTUDir, Opts.CTUIndexName,296Opts.DisplayCTUProgress);297298if (!CTUDeclOrError) {299handleAllErrors(CTUDeclOrError.takeError(),300[&](const cross_tu::IndexError &IE) {301CTU.emitCrossTUDiagnostics(IE);302});303}304305return true;306}307308bool VisitFunctionDecl(FunctionDecl *FD) {309IdentifierInfo *II = FD->getIdentifier();310if (II && II->getName().starts_with("__inline"))311return true;312313// We skip function template definitions, as their semantics is314// only determined when they are instantiated.315if (FD->isThisDeclarationADefinition() &&316!FD->isDependentContext()) {317assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);318HandleCode(FD, RecVisitorMode);319}320return true;321}322323bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {324if (MD->isThisDeclarationADefinition()) {325assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);326HandleCode(MD, RecVisitorMode);327}328return true;329}330331bool VisitBlockDecl(BlockDecl *BD) {332if (BD->hasBody()) {333assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);334// Since we skip function template definitions, we should skip blocks335// declared in those functions as well.336if (!BD->isDependentContext()) {337HandleCode(BD, RecVisitorMode);338}339}340return true;341}342343void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) override {344PathConsumers.push_back(Consumer);345}346347void AddCheckerRegistrationFn(std::function<void(CheckerRegistry&)> Fn) override {348CheckerRegistrationFns.push_back(std::move(Fn));349}350351private:352void storeTopLevelDecls(DeclGroupRef DG);353354/// Check if we should skip (not analyze) the given function.355AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);356void runAnalysisOnTranslationUnit(ASTContext &C);357358/// Print \p S to stderr if \c Opts.AnalyzerDisplayProgress is set.359void reportAnalyzerProgress(StringRef S);360}; // namespace361} // end anonymous namespace362363364//===----------------------------------------------------------------------===//365// AnalysisConsumer implementation.366//===----------------------------------------------------------------------===//367bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {368storeTopLevelDecls(DG);369return true;370}371372void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {373storeTopLevelDecls(DG);374}375376void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {377for (auto &I : DG) {378379// Skip ObjCMethodDecl, wait for the objc container to avoid380// analyzing twice.381if (isa<ObjCMethodDecl>(I))382continue;383384LocalTUDecls.push_back(I);385}386}387388static bool shouldSkipFunction(const Decl *D,389const SetOfConstDecls &Visited,390const SetOfConstDecls &VisitedAsTopLevel) {391if (VisitedAsTopLevel.count(D))392return true;393394// Skip analysis of inheriting constructors as top-level functions. These395// constructors don't even have a body written down in the code, so even if396// we find a bug, we won't be able to display it.397if (const auto *CD = dyn_cast<CXXConstructorDecl>(D))398if (CD->isInheritingConstructor())399return true;400401// We want to re-analyse the functions as top level in the following cases:402// - The 'init' methods should be reanalyzed because403// ObjCNonNilReturnValueChecker assumes that '[super init]' never returns404// 'nil' and unless we analyze the 'init' functions as top level, we will405// not catch errors within defensive code.406// - We want to reanalyze all ObjC methods as top level to report Retain407// Count naming convention errors more aggressively.408if (isa<ObjCMethodDecl>(D))409return false;410// We also want to reanalyze all C++ copy and move assignment operators to411// separately check the two cases where 'this' aliases with the parameter and412// where it may not. (cplusplus.SelfAssignmentChecker)413if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {414if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())415return false;416}417418// Otherwise, if we visited the function before, do not reanalyze it.419return Visited.count(D);420}421422ExprEngine::InliningModes423AnalysisConsumer::getInliningModeForFunction(const Decl *D,424const SetOfConstDecls &Visited) {425// We want to reanalyze all ObjC methods as top level to report Retain426// Count naming convention errors more aggressively. But we should tune down427// inlining when reanalyzing an already inlined function.428if (Visited.count(D) && isa<ObjCMethodDecl>(D)) {429const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D);430if (ObjCM->getMethodFamily() != OMF_init)431return ExprEngine::Inline_Minimal;432}433434return ExprEngine::Inline_Regular;435}436437void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {438// Build the Call Graph by adding all the top level declarations to the graph.439// Note: CallGraph can trigger deserialization of more items from a pch440// (though HandleInterestingDecl); triggering additions to LocalTUDecls.441// We rely on random access to add the initially processed Decls to CG.442CallGraph CG;443for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {444CG.addToCallGraph(LocalTUDecls[i]);445}446447// Walk over all of the call graph nodes in topological order, so that we448// analyze parents before the children. Skip the functions inlined into449// the previously processed functions. Use external Visited set to identify450// inlined functions. The topological order allows the "do not reanalyze451// previously inlined function" performance heuristic to be triggered more452// often.453SetOfConstDecls Visited;454SetOfConstDecls VisitedAsTopLevel;455llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);456for (auto &N : RPOT) {457NumFunctionTopLevel++;458459Decl *D = N->getDecl();460461// Skip the abstract root node.462if (!D)463continue;464465// Skip the functions which have been processed already or previously466// inlined.467if (shouldSkipFunction(D, Visited, VisitedAsTopLevel))468continue;469470// The CallGraph might have declarations as callees. However, during CTU471// the declaration might form a declaration chain with the newly imported472// definition from another TU. In this case we don't want to analyze the473// function definition as toplevel.474if (const auto *FD = dyn_cast<FunctionDecl>(D)) {475// Calling 'hasBody' replaces 'FD' in place with the FunctionDecl476// that has the body.477FD->hasBody(FD);478if (CTU.isImportedAsNew(FD))479continue;480}481482// Analyze the function.483SetOfConstDecls VisitedCallees;484485HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),486(Mgr->options.InliningMode == All ? nullptr : &VisitedCallees));487488// Add the visited callees to the global visited set.489for (const Decl *Callee : VisitedCallees)490// Decls from CallGraph are already canonical. But Decls coming from491// CallExprs may be not. We should canonicalize them manually.492Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee493: Callee->getCanonicalDecl());494VisitedAsTopLevel.insert(D);495}496}497498static bool fileContainsString(StringRef Substring, ASTContext &C) {499const SourceManager &SM = C.getSourceManager();500FileID FID = SM.getMainFileID();501StringRef Buffer = SM.getBufferOrFake(FID).getBuffer();502return Buffer.contains(Substring);503}504505static void reportAnalyzerFunctionMisuse(const AnalyzerOptions &Opts,506const ASTContext &Ctx) {507llvm::errs() << "Every top-level function was skipped.\n";508509if (!Opts.AnalyzerDisplayProgress)510llvm::errs() << "Pass the -analyzer-display-progress for tracking which "511"functions are analyzed.\n";512513bool HasBrackets =514Opts.AnalyzeSpecificFunction.find("(") != std::string::npos;515516if (Ctx.getLangOpts().CPlusPlus && !HasBrackets) {517llvm::errs()518<< "For analyzing C++ code you need to pass the function parameter "519"list: -analyze-function=\"foobar(int, _Bool)\"\n";520} else if (!Ctx.getLangOpts().CPlusPlus && HasBrackets) {521llvm::errs() << "For analyzing C code you shouldn't pass the function "522"parameter list, only the name of the function: "523"-analyze-function=foobar\n";524}525}526527void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) {528BugReporter BR(*Mgr);529const TranslationUnitDecl *TU = C.getTranslationUnitDecl();530BR.setAnalysisEntryPoint(TU);531if (SyntaxCheckTimer)532SyntaxCheckTimer->startTimer();533checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);534if (SyntaxCheckTimer)535SyntaxCheckTimer->stopTimer();536537// Run the AST-only checks using the order in which functions are defined.538// If inlining is not turned on, use the simplest function order for path539// sensitive analyzes as well.540RecVisitorMode = AM_Syntax;541if (!Mgr->shouldInlineCall())542RecVisitorMode |= AM_Path;543RecVisitorBR = &BR;544545// Process all the top level declarations.546//547// Note: TraverseDecl may modify LocalTUDecls, but only by appending more548// entries. Thus we don't use an iterator, but rely on LocalTUDecls549// random access. By doing so, we automatically compensate for iterators550// possibly being invalidated, although this is a bit slower.551const unsigned LocalTUDeclsSize = LocalTUDecls.size();552for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {553TraverseDecl(LocalTUDecls[i]);554}555556if (Mgr->shouldInlineCall())557HandleDeclsCallGraph(LocalTUDeclsSize);558559// After all decls handled, run checkers on the entire TranslationUnit.560checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);561562BR.FlushReports();563RecVisitorBR = nullptr;564565// If the user wanted to analyze a specific function and the number of basic566// blocks analyzed is zero, than the user might not specified the function567// name correctly.568// FIXME: The user might have analyzed the requested function in Syntax mode,569// but we are unaware of that.570if (!Opts.AnalyzeSpecificFunction.empty() && NumFunctionsAnalyzed == 0)571reportAnalyzerFunctionMisuse(Opts, *Ctx);572}573574void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {575if (Opts.AnalyzerDisplayProgress)576llvm::errs() << S;577}578579void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {580// Don't run the actions if an error has occurred with parsing the file.581DiagnosticsEngine &Diags = PP.getDiagnostics();582if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())583return;584585// Explicitly destroy the PathDiagnosticConsumer. This will flush its output.586// FIXME: This should be replaced with something that doesn't rely on587// side-effects in PathDiagnosticConsumer's destructor. This is required when588// used with option -disable-free.589const auto DiagFlusherScopeExit =590llvm::make_scope_exit([this] { Mgr.reset(); });591592if (Opts.ShouldIgnoreBisonGeneratedFiles &&593fileContainsString("/* A Bison parser, made by", C)) {594reportAnalyzerProgress("Skipping bison-generated file\n");595return;596}597598if (Opts.ShouldIgnoreFlexGeneratedFiles &&599fileContainsString("/* A lexical scanner generated by flex", C)) {600reportAnalyzerProgress("Skipping flex-generated file\n");601return;602}603604// Don't analyze if the user explicitly asked for no checks to be performed605// on this file.606if (Opts.DisableAllCheckers) {607reportAnalyzerProgress("All checks are disabled using a supplied option\n");608return;609}610611// Otherwise, just run the analysis.612runAnalysisOnTranslationUnit(C);613614// Count how many basic blocks we have not covered.615NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();616NumVisitedBlocksInAnalyzedFunctions =617FunctionSummaries.getTotalNumVisitedBasicBlocks();618if (NumBlocksInAnalyzedFunctions > 0)619PercentReachableBlocks =620(FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /621NumBlocksInAnalyzedFunctions;622}623624AnalysisConsumer::AnalysisMode625AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {626if (!Opts.AnalyzeSpecificFunction.empty() &&627AnalysisDeclContext::getFunctionName(D) != Opts.AnalyzeSpecificFunction)628return AM_None;629630// Unless -analyze-all is specified, treat decls differently depending on631// where they came from:632// - Main source file: run both path-sensitive and non-path-sensitive checks.633// - Header files: run non-path-sensitive checks only.634// - System headers: don't run any checks.635if (Opts.AnalyzeAll)636return Mode;637638const SourceManager &SM = Ctx->getSourceManager();639640const SourceLocation Loc = [&SM](Decl *D) -> SourceLocation {641const Stmt *Body = D->getBody();642SourceLocation SL = Body ? Body->getBeginLoc() : D->getLocation();643return SM.getExpansionLoc(SL);644}(D);645646// Ignore system headers.647if (Loc.isInvalid() || SM.isInSystemHeader(Loc))648return AM_None;649650// Disable path sensitive analysis in user-headers.651if (!Mgr->isInCodeFile(Loc))652return Mode & ~AM_Path;653654return Mode;655}656657void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,658ExprEngine::InliningModes IMode,659SetOfConstDecls *VisitedCallees) {660if (!D->hasBody())661return;662Mode = getModeForDecl(D, Mode);663if (Mode == AM_None)664return;665666// Clear the AnalysisManager of old AnalysisDeclContexts.667Mgr->ClearContexts();668// Ignore autosynthesized code.669if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized())670return;671672CFG *DeclCFG = Mgr->getCFG(D);673if (DeclCFG)674MaxCFGSize.updateMax(DeclCFG->size());675676DisplayFunction(D, Mode, IMode);677BugReporter BR(*Mgr);678BR.setAnalysisEntryPoint(D);679680if (Mode & AM_Syntax) {681llvm::TimeRecord CheckerStartTime;682if (SyntaxCheckTimer) {683CheckerStartTime = SyntaxCheckTimer->getTotalTime();684SyntaxCheckTimer->startTimer();685}686checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);687if (SyntaxCheckTimer) {688SyntaxCheckTimer->stopTimer();689llvm::TimeRecord CheckerEndTime = SyntaxCheckTimer->getTotalTime();690CheckerEndTime -= CheckerStartTime;691DisplayTime(CheckerEndTime);692}693}694695BR.FlushReports();696697if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {698RunPathSensitiveChecks(D, IMode, VisitedCallees);699if (IMode != ExprEngine::Inline_Minimal)700NumFunctionsAnalyzed++;701}702}703704//===----------------------------------------------------------------------===//705// Path-sensitive checking.706//===----------------------------------------------------------------------===//707708void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,709ExprEngine::InliningModes IMode,710SetOfConstDecls *VisitedCallees) {711// Construct the analysis engine. First check if the CFG is valid.712// FIXME: Inter-procedural analysis will need to handle invalid CFGs.713if (!Mgr->getCFG(D))714return;715716// See if the LiveVariables analysis scales.717if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())718return;719720ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);721722// Execute the worklist algorithm.723llvm::TimeRecord ExprEngineStartTime;724if (ExprEngineTimer) {725ExprEngineStartTime = ExprEngineTimer->getTotalTime();726ExprEngineTimer->startTimer();727}728Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),729Mgr->options.MaxNodesPerTopLevelFunction);730if (ExprEngineTimer) {731ExprEngineTimer->stopTimer();732llvm::TimeRecord ExprEngineEndTime = ExprEngineTimer->getTotalTime();733ExprEngineEndTime -= ExprEngineStartTime;734DisplayTime(ExprEngineEndTime);735}736737if (!Mgr->options.DumpExplodedGraphTo.empty())738Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo);739740// Visualize the exploded graph.741if (Mgr->options.visualizeExplodedGraphWithGraphViz)742Eng.ViewGraph(Mgr->options.TrimGraph);743744// Display warnings.745if (BugReporterTimer)746BugReporterTimer->startTimer();747Eng.getBugReporter().FlushReports();748if (BugReporterTimer)749BugReporterTimer->stopTimer();750}751752//===----------------------------------------------------------------------===//753// AnalysisConsumer creation.754//===----------------------------------------------------------------------===//755756std::unique_ptr<AnalysisASTConsumer>757ento::CreateAnalysisConsumer(CompilerInstance &CI) {758// Disable the effects of '-Werror' when using the AnalysisConsumer.759CI.getPreprocessor().getDiagnostics().setWarningsAsErrors(false);760761AnalyzerOptions &analyzerOpts = CI.getAnalyzerOpts();762bool hasModelPath = analyzerOpts.Config.count("model-path") > 0;763764return std::make_unique<AnalysisConsumer>(765CI, CI.getFrontendOpts().OutputFile, analyzerOpts,766CI.getFrontendOpts().Plugins,767hasModelPath ? new ModelInjector(CI) : nullptr);768}769770771