1e5dd7070Spatrick //===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // "Meta" ASTConsumer for running different source analyses.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
14e5dd7070Spatrick #include "ModelInjector.h"
15e5dd7070Spatrick #include "clang/AST/Decl.h"
16e5dd7070Spatrick #include "clang/AST/DeclCXX.h"
17e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
18e5dd7070Spatrick #include "clang/AST/RecursiveASTVisitor.h"
19e5dd7070Spatrick #include "clang/Analysis/Analyses/LiveVariables.h"
20e5dd7070Spatrick #include "clang/Analysis/CFG.h"
21e5dd7070Spatrick #include "clang/Analysis/CallGraph.h"
22e5dd7070Spatrick #include "clang/Analysis/CodeInjector.h"
23a9ac8606Spatrick #include "clang/Analysis/MacroExpansionContext.h"
24ec727ea7Spatrick #include "clang/Analysis/PathDiagnostic.h"
25e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
26e5dd7070Spatrick #include "clang/CrossTU/CrossTranslationUnit.h"
27e5dd7070Spatrick #include "clang/Frontend/CompilerInstance.h"
28e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
29ec727ea7Spatrick #include "clang/Rewrite/Core/Rewriter.h"
30e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
31e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
32e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h"
33e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
34e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
35e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
36e5dd7070Spatrick #include "llvm/ADT/PostOrderIterator.h"
37*12c85518Srobert #include "llvm/ADT/ScopeExit.h"
38e5dd7070Spatrick #include "llvm/ADT/Statistic.h"
39e5dd7070Spatrick #include "llvm/Support/FileSystem.h"
40e5dd7070Spatrick #include "llvm/Support/Path.h"
41e5dd7070Spatrick #include "llvm/Support/Program.h"
42e5dd7070Spatrick #include "llvm/Support/Timer.h"
43e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
44e5dd7070Spatrick #include <memory>
45e5dd7070Spatrick #include <queue>
46e5dd7070Spatrick #include <utility>
47e5dd7070Spatrick
48e5dd7070Spatrick using namespace clang;
49e5dd7070Spatrick using namespace ento;
50e5dd7070Spatrick
51e5dd7070Spatrick #define DEBUG_TYPE "AnalysisConsumer"
52e5dd7070Spatrick
53e5dd7070Spatrick STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
54e5dd7070Spatrick STATISTIC(NumFunctionsAnalyzed,
55e5dd7070Spatrick "The # of functions and blocks analyzed (as top level "
56e5dd7070Spatrick "with inlining turned on).");
57e5dd7070Spatrick STATISTIC(NumBlocksInAnalyzedFunctions,
58e5dd7070Spatrick "The # of basic blocks in the analyzed functions.");
59e5dd7070Spatrick STATISTIC(NumVisitedBlocksInAnalyzedFunctions,
60e5dd7070Spatrick "The # of visited basic blocks in the analyzed functions.");
61e5dd7070Spatrick STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
62e5dd7070Spatrick STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
63e5dd7070Spatrick
64e5dd7070Spatrick //===----------------------------------------------------------------------===//
65e5dd7070Spatrick // AnalysisConsumer declaration.
66e5dd7070Spatrick //===----------------------------------------------------------------------===//
67e5dd7070Spatrick
68e5dd7070Spatrick namespace {
69e5dd7070Spatrick
70e5dd7070Spatrick class AnalysisConsumer : public AnalysisASTConsumer,
71e5dd7070Spatrick public RecursiveASTVisitor<AnalysisConsumer> {
72e5dd7070Spatrick enum {
73e5dd7070Spatrick AM_None = 0,
74e5dd7070Spatrick AM_Syntax = 0x1,
75e5dd7070Spatrick AM_Path = 0x2
76e5dd7070Spatrick };
77e5dd7070Spatrick typedef unsigned AnalysisMode;
78e5dd7070Spatrick
79e5dd7070Spatrick /// Mode of the analyzes while recursively visiting Decls.
80e5dd7070Spatrick AnalysisMode RecVisitorMode;
81e5dd7070Spatrick /// Bug Reporter to use while recursively visiting Decls.
82e5dd7070Spatrick BugReporter *RecVisitorBR;
83e5dd7070Spatrick
84e5dd7070Spatrick std::vector<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns;
85e5dd7070Spatrick
86e5dd7070Spatrick public:
87e5dd7070Spatrick ASTContext *Ctx;
88ec727ea7Spatrick Preprocessor &PP;
89e5dd7070Spatrick const std::string OutDir;
90e5dd7070Spatrick AnalyzerOptionsRef Opts;
91e5dd7070Spatrick ArrayRef<std::string> Plugins;
92e5dd7070Spatrick CodeInjector *Injector;
93e5dd7070Spatrick cross_tu::CrossTranslationUnitContext CTU;
94e5dd7070Spatrick
95e5dd7070Spatrick /// Stores the declarations from the local translation unit.
96e5dd7070Spatrick /// Note, we pre-compute the local declarations at parse time as an
97e5dd7070Spatrick /// optimization to make sure we do not deserialize everything from disk.
98e5dd7070Spatrick /// The local declaration to all declarations ratio might be very small when
99e5dd7070Spatrick /// working with a PCH file.
100e5dd7070Spatrick SetOfDecls LocalTUDecls;
101e5dd7070Spatrick
102a9ac8606Spatrick MacroExpansionContext MacroExpansions;
103a9ac8606Spatrick
104e5dd7070Spatrick // Set of PathDiagnosticConsumers. Owned by AnalysisManager.
105e5dd7070Spatrick PathDiagnosticConsumers PathConsumers;
106e5dd7070Spatrick
107e5dd7070Spatrick StoreManagerCreator CreateStoreMgr;
108e5dd7070Spatrick ConstraintManagerCreator CreateConstraintMgr;
109e5dd7070Spatrick
110e5dd7070Spatrick std::unique_ptr<CheckerManager> checkerMgr;
111e5dd7070Spatrick std::unique_ptr<AnalysisManager> Mgr;
112e5dd7070Spatrick
113e5dd7070Spatrick /// Time the analyzes time of each translation unit.
114e5dd7070Spatrick std::unique_ptr<llvm::TimerGroup> AnalyzerTimers;
115e5dd7070Spatrick std::unique_ptr<llvm::Timer> SyntaxCheckTimer;
116e5dd7070Spatrick std::unique_ptr<llvm::Timer> ExprEngineTimer;
117e5dd7070Spatrick std::unique_ptr<llvm::Timer> BugReporterTimer;
118e5dd7070Spatrick
119e5dd7070Spatrick /// The information about analyzed functions shared throughout the
120e5dd7070Spatrick /// translation unit.
121e5dd7070Spatrick FunctionSummariesTy FunctionSummaries;
122e5dd7070Spatrick
AnalysisConsumer(CompilerInstance & CI,const std::string & outdir,AnalyzerOptionsRef opts,ArrayRef<std::string> plugins,CodeInjector * injector)123e5dd7070Spatrick AnalysisConsumer(CompilerInstance &CI, const std::string &outdir,
124e5dd7070Spatrick AnalyzerOptionsRef opts, ArrayRef<std::string> plugins,
125e5dd7070Spatrick CodeInjector *injector)
126e5dd7070Spatrick : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),
127e5dd7070Spatrick PP(CI.getPreprocessor()), OutDir(outdir), Opts(std::move(opts)),
128a9ac8606Spatrick Plugins(plugins), Injector(injector), CTU(CI),
129a9ac8606Spatrick MacroExpansions(CI.getLangOpts()) {
130e5dd7070Spatrick DigestAnalyzerOptions();
131a9ac8606Spatrick if (Opts->AnalyzerDisplayProgress || Opts->PrintStats ||
132a9ac8606Spatrick Opts->ShouldSerializeStats) {
133e5dd7070Spatrick AnalyzerTimers = std::make_unique<llvm::TimerGroup>(
134e5dd7070Spatrick "analyzer", "Analyzer timers");
135e5dd7070Spatrick SyntaxCheckTimer = std::make_unique<llvm::Timer>(
136e5dd7070Spatrick "syntaxchecks", "Syntax-based analysis time", *AnalyzerTimers);
137e5dd7070Spatrick ExprEngineTimer = std::make_unique<llvm::Timer>(
138e5dd7070Spatrick "exprengine", "Path exploration time", *AnalyzerTimers);
139e5dd7070Spatrick BugReporterTimer = std::make_unique<llvm::Timer>(
140e5dd7070Spatrick "bugreporter", "Path-sensitive report post-processing time",
141e5dd7070Spatrick *AnalyzerTimers);
142a9ac8606Spatrick }
143a9ac8606Spatrick
144a9ac8606Spatrick if (Opts->PrintStats || Opts->ShouldSerializeStats) {
145*12c85518Srobert llvm::EnableStatistics(/* DoPrintOnExit= */ false);
146e5dd7070Spatrick }
147a9ac8606Spatrick
148a9ac8606Spatrick if (Opts->ShouldDisplayMacroExpansions)
149a9ac8606Spatrick MacroExpansions.registerForPreprocessor(PP);
150e5dd7070Spatrick }
151e5dd7070Spatrick
~AnalysisConsumer()152e5dd7070Spatrick ~AnalysisConsumer() override {
153e5dd7070Spatrick if (Opts->PrintStats) {
154e5dd7070Spatrick llvm::PrintStatistics();
155e5dd7070Spatrick }
156e5dd7070Spatrick }
157e5dd7070Spatrick
DigestAnalyzerOptions()158e5dd7070Spatrick void DigestAnalyzerOptions() {
159e5dd7070Spatrick switch (Opts->AnalysisDiagOpt) {
160ec727ea7Spatrick case PD_NONE:
161ec727ea7Spatrick break;
162e5dd7070Spatrick #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
163e5dd7070Spatrick case PD_##NAME: \
164a9ac8606Spatrick CREATEFN(Opts->getDiagOpts(), PathConsumers, OutDir, PP, CTU, \
165a9ac8606Spatrick MacroExpansions); \
166e5dd7070Spatrick break;
167e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Analyses.def"
168ec727ea7Spatrick default:
169ec727ea7Spatrick llvm_unreachable("Unknown analyzer output type!");
170e5dd7070Spatrick }
171e5dd7070Spatrick
172e5dd7070Spatrick // Create the analyzer component creators.
173*12c85518Srobert CreateStoreMgr = &CreateRegionStoreManager;
174e5dd7070Spatrick
175e5dd7070Spatrick switch (Opts->AnalysisConstraintsOpt) {
176e5dd7070Spatrick default:
177e5dd7070Spatrick llvm_unreachable("Unknown constraint manager.");
178e5dd7070Spatrick #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
179e5dd7070Spatrick case NAME##Model: CreateConstraintMgr = CREATEFN; break;
180e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Analyses.def"
181e5dd7070Spatrick }
182e5dd7070Spatrick }
183e5dd7070Spatrick
DisplayTime(llvm::TimeRecord & Time)184a9ac8606Spatrick void DisplayTime(llvm::TimeRecord &Time) {
185a9ac8606Spatrick if (!Opts->AnalyzerDisplayProgress) {
186a9ac8606Spatrick return;
187a9ac8606Spatrick }
188a9ac8606Spatrick llvm::errs() << " : " << llvm::format("%1.1f", Time.getWallTime() * 1000)
189a9ac8606Spatrick << " ms\n";
190a9ac8606Spatrick }
191a9ac8606Spatrick
DisplayFunction(const Decl * D,AnalysisMode Mode,ExprEngine::InliningModes IMode)192e5dd7070Spatrick void DisplayFunction(const Decl *D, AnalysisMode Mode,
193e5dd7070Spatrick ExprEngine::InliningModes IMode) {
194e5dd7070Spatrick if (!Opts->AnalyzerDisplayProgress)
195e5dd7070Spatrick return;
196e5dd7070Spatrick
197e5dd7070Spatrick SourceManager &SM = Mgr->getASTContext().getSourceManager();
198e5dd7070Spatrick PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
199e5dd7070Spatrick if (Loc.isValid()) {
200e5dd7070Spatrick llvm::errs() << "ANALYZE";
201e5dd7070Spatrick
202e5dd7070Spatrick if (Mode == AM_Syntax)
203e5dd7070Spatrick llvm::errs() << " (Syntax)";
204e5dd7070Spatrick else if (Mode == AM_Path) {
205e5dd7070Spatrick llvm::errs() << " (Path, ";
206e5dd7070Spatrick switch (IMode) {
207e5dd7070Spatrick case ExprEngine::Inline_Minimal:
208e5dd7070Spatrick llvm::errs() << " Inline_Minimal";
209e5dd7070Spatrick break;
210e5dd7070Spatrick case ExprEngine::Inline_Regular:
211e5dd7070Spatrick llvm::errs() << " Inline_Regular";
212e5dd7070Spatrick break;
213e5dd7070Spatrick }
214e5dd7070Spatrick llvm::errs() << ")";
215ec727ea7Spatrick } else
216e5dd7070Spatrick assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");
217e5dd7070Spatrick
218a9ac8606Spatrick llvm::errs() << ": " << Loc.getFilename() << ' '
219a9ac8606Spatrick << AnalysisDeclContext::getFunctionName(D);
220e5dd7070Spatrick }
221e5dd7070Spatrick }
222e5dd7070Spatrick
Initialize(ASTContext & Context)223e5dd7070Spatrick void Initialize(ASTContext &Context) override {
224e5dd7070Spatrick Ctx = &Context;
225ec727ea7Spatrick checkerMgr = std::make_unique<CheckerManager>(*Ctx, *Opts, PP, Plugins,
226ec727ea7Spatrick CheckerRegistrationFns);
227e5dd7070Spatrick
228ec727ea7Spatrick Mgr = std::make_unique<AnalysisManager>(*Ctx, PP, PathConsumers,
229ec727ea7Spatrick CreateStoreMgr, CreateConstraintMgr,
230e5dd7070Spatrick checkerMgr.get(), *Opts, Injector);
231e5dd7070Spatrick }
232e5dd7070Spatrick
233e5dd7070Spatrick /// Store the top level decls in the set to be processed later on.
234e5dd7070Spatrick /// (Doing this pre-processing avoids deserialization of data from PCH.)
235e5dd7070Spatrick bool HandleTopLevelDecl(DeclGroupRef D) override;
236e5dd7070Spatrick void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;
237e5dd7070Spatrick
238e5dd7070Spatrick void HandleTranslationUnit(ASTContext &C) override;
239e5dd7070Spatrick
240e5dd7070Spatrick /// Determine which inlining mode should be used when this function is
241e5dd7070Spatrick /// analyzed. This allows to redefine the default inlining policies when
242e5dd7070Spatrick /// analyzing a given function.
243e5dd7070Spatrick ExprEngine::InliningModes
244e5dd7070Spatrick getInliningModeForFunction(const Decl *D, const SetOfConstDecls &Visited);
245e5dd7070Spatrick
246e5dd7070Spatrick /// Build the call graph for all the top level decls of this TU and
247e5dd7070Spatrick /// use it to define the order in which the functions should be visited.
248e5dd7070Spatrick void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);
249e5dd7070Spatrick
250e5dd7070Spatrick /// Run analyzes(syntax or path sensitive) on the given function.
251e5dd7070Spatrick /// \param Mode - determines if we are requesting syntax only or path
252e5dd7070Spatrick /// sensitive only analysis.
253e5dd7070Spatrick /// \param VisitedCallees - The output parameter, which is populated with the
254e5dd7070Spatrick /// set of functions which should be considered analyzed after analyzing the
255e5dd7070Spatrick /// given root function.
256e5dd7070Spatrick void HandleCode(Decl *D, AnalysisMode Mode,
257e5dd7070Spatrick ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal,
258e5dd7070Spatrick SetOfConstDecls *VisitedCallees = nullptr);
259e5dd7070Spatrick
260e5dd7070Spatrick void RunPathSensitiveChecks(Decl *D,
261e5dd7070Spatrick ExprEngine::InliningModes IMode,
262e5dd7070Spatrick SetOfConstDecls *VisitedCallees);
263e5dd7070Spatrick
264e5dd7070Spatrick /// Visitors for the RecursiveASTVisitor.
shouldWalkTypesOfTypeLocs() const265e5dd7070Spatrick bool shouldWalkTypesOfTypeLocs() const { return false; }
266e5dd7070Spatrick
267e5dd7070Spatrick /// Handle callbacks for arbitrary Decls.
VisitDecl(Decl * D)268e5dd7070Spatrick bool VisitDecl(Decl *D) {
269e5dd7070Spatrick AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
270e5dd7070Spatrick if (Mode & AM_Syntax) {
271e5dd7070Spatrick if (SyntaxCheckTimer)
272e5dd7070Spatrick SyntaxCheckTimer->startTimer();
273e5dd7070Spatrick checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
274e5dd7070Spatrick if (SyntaxCheckTimer)
275e5dd7070Spatrick SyntaxCheckTimer->stopTimer();
276e5dd7070Spatrick }
277e5dd7070Spatrick return true;
278e5dd7070Spatrick }
279e5dd7070Spatrick
VisitVarDecl(VarDecl * VD)280e5dd7070Spatrick bool VisitVarDecl(VarDecl *VD) {
281e5dd7070Spatrick if (!Opts->IsNaiveCTUEnabled)
282e5dd7070Spatrick return true;
283e5dd7070Spatrick
284e5dd7070Spatrick if (VD->hasExternalStorage() || VD->isStaticDataMember()) {
285*12c85518Srobert if (!cross_tu::shouldImport(VD, *Ctx))
286e5dd7070Spatrick return true;
287e5dd7070Spatrick } else {
288e5dd7070Spatrick // Cannot be initialized in another TU.
289e5dd7070Spatrick return true;
290e5dd7070Spatrick }
291e5dd7070Spatrick
292e5dd7070Spatrick if (VD->getAnyInitializer())
293e5dd7070Spatrick return true;
294e5dd7070Spatrick
295e5dd7070Spatrick llvm::Expected<const VarDecl *> CTUDeclOrError =
296e5dd7070Spatrick CTU.getCrossTUDefinition(VD, Opts->CTUDir, Opts->CTUIndexName,
297e5dd7070Spatrick Opts->DisplayCTUProgress);
298e5dd7070Spatrick
299e5dd7070Spatrick if (!CTUDeclOrError) {
300e5dd7070Spatrick handleAllErrors(CTUDeclOrError.takeError(),
301e5dd7070Spatrick [&](const cross_tu::IndexError &IE) {
302e5dd7070Spatrick CTU.emitCrossTUDiagnostics(IE);
303e5dd7070Spatrick });
304e5dd7070Spatrick }
305e5dd7070Spatrick
306e5dd7070Spatrick return true;
307e5dd7070Spatrick }
308e5dd7070Spatrick
VisitFunctionDecl(FunctionDecl * FD)309e5dd7070Spatrick bool VisitFunctionDecl(FunctionDecl *FD) {
310e5dd7070Spatrick IdentifierInfo *II = FD->getIdentifier();
311e5dd7070Spatrick if (II && II->getName().startswith("__inline"))
312e5dd7070Spatrick return true;
313e5dd7070Spatrick
314e5dd7070Spatrick // We skip function template definitions, as their semantics is
315e5dd7070Spatrick // only determined when they are instantiated.
316e5dd7070Spatrick if (FD->isThisDeclarationADefinition() &&
317e5dd7070Spatrick !FD->isDependentContext()) {
318e5dd7070Spatrick assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
319e5dd7070Spatrick HandleCode(FD, RecVisitorMode);
320e5dd7070Spatrick }
321e5dd7070Spatrick return true;
322e5dd7070Spatrick }
323e5dd7070Spatrick
VisitObjCMethodDecl(ObjCMethodDecl * MD)324e5dd7070Spatrick bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
325e5dd7070Spatrick if (MD->isThisDeclarationADefinition()) {
326e5dd7070Spatrick assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
327e5dd7070Spatrick HandleCode(MD, RecVisitorMode);
328e5dd7070Spatrick }
329e5dd7070Spatrick return true;
330e5dd7070Spatrick }
331e5dd7070Spatrick
VisitBlockDecl(BlockDecl * BD)332e5dd7070Spatrick bool VisitBlockDecl(BlockDecl *BD) {
333e5dd7070Spatrick if (BD->hasBody()) {
334e5dd7070Spatrick assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
335e5dd7070Spatrick // Since we skip function template definitions, we should skip blocks
336e5dd7070Spatrick // declared in those functions as well.
337e5dd7070Spatrick if (!BD->isDependentContext()) {
338e5dd7070Spatrick HandleCode(BD, RecVisitorMode);
339e5dd7070Spatrick }
340e5dd7070Spatrick }
341e5dd7070Spatrick return true;
342e5dd7070Spatrick }
343e5dd7070Spatrick
AddDiagnosticConsumer(PathDiagnosticConsumer * Consumer)344e5dd7070Spatrick void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) override {
345e5dd7070Spatrick PathConsumers.push_back(Consumer);
346e5dd7070Spatrick }
347e5dd7070Spatrick
AddCheckerRegistrationFn(std::function<void (CheckerRegistry &)> Fn)348e5dd7070Spatrick void AddCheckerRegistrationFn(std::function<void(CheckerRegistry&)> Fn) override {
349e5dd7070Spatrick CheckerRegistrationFns.push_back(std::move(Fn));
350e5dd7070Spatrick }
351e5dd7070Spatrick
352e5dd7070Spatrick private:
353e5dd7070Spatrick void storeTopLevelDecls(DeclGroupRef DG);
354e5dd7070Spatrick
355e5dd7070Spatrick /// Check if we should skip (not analyze) the given function.
356e5dd7070Spatrick AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);
357e5dd7070Spatrick void runAnalysisOnTranslationUnit(ASTContext &C);
358e5dd7070Spatrick
359e5dd7070Spatrick /// Print \p S to stderr if \c Opts->AnalyzerDisplayProgress is set.
360e5dd7070Spatrick void reportAnalyzerProgress(StringRef S);
361ec727ea7Spatrick }; // namespace
362e5dd7070Spatrick } // end anonymous namespace
363e5dd7070Spatrick
364e5dd7070Spatrick
365e5dd7070Spatrick //===----------------------------------------------------------------------===//
366e5dd7070Spatrick // AnalysisConsumer implementation.
367e5dd7070Spatrick //===----------------------------------------------------------------------===//
HandleTopLevelDecl(DeclGroupRef DG)368e5dd7070Spatrick bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
369e5dd7070Spatrick storeTopLevelDecls(DG);
370e5dd7070Spatrick return true;
371e5dd7070Spatrick }
372e5dd7070Spatrick
HandleTopLevelDeclInObjCContainer(DeclGroupRef DG)373e5dd7070Spatrick void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
374e5dd7070Spatrick storeTopLevelDecls(DG);
375e5dd7070Spatrick }
376e5dd7070Spatrick
storeTopLevelDecls(DeclGroupRef DG)377e5dd7070Spatrick void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
378*12c85518Srobert for (auto &I : DG) {
379e5dd7070Spatrick
380e5dd7070Spatrick // Skip ObjCMethodDecl, wait for the objc container to avoid
381e5dd7070Spatrick // analyzing twice.
382*12c85518Srobert if (isa<ObjCMethodDecl>(I))
383e5dd7070Spatrick continue;
384e5dd7070Spatrick
385*12c85518Srobert LocalTUDecls.push_back(I);
386e5dd7070Spatrick }
387e5dd7070Spatrick }
388e5dd7070Spatrick
shouldSkipFunction(const Decl * D,const SetOfConstDecls & Visited,const SetOfConstDecls & VisitedAsTopLevel)389e5dd7070Spatrick static bool shouldSkipFunction(const Decl *D,
390e5dd7070Spatrick const SetOfConstDecls &Visited,
391e5dd7070Spatrick const SetOfConstDecls &VisitedAsTopLevel) {
392e5dd7070Spatrick if (VisitedAsTopLevel.count(D))
393e5dd7070Spatrick return true;
394e5dd7070Spatrick
395ec727ea7Spatrick // Skip analysis of inheriting constructors as top-level functions. These
396ec727ea7Spatrick // constructors don't even have a body written down in the code, so even if
397ec727ea7Spatrick // we find a bug, we won't be able to display it.
398ec727ea7Spatrick if (const auto *CD = dyn_cast<CXXConstructorDecl>(D))
399ec727ea7Spatrick if (CD->isInheritingConstructor())
400ec727ea7Spatrick return true;
401ec727ea7Spatrick
402e5dd7070Spatrick // We want to re-analyse the functions as top level in the following cases:
403e5dd7070Spatrick // - The 'init' methods should be reanalyzed because
404e5dd7070Spatrick // ObjCNonNilReturnValueChecker assumes that '[super init]' never returns
405e5dd7070Spatrick // 'nil' and unless we analyze the 'init' functions as top level, we will
406e5dd7070Spatrick // not catch errors within defensive code.
407e5dd7070Spatrick // - We want to reanalyze all ObjC methods as top level to report Retain
408e5dd7070Spatrick // Count naming convention errors more aggressively.
409e5dd7070Spatrick if (isa<ObjCMethodDecl>(D))
410e5dd7070Spatrick return false;
411e5dd7070Spatrick // We also want to reanalyze all C++ copy and move assignment operators to
412e5dd7070Spatrick // separately check the two cases where 'this' aliases with the parameter and
413e5dd7070Spatrick // where it may not. (cplusplus.SelfAssignmentChecker)
414e5dd7070Spatrick if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
415e5dd7070Spatrick if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())
416e5dd7070Spatrick return false;
417e5dd7070Spatrick }
418e5dd7070Spatrick
419e5dd7070Spatrick // Otherwise, if we visited the function before, do not reanalyze it.
420e5dd7070Spatrick return Visited.count(D);
421e5dd7070Spatrick }
422e5dd7070Spatrick
423e5dd7070Spatrick ExprEngine::InliningModes
getInliningModeForFunction(const Decl * D,const SetOfConstDecls & Visited)424e5dd7070Spatrick AnalysisConsumer::getInliningModeForFunction(const Decl *D,
425e5dd7070Spatrick const SetOfConstDecls &Visited) {
426e5dd7070Spatrick // We want to reanalyze all ObjC methods as top level to report Retain
427e5dd7070Spatrick // Count naming convention errors more aggressively. But we should tune down
428e5dd7070Spatrick // inlining when reanalyzing an already inlined function.
429e5dd7070Spatrick if (Visited.count(D) && isa<ObjCMethodDecl>(D)) {
430e5dd7070Spatrick const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D);
431e5dd7070Spatrick if (ObjCM->getMethodFamily() != OMF_init)
432e5dd7070Spatrick return ExprEngine::Inline_Minimal;
433e5dd7070Spatrick }
434e5dd7070Spatrick
435e5dd7070Spatrick return ExprEngine::Inline_Regular;
436e5dd7070Spatrick }
437e5dd7070Spatrick
HandleDeclsCallGraph(const unsigned LocalTUDeclsSize)438e5dd7070Spatrick void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
439e5dd7070Spatrick // Build the Call Graph by adding all the top level declarations to the graph.
440e5dd7070Spatrick // Note: CallGraph can trigger deserialization of more items from a pch
441e5dd7070Spatrick // (though HandleInterestingDecl); triggering additions to LocalTUDecls.
442e5dd7070Spatrick // We rely on random access to add the initially processed Decls to CG.
443e5dd7070Spatrick CallGraph CG;
444e5dd7070Spatrick for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
445e5dd7070Spatrick CG.addToCallGraph(LocalTUDecls[i]);
446e5dd7070Spatrick }
447e5dd7070Spatrick
448e5dd7070Spatrick // Walk over all of the call graph nodes in topological order, so that we
449e5dd7070Spatrick // analyze parents before the children. Skip the functions inlined into
450e5dd7070Spatrick // the previously processed functions. Use external Visited set to identify
451e5dd7070Spatrick // inlined functions. The topological order allows the "do not reanalyze
452e5dd7070Spatrick // previously inlined function" performance heuristic to be triggered more
453e5dd7070Spatrick // often.
454e5dd7070Spatrick SetOfConstDecls Visited;
455e5dd7070Spatrick SetOfConstDecls VisitedAsTopLevel;
456e5dd7070Spatrick llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
457*12c85518Srobert for (auto &N : RPOT) {
458e5dd7070Spatrick NumFunctionTopLevel++;
459e5dd7070Spatrick
460e5dd7070Spatrick Decl *D = N->getDecl();
461e5dd7070Spatrick
462e5dd7070Spatrick // Skip the abstract root node.
463e5dd7070Spatrick if (!D)
464e5dd7070Spatrick continue;
465e5dd7070Spatrick
466e5dd7070Spatrick // Skip the functions which have been processed already or previously
467e5dd7070Spatrick // inlined.
468e5dd7070Spatrick if (shouldSkipFunction(D, Visited, VisitedAsTopLevel))
469e5dd7070Spatrick continue;
470e5dd7070Spatrick
471*12c85518Srobert // The CallGraph might have declarations as callees. However, during CTU
472*12c85518Srobert // the declaration might form a declaration chain with the newly imported
473*12c85518Srobert // definition from another TU. In this case we don't want to analyze the
474*12c85518Srobert // function definition as toplevel.
475*12c85518Srobert if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
476*12c85518Srobert // Calling 'hasBody' replaces 'FD' in place with the FunctionDecl
477*12c85518Srobert // that has the body.
478*12c85518Srobert FD->hasBody(FD);
479*12c85518Srobert if (CTU.isImportedAsNew(FD))
480*12c85518Srobert continue;
481*12c85518Srobert }
482*12c85518Srobert
483e5dd7070Spatrick // Analyze the function.
484e5dd7070Spatrick SetOfConstDecls VisitedCallees;
485e5dd7070Spatrick
486e5dd7070Spatrick HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
487e5dd7070Spatrick (Mgr->options.InliningMode == All ? nullptr : &VisitedCallees));
488e5dd7070Spatrick
489e5dd7070Spatrick // Add the visited callees to the global visited set.
490e5dd7070Spatrick for (const Decl *Callee : VisitedCallees)
491e5dd7070Spatrick // Decls from CallGraph are already canonical. But Decls coming from
492e5dd7070Spatrick // CallExprs may be not. We should canonicalize them manually.
493e5dd7070Spatrick Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
494e5dd7070Spatrick : Callee->getCanonicalDecl());
495e5dd7070Spatrick VisitedAsTopLevel.insert(D);
496e5dd7070Spatrick }
497e5dd7070Spatrick }
498e5dd7070Spatrick
fileContainsString(StringRef Substring,ASTContext & C)499*12c85518Srobert static bool fileContainsString(StringRef Substring, ASTContext &C) {
500e5dd7070Spatrick const SourceManager &SM = C.getSourceManager();
501e5dd7070Spatrick FileID FID = SM.getMainFileID();
502a9ac8606Spatrick StringRef Buffer = SM.getBufferOrFake(FID).getBuffer();
503*12c85518Srobert return Buffer.contains(Substring);
504*12c85518Srobert }
505*12c85518Srobert
reportAnalyzerFunctionMisuse(const AnalyzerOptions & Opts,const ASTContext & Ctx)506*12c85518Srobert static void reportAnalyzerFunctionMisuse(const AnalyzerOptions &Opts,
507*12c85518Srobert const ASTContext &Ctx) {
508*12c85518Srobert llvm::errs() << "Every top-level function was skipped.\n";
509*12c85518Srobert
510*12c85518Srobert if (!Opts.AnalyzerDisplayProgress)
511*12c85518Srobert llvm::errs() << "Pass the -analyzer-display-progress for tracking which "
512*12c85518Srobert "functions are analyzed.\n";
513*12c85518Srobert
514*12c85518Srobert bool HasBrackets =
515*12c85518Srobert Opts.AnalyzeSpecificFunction.find("(") != std::string::npos;
516*12c85518Srobert
517*12c85518Srobert if (Ctx.getLangOpts().CPlusPlus && !HasBrackets) {
518*12c85518Srobert llvm::errs()
519*12c85518Srobert << "For analyzing C++ code you need to pass the function parameter "
520*12c85518Srobert "list: -analyze-function=\"foobar(int, _Bool)\"\n";
521*12c85518Srobert } else if (!Ctx.getLangOpts().CPlusPlus && HasBrackets) {
522*12c85518Srobert llvm::errs() << "For analyzing C code you shouldn't pass the function "
523*12c85518Srobert "parameter list, only the name of the function: "
524*12c85518Srobert "-analyze-function=foobar\n";
525*12c85518Srobert }
526e5dd7070Spatrick }
527e5dd7070Spatrick
runAnalysisOnTranslationUnit(ASTContext & C)528e5dd7070Spatrick void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) {
529e5dd7070Spatrick BugReporter BR(*Mgr);
530e5dd7070Spatrick TranslationUnitDecl *TU = C.getTranslationUnitDecl();
531e5dd7070Spatrick if (SyntaxCheckTimer)
532e5dd7070Spatrick SyntaxCheckTimer->startTimer();
533e5dd7070Spatrick checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
534e5dd7070Spatrick if (SyntaxCheckTimer)
535e5dd7070Spatrick SyntaxCheckTimer->stopTimer();
536e5dd7070Spatrick
537e5dd7070Spatrick // Run the AST-only checks using the order in which functions are defined.
538e5dd7070Spatrick // If inlining is not turned on, use the simplest function order for path
539e5dd7070Spatrick // sensitive analyzes as well.
540e5dd7070Spatrick RecVisitorMode = AM_Syntax;
541e5dd7070Spatrick if (!Mgr->shouldInlineCall())
542e5dd7070Spatrick RecVisitorMode |= AM_Path;
543e5dd7070Spatrick RecVisitorBR = &BR;
544e5dd7070Spatrick
545e5dd7070Spatrick // Process all the top level declarations.
546e5dd7070Spatrick //
547e5dd7070Spatrick // Note: TraverseDecl may modify LocalTUDecls, but only by appending more
548e5dd7070Spatrick // entries. Thus we don't use an iterator, but rely on LocalTUDecls
549e5dd7070Spatrick // random access. By doing so, we automatically compensate for iterators
550e5dd7070Spatrick // possibly being invalidated, although this is a bit slower.
551e5dd7070Spatrick const unsigned LocalTUDeclsSize = LocalTUDecls.size();
552e5dd7070Spatrick for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
553e5dd7070Spatrick TraverseDecl(LocalTUDecls[i]);
554e5dd7070Spatrick }
555e5dd7070Spatrick
556e5dd7070Spatrick if (Mgr->shouldInlineCall())
557e5dd7070Spatrick HandleDeclsCallGraph(LocalTUDeclsSize);
558e5dd7070Spatrick
559e5dd7070Spatrick // After all decls handled, run checkers on the entire TranslationUnit.
560e5dd7070Spatrick checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
561e5dd7070Spatrick
562e5dd7070Spatrick BR.FlushReports();
563e5dd7070Spatrick RecVisitorBR = nullptr;
564*12c85518Srobert
565*12c85518Srobert // If the user wanted to analyze a specific function and the number of basic
566*12c85518Srobert // blocks analyzed is zero, than the user might not specified the function
567*12c85518Srobert // name correctly.
568*12c85518Srobert // FIXME: The user might have analyzed the requested function in Syntax mode,
569*12c85518Srobert // but we are unaware of that.
570*12c85518Srobert if (!Opts->AnalyzeSpecificFunction.empty() && NumFunctionsAnalyzed == 0)
571*12c85518Srobert reportAnalyzerFunctionMisuse(*Opts, *Ctx);
572e5dd7070Spatrick }
573e5dd7070Spatrick
reportAnalyzerProgress(StringRef S)574e5dd7070Spatrick void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {
575e5dd7070Spatrick if (Opts->AnalyzerDisplayProgress)
576e5dd7070Spatrick llvm::errs() << S;
577e5dd7070Spatrick }
578e5dd7070Spatrick
HandleTranslationUnit(ASTContext & C)579e5dd7070Spatrick void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
580e5dd7070Spatrick // Don't run the actions if an error has occurred with parsing the file.
581e5dd7070Spatrick DiagnosticsEngine &Diags = PP.getDiagnostics();
582e5dd7070Spatrick if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
583e5dd7070Spatrick return;
584e5dd7070Spatrick
585*12c85518Srobert // Explicitly destroy the PathDiagnosticConsumer. This will flush its output.
586*12c85518Srobert // FIXME: This should be replaced with something that doesn't rely on
587*12c85518Srobert // side-effects in PathDiagnosticConsumer's destructor. This is required when
588*12c85518Srobert // used with option -disable-free.
589*12c85518Srobert const auto DiagFlusherScopeExit =
590*12c85518Srobert llvm::make_scope_exit([this] { Mgr.reset(); });
591*12c85518Srobert
592*12c85518Srobert if (Opts->ShouldIgnoreBisonGeneratedFiles &&
593*12c85518Srobert fileContainsString("/* A Bison parser, made by", C)) {
594e5dd7070Spatrick reportAnalyzerProgress("Skipping bison-generated file\n");
595*12c85518Srobert return;
596*12c85518Srobert }
597*12c85518Srobert
598*12c85518Srobert if (Opts->ShouldIgnoreFlexGeneratedFiles &&
599*12c85518Srobert fileContainsString("/* A lexical scanner generated by flex", C)) {
600*12c85518Srobert reportAnalyzerProgress("Skipping flex-generated file\n");
601*12c85518Srobert return;
602*12c85518Srobert }
603e5dd7070Spatrick
604e5dd7070Spatrick // Don't analyze if the user explicitly asked for no checks to be performed
605e5dd7070Spatrick // on this file.
606*12c85518Srobert if (Opts->DisableAllCheckers) {
607e5dd7070Spatrick reportAnalyzerProgress("All checks are disabled using a supplied option\n");
608*12c85518Srobert return;
609*12c85518Srobert }
610*12c85518Srobert
611e5dd7070Spatrick // Otherwise, just run the analysis.
612e5dd7070Spatrick runAnalysisOnTranslationUnit(C);
613e5dd7070Spatrick
614e5dd7070Spatrick // Count how many basic blocks we have not covered.
615e5dd7070Spatrick NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
616e5dd7070Spatrick NumVisitedBlocksInAnalyzedFunctions =
617e5dd7070Spatrick FunctionSummaries.getTotalNumVisitedBasicBlocks();
618e5dd7070Spatrick if (NumBlocksInAnalyzedFunctions > 0)
619e5dd7070Spatrick PercentReachableBlocks =
620e5dd7070Spatrick (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
621e5dd7070Spatrick NumBlocksInAnalyzedFunctions;
622e5dd7070Spatrick }
623e5dd7070Spatrick
624e5dd7070Spatrick AnalysisConsumer::AnalysisMode
getModeForDecl(Decl * D,AnalysisMode Mode)625e5dd7070Spatrick AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
626e5dd7070Spatrick if (!Opts->AnalyzeSpecificFunction.empty() &&
627a9ac8606Spatrick AnalysisDeclContext::getFunctionName(D) != Opts->AnalyzeSpecificFunction)
628e5dd7070Spatrick return AM_None;
629e5dd7070Spatrick
630e5dd7070Spatrick // Unless -analyze-all is specified, treat decls differently depending on
631e5dd7070Spatrick // where they came from:
632e5dd7070Spatrick // - Main source file: run both path-sensitive and non-path-sensitive checks.
633e5dd7070Spatrick // - Header files: run non-path-sensitive checks only.
634e5dd7070Spatrick // - System headers: don't run any checks.
635*12c85518Srobert if (Opts->AnalyzeAll)
636*12c85518Srobert return Mode;
637*12c85518Srobert
638*12c85518Srobert const SourceManager &SM = Ctx->getSourceManager();
639*12c85518Srobert
640*12c85518Srobert const SourceLocation Loc = [&SM](Decl *D) -> SourceLocation {
641e5dd7070Spatrick const Stmt *Body = D->getBody();
642e5dd7070Spatrick SourceLocation SL = Body ? Body->getBeginLoc() : D->getLocation();
643*12c85518Srobert return SM.getExpansionLoc(SL);
644*12c85518Srobert }(D);
645e5dd7070Spatrick
646*12c85518Srobert // Ignore system headers.
647*12c85518Srobert if (Loc.isInvalid() || SM.isInSystemHeader(Loc))
648e5dd7070Spatrick return AM_None;
649*12c85518Srobert
650*12c85518Srobert // Disable path sensitive analysis in user-headers.
651*12c85518Srobert if (!Mgr->isInCodeFile(Loc))
652e5dd7070Spatrick return Mode & ~AM_Path;
653e5dd7070Spatrick
654e5dd7070Spatrick return Mode;
655e5dd7070Spatrick }
656e5dd7070Spatrick
HandleCode(Decl * D,AnalysisMode Mode,ExprEngine::InliningModes IMode,SetOfConstDecls * VisitedCallees)657e5dd7070Spatrick void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
658e5dd7070Spatrick ExprEngine::InliningModes IMode,
659e5dd7070Spatrick SetOfConstDecls *VisitedCallees) {
660e5dd7070Spatrick if (!D->hasBody())
661e5dd7070Spatrick return;
662e5dd7070Spatrick Mode = getModeForDecl(D, Mode);
663e5dd7070Spatrick if (Mode == AM_None)
664e5dd7070Spatrick return;
665e5dd7070Spatrick
666e5dd7070Spatrick // Clear the AnalysisManager of old AnalysisDeclContexts.
667e5dd7070Spatrick Mgr->ClearContexts();
668e5dd7070Spatrick // Ignore autosynthesized code.
669e5dd7070Spatrick if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized())
670e5dd7070Spatrick return;
671e5dd7070Spatrick
672e5dd7070Spatrick CFG *DeclCFG = Mgr->getCFG(D);
673e5dd7070Spatrick if (DeclCFG)
674e5dd7070Spatrick MaxCFGSize.updateMax(DeclCFG->size());
675e5dd7070Spatrick
676a9ac8606Spatrick DisplayFunction(D, Mode, IMode);
677e5dd7070Spatrick BugReporter BR(*Mgr);
678e5dd7070Spatrick
679e5dd7070Spatrick if (Mode & AM_Syntax) {
680a9ac8606Spatrick llvm::TimeRecord CheckerStartTime;
681a9ac8606Spatrick if (SyntaxCheckTimer) {
682a9ac8606Spatrick CheckerStartTime = SyntaxCheckTimer->getTotalTime();
683e5dd7070Spatrick SyntaxCheckTimer->startTimer();
684a9ac8606Spatrick }
685e5dd7070Spatrick checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
686a9ac8606Spatrick if (SyntaxCheckTimer) {
687e5dd7070Spatrick SyntaxCheckTimer->stopTimer();
688a9ac8606Spatrick llvm::TimeRecord CheckerEndTime = SyntaxCheckTimer->getTotalTime();
689a9ac8606Spatrick CheckerEndTime -= CheckerStartTime;
690a9ac8606Spatrick DisplayTime(CheckerEndTime);
691a9ac8606Spatrick }
692e5dd7070Spatrick }
693e5dd7070Spatrick
694e5dd7070Spatrick BR.FlushReports();
695e5dd7070Spatrick
696e5dd7070Spatrick if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
697e5dd7070Spatrick RunPathSensitiveChecks(D, IMode, VisitedCallees);
698e5dd7070Spatrick if (IMode != ExprEngine::Inline_Minimal)
699e5dd7070Spatrick NumFunctionsAnalyzed++;
700e5dd7070Spatrick }
701e5dd7070Spatrick }
702e5dd7070Spatrick
703e5dd7070Spatrick //===----------------------------------------------------------------------===//
704e5dd7070Spatrick // Path-sensitive checking.
705e5dd7070Spatrick //===----------------------------------------------------------------------===//
706e5dd7070Spatrick
RunPathSensitiveChecks(Decl * D,ExprEngine::InliningModes IMode,SetOfConstDecls * VisitedCallees)707e5dd7070Spatrick void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
708e5dd7070Spatrick ExprEngine::InliningModes IMode,
709e5dd7070Spatrick SetOfConstDecls *VisitedCallees) {
710e5dd7070Spatrick // Construct the analysis engine. First check if the CFG is valid.
711e5dd7070Spatrick // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
712e5dd7070Spatrick if (!Mgr->getCFG(D))
713e5dd7070Spatrick return;
714e5dd7070Spatrick
715e5dd7070Spatrick // See if the LiveVariables analysis scales.
716e5dd7070Spatrick if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
717e5dd7070Spatrick return;
718e5dd7070Spatrick
719e5dd7070Spatrick ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
720e5dd7070Spatrick
721e5dd7070Spatrick // Execute the worklist algorithm.
722a9ac8606Spatrick llvm::TimeRecord ExprEngineStartTime;
723a9ac8606Spatrick if (ExprEngineTimer) {
724a9ac8606Spatrick ExprEngineStartTime = ExprEngineTimer->getTotalTime();
725e5dd7070Spatrick ExprEngineTimer->startTimer();
726a9ac8606Spatrick }
727e5dd7070Spatrick Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
728e5dd7070Spatrick Mgr->options.MaxNodesPerTopLevelFunction);
729a9ac8606Spatrick if (ExprEngineTimer) {
730e5dd7070Spatrick ExprEngineTimer->stopTimer();
731a9ac8606Spatrick llvm::TimeRecord ExprEngineEndTime = ExprEngineTimer->getTotalTime();
732a9ac8606Spatrick ExprEngineEndTime -= ExprEngineStartTime;
733a9ac8606Spatrick DisplayTime(ExprEngineEndTime);
734a9ac8606Spatrick }
735e5dd7070Spatrick
736e5dd7070Spatrick if (!Mgr->options.DumpExplodedGraphTo.empty())
737e5dd7070Spatrick Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo);
738e5dd7070Spatrick
739e5dd7070Spatrick // Visualize the exploded graph.
740e5dd7070Spatrick if (Mgr->options.visualizeExplodedGraphWithGraphViz)
741e5dd7070Spatrick Eng.ViewGraph(Mgr->options.TrimGraph);
742e5dd7070Spatrick
743e5dd7070Spatrick // Display warnings.
744e5dd7070Spatrick if (BugReporterTimer)
745e5dd7070Spatrick BugReporterTimer->startTimer();
746e5dd7070Spatrick Eng.getBugReporter().FlushReports();
747e5dd7070Spatrick if (BugReporterTimer)
748e5dd7070Spatrick BugReporterTimer->stopTimer();
749e5dd7070Spatrick }
750e5dd7070Spatrick
751e5dd7070Spatrick //===----------------------------------------------------------------------===//
752e5dd7070Spatrick // AnalysisConsumer creation.
753e5dd7070Spatrick //===----------------------------------------------------------------------===//
754e5dd7070Spatrick
755e5dd7070Spatrick std::unique_ptr<AnalysisASTConsumer>
CreateAnalysisConsumer(CompilerInstance & CI)756e5dd7070Spatrick ento::CreateAnalysisConsumer(CompilerInstance &CI) {
757e5dd7070Spatrick // Disable the effects of '-Werror' when using the AnalysisConsumer.
758e5dd7070Spatrick CI.getPreprocessor().getDiagnostics().setWarningsAsErrors(false);
759e5dd7070Spatrick
760e5dd7070Spatrick AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
761e5dd7070Spatrick bool hasModelPath = analyzerOpts->Config.count("model-path") > 0;
762e5dd7070Spatrick
763e5dd7070Spatrick return std::make_unique<AnalysisConsumer>(
764e5dd7070Spatrick CI, CI.getFrontendOpts().OutputFile, analyzerOpts,
765e5dd7070Spatrick CI.getFrontendOpts().Plugins,
766e5dd7070Spatrick hasModelPath ? new ModelInjector(CI) : nullptr);
767e5dd7070Spatrick }
768