xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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