summaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp65
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();
+ }
}
//===----------------------------------------------------------------------===//