diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp | 65 |
1 files changed, 57 insertions, 8 deletions
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 53466e7a75b0..f6a3e7996cd6 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -39,6 +39,7 @@ #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" +#include <cmath> #include <memory> #include <utility> @@ -51,6 +52,9 @@ STAT_COUNTER(NumFunctionTopLevel, "The # of functions at top level."); ALWAYS_ENABLED_STATISTIC(NumFunctionsAnalyzed, "The # of functions and blocks analyzed (as top level " "with inlining turned on)."); +ALWAYS_ENABLED_STATISTIC( + NumFunctionsAnalyzedSyntaxOnly, + "The # of functions analyzed by syntax checkers only."); ALWAYS_ENABLED_STATISTIC(NumBlocksInAnalyzedFunctions, "The # of basic blocks in the analyzed functions."); ALWAYS_ENABLED_STATISTIC( @@ -58,13 +62,24 @@ ALWAYS_ENABLED_STATISTIC( "The # of visited basic blocks in the analyzed functions."); ALWAYS_ENABLED_STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks."); -STAT_MAX(MaxCFGSize, "The maximum number of basic blocks in a function."); +ALWAYS_ENABLED_STATISTIC(MaxCFGSize, + "The maximum number of basic blocks in a function."); +static UnsignedEPStat CFGSize("CFGSize"); //===----------------------------------------------------------------------===// // AnalysisConsumer declaration. //===----------------------------------------------------------------------===// namespace { +StringRef getMainFileName(const CompilerInvocation &Invocation) { + if (!Invocation.getFrontendOpts().Inputs.empty()) { + const FrontendInputFile &Input = Invocation.getFrontendOpts().Inputs[0]; + return Input.isFile() ? Input.getFile() + : Input.getBuffer().getBufferIdentifier(); + } + return "<no input>"; +} + class AnalysisConsumer : public AnalysisASTConsumer, public DynamicRecursiveASTVisitor { enum { @@ -113,6 +128,7 @@ public: std::unique_ptr<llvm::Timer> SyntaxCheckTimer; std::unique_ptr<llvm::Timer> ExprEngineTimer; std::unique_ptr<llvm::Timer> BugReporterTimer; + bool ShouldClearTimersToPreventDisplayingThem; /// The information about analyzed functions shared throughout the /// translation unit. @@ -125,11 +141,13 @@ public: PP(CI.getPreprocessor()), OutDir(outdir), Opts(opts), Plugins(plugins), Injector(std::move(injector)), CTU(CI), MacroExpansions(CI.getLangOpts()) { - EntryPointStat::lockRegistry(); + + EntryPointStat::lockRegistry(getMainFileName(CI.getInvocation()), + CI.getASTContext()); DigestAnalyzerOptions(); if (Opts.AnalyzerDisplayProgress || Opts.PrintStats || - Opts.ShouldSerializeStats) { + Opts.ShouldSerializeStats || !Opts.DumpEntryPointStatsToCSV.empty()) { AnalyzerTimers = std::make_unique<llvm::TimerGroup>( "analyzer", "Analyzer timers"); SyntaxCheckTimer = std::make_unique<llvm::Timer>( @@ -141,6 +159,12 @@ public: *AnalyzerTimers); } + // Avoid displaying the timers created above in case we only want to record + // per-entry-point stats. + ShouldClearTimersToPreventDisplayingThem = !Opts.AnalyzerDisplayProgress && + !Opts.PrintStats && + !Opts.ShouldSerializeStats; + if (Opts.PrintStats || Opts.ShouldSerializeStats) { llvm::EnableStatistics(/* DoPrintOnExit= */ false); } @@ -263,6 +287,9 @@ public: checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR); if (SyntaxCheckTimer) SyntaxCheckTimer->stopTimer(); + if (AnalyzerTimers && ShouldClearTimersToPreventDisplayingThem) { + AnalyzerTimers->clear(); + } } return true; } @@ -556,6 +583,9 @@ void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) { checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR); if (SyntaxCheckTimer) SyntaxCheckTimer->stopTimer(); + if (AnalyzerTimers && ShouldClearTimersToPreventDisplayingThem) { + AnalyzerTimers->clear(); + } // Run the AST-only checks using the order in which functions are defined. // If inlining is not turned on, use the simplest function order for path @@ -588,10 +618,10 @@ void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) { // If the user wanted to analyze a specific function and the number of basic // blocks analyzed is zero, than the user might not specified the function // name correctly. - // FIXME: The user might have analyzed the requested function in Syntax mode, - // but we are unaware of that. - if (!Opts.AnalyzeSpecificFunction.empty() && NumFunctionsAnalyzed == 0) + if (!Opts.AnalyzeSpecificFunction.empty() && NumFunctionsAnalyzed == 0 && + NumFunctionsAnalyzedSyntaxOnly == 0) { reportAnalyzerFunctionMisuse(Opts, *Ctx); + } } void AnalysisConsumer::reportAnalyzerProgress(StringRef S) { @@ -659,8 +689,11 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { AnalysisConsumer::AnalysisMode AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) { if (!Opts.AnalyzeSpecificFunction.empty() && - AnalysisDeclContext::getFunctionName(D) != Opts.AnalyzeSpecificFunction) + AnalysisDeclContext::getFunctionName(D) != Opts.AnalyzeSpecificFunction && + cross_tu::CrossTranslationUnitContext::getLookupName(D).value_or("") != + Opts.AnalyzeSpecificFunction) { return AM_None; + } // Unless -analyze-all is specified, treat decls differently depending on // where they came from: @@ -723,11 +756,15 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, SyntaxCheckTimer->startTimer(); } checkerMgr->runCheckersOnASTBody(D, *Mgr, BR); + ++NumFunctionsAnalyzedSyntaxOnly; if (SyntaxCheckTimer) { SyntaxCheckTimer->stopTimer(); llvm::TimeRecord CheckerEndTime = SyntaxCheckTimer->getTotalTime(); CheckerEndTime -= CheckerStartTime; DisplayTime(CheckerEndTime); + if (AnalyzerTimers && ShouldClearTimersToPreventDisplayingThem) { + AnalyzerTimers->clear(); + } } } @@ -748,15 +785,19 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, ExprEngine::InliningModes IMode, SetOfConstDecls *VisitedCallees) { + auto *CFG = Mgr->getCFG(D); + // Construct the analysis engine. First check if the CFG is valid. // FIXME: Inter-procedural analysis will need to handle invalid CFGs. - if (!Mgr->getCFG(D)) + if (!CFG) return; // See if the LiveVariables analysis scales. if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>()) return; + CFGSize.set(CFG->size()); + ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode); // Execute the worklist algorithm. @@ -771,7 +812,12 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, ExprEngineTimer->stopTimer(); llvm::TimeRecord ExprEngineEndTime = ExprEngineTimer->getTotalTime(); ExprEngineEndTime -= ExprEngineStartTime; + PathRunningTime.set(static_cast<unsigned>( + std::lround(ExprEngineEndTime.getWallTime() * 1000))); DisplayTime(ExprEngineEndTime); + if (AnalyzerTimers && ShouldClearTimersToPreventDisplayingThem) { + AnalyzerTimers->clear(); + } } if (!Mgr->options.DumpExplodedGraphTo.empty()) @@ -782,6 +828,9 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, Eng.ViewGraph(Mgr->options.TrimGraph); flushReports(BugReporterTimer.get(), Eng.getBugReporter()); + if (AnalyzerTimers && ShouldClearTimersToPreventDisplayingThem) { + AnalyzerTimers->clear(); + } } //===----------------------------------------------------------------------===// |
