1ecd3334dSArgyrios Kyrtzidis //===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
2ecd3334dSArgyrios Kyrtzidis //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ecd3334dSArgyrios Kyrtzidis //
7ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
8ecd3334dSArgyrios Kyrtzidis //
9ecd3334dSArgyrios Kyrtzidis // "Meta" ASTConsumer for running different source analyses.
10ecd3334dSArgyrios Kyrtzidis //
11ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
12ecd3334dSArgyrios Kyrtzidis 
136de39492SAlexander Kornienko #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
140d9593ddSChandler Carruth #include "ModelInjector.h"
15ecd3334dSArgyrios Kyrtzidis #include "clang/AST/Decl.h"
16ecd3334dSArgyrios Kyrtzidis #include "clang/AST/DeclCXX.h"
17ecd3334dSArgyrios Kyrtzidis #include "clang/AST/DeclObjC.h"
18cfeacf56SBenjamin Kramer #include "clang/AST/RecursiveASTVisitor.h"
193a02247dSChandler Carruth #include "clang/Analysis/Analyses/LiveVariables.h"
20ecd3334dSArgyrios Kyrtzidis #include "clang/Analysis/CFG.h"
21eee91107SAnna Zaks #include "clang/Analysis/CallGraph.h"
220d9593ddSChandler Carruth #include "clang/Analysis/CodeInjector.h"
237c58fb6bSBalazs Benics #include "clang/Analysis/MacroExpansionContext.h"
24f69c74dbSCharusso #include "clang/Analysis/PathDiagnostic.h"
25ecd3334dSArgyrios Kyrtzidis #include "clang/Basic/SourceManager.h"
268b9b3bd0SIlya Biryukov #include "clang/CrossTU/CrossTranslationUnit.h"
270d9593ddSChandler Carruth #include "clang/Frontend/CompilerInstance.h"
28ecd3334dSArgyrios Kyrtzidis #include "clang/Lex/Preprocessor.h"
29f69c74dbSCharusso #include "clang/Rewrite/Core/Rewriter.h"
303a02247dSChandler Carruth #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
313a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
323a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
333a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/CheckerManager.h"
349c4b2225SAlexander Belyaev #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
353a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
363a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
3744eb4f66SChandler Carruth #include "llvm/ADT/PostOrderIterator.h"
389873ef40SBalazs Benics #include "llvm/ADT/ScopeExit.h"
39b0286540SAnna Zaks #include "llvm/ADT/Statistic.h"
404168ee73SRafael Espindola #include "llvm/Support/FileSystem.h"
413a02247dSChandler Carruth #include "llvm/Support/Path.h"
423a02247dSChandler Carruth #include "llvm/Support/Program.h"
433a02247dSChandler Carruth #include "llvm/Support/Timer.h"
443a02247dSChandler Carruth #include "llvm/Support/raw_ostream.h"
45dfca6f97SAhmed Charles #include <memory>
46ca70ed53SAnna Zaks #include <queue>
47cfeacf56SBenjamin Kramer #include <utility>
48ca70ed53SAnna Zaks 
49ecd3334dSArgyrios Kyrtzidis using namespace clang;
50ecd3334dSArgyrios Kyrtzidis using namespace ento;
51ecd3334dSArgyrios Kyrtzidis 
5210346667SChandler Carruth #define DEBUG_TYPE "AnalysisConsumer"
5310346667SChandler Carruth 
54394d07eaSAnna Zaks STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
555d484780SAnna Zaks STATISTIC(NumFunctionsAnalyzed,
56ad3704c9SAnna Zaks                       "The # of functions and blocks analyzed (as top level "
57ad3704c9SAnna Zaks                       "with inlining turned on).");
58cc24e45eSAnna Zaks STATISTIC(NumBlocksInAnalyzedFunctions,
59cc24e45eSAnna Zaks                       "The # of basic blocks in the analyzed functions.");
602a639858SGeorge Karpenkov STATISTIC(NumVisitedBlocksInAnalyzedFunctions,
612a639858SGeorge Karpenkov           "The # of visited basic blocks in the analyzed functions.");
62cc24e45eSAnna Zaks STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
6340b87fc1SAnna Zaks STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
64eee91107SAnna Zaks 
65ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
66ecd3334dSArgyrios Kyrtzidis // AnalysisConsumer declaration.
67ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
68ecd3334dSArgyrios Kyrtzidis 
69ecd3334dSArgyrios Kyrtzidis namespace {
70ecd3334dSArgyrios Kyrtzidis 
717a712ceaSAlexander Kornienko class AnalysisConsumer : public AnalysisASTConsumer,
7250668455SRichard Smith                          public RecursiveASTVisitor<AnalysisConsumer> {
73d8665b3dSJordan Rose   enum {
74d8665b3dSJordan Rose     AM_None = 0,
75d8665b3dSJordan Rose     AM_Syntax = 0x1,
76d8665b3dSJordan Rose     AM_Path = 0x2
7714189514SAnna Zaks   };
78d8665b3dSJordan Rose   typedef unsigned AnalysisMode;
7914189514SAnna Zaks 
8014189514SAnna Zaks   /// Mode of the analyzes while recursively visiting Decls.
8114189514SAnna Zaks   AnalysisMode RecVisitorMode;
8214189514SAnna Zaks   /// Bug Reporter to use while recursively visiting Decls.
8314189514SAnna Zaks   BugReporter *RecVisitorBR;
8414189514SAnna Zaks 
85d00ed8e2SAlexander Kornienko   std::vector<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns;
86d00ed8e2SAlexander Kornienko 
87ecd3334dSArgyrios Kyrtzidis public:
88ecd3334dSArgyrios Kyrtzidis   ASTContext *Ctx;
8938ab3b87SCharusso   Preprocessor &PP;
90ecd3334dSArgyrios Kyrtzidis   const std::string OutDir;
9140ea0eaaSTed Kremenek   AnalyzerOptionsRef Opts;
9259cce71aSJordy Rose   ArrayRef<std::string> Plugins;
93eeccb30bSTed Kremenek   CodeInjector *Injector;
948b9b3bd0SIlya Biryukov   cross_tu::CrossTranslationUnitContext CTU;
95ecd3334dSArgyrios Kyrtzidis 
969fc8faf9SAdrian Prantl   /// Stores the declarations from the local translation unit.
978e078528SAnna Zaks   /// Note, we pre-compute the local declarations at parse time as an
988e078528SAnna Zaks   /// optimization to make sure we do not deserialize everything from disk.
998e078528SAnna Zaks   /// The local declaration to all declarations ratio might be very small when
1008e078528SAnna Zaks   /// working with a PCH file.
1018e078528SAnna Zaks   SetOfDecls LocalTUDecls;
1028e078528SAnna Zaks 
1037c58fb6bSBalazs Benics   MacroExpansionContext MacroExpansions;
1047c58fb6bSBalazs Benics 
1059bf9af92STed Kremenek   // Set of PathDiagnosticConsumers.  Owned by AnalysisManager.
1069bf9af92STed Kremenek   PathDiagnosticConsumers PathConsumers;
107ecd3334dSArgyrios Kyrtzidis 
108ecd3334dSArgyrios Kyrtzidis   StoreManagerCreator CreateStoreMgr;
109ecd3334dSArgyrios Kyrtzidis   ConstraintManagerCreator CreateConstraintMgr;
110ecd3334dSArgyrios Kyrtzidis 
111b8984329SAhmed Charles   std::unique_ptr<CheckerManager> checkerMgr;
112b8984329SAhmed Charles   std::unique_ptr<AnalysisManager> Mgr;
113ecd3334dSArgyrios Kyrtzidis 
1149bd4be96SAnna Zaks   /// Time the analyzes time of each translation unit.
1155a755b33SGeorge Karpenkov   std::unique_ptr<llvm::TimerGroup> AnalyzerTimers;
116c48be7fcSArtem Dergachev   std::unique_ptr<llvm::Timer> SyntaxCheckTimer;
117c48be7fcSArtem Dergachev   std::unique_ptr<llvm::Timer> ExprEngineTimer;
118c48be7fcSArtem Dergachev   std::unique_ptr<llvm::Timer> BugReporterTimer;
1199bd4be96SAnna Zaks 
12054fd4a07SAnna Zaks   /// The information about analyzed functions shared throughout the
12154fd4a07SAnna Zaks   /// translation unit.
12254fd4a07SAnna Zaks   FunctionSummariesTy FunctionSummaries;
12354fd4a07SAnna Zaks 
AnalysisConsumer(CompilerInstance & CI,const std::string & outdir,AnalyzerOptionsRef opts,ArrayRef<std::string> plugins,CodeInjector * injector)1248b9b3bd0SIlya Biryukov   AnalysisConsumer(CompilerInstance &CI, const std::string &outdir,
125cfeacf56SBenjamin Kramer                    AnalyzerOptionsRef opts, ArrayRef<std::string> plugins,
126eeccb30bSTed Kremenek                    CodeInjector *injector)
1278b9b3bd0SIlya Biryukov       : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),
1288b9b3bd0SIlya Biryukov         PP(CI.getPreprocessor()), OutDir(outdir), Opts(std::move(opts)),
1297c58fb6bSBalazs Benics         Plugins(plugins), Injector(injector), CTU(CI),
1307c58fb6bSBalazs Benics         MacroExpansions(CI.getLangOpts()) {
131ecd3334dSArgyrios Kyrtzidis     DigestAnalyzerOptions();
132cad9b7f7SSharmaRithik     if (Opts->AnalyzerDisplayProgress || Opts->PrintStats ||
133cad9b7f7SSharmaRithik         Opts->ShouldSerializeStats) {
1342b3d49b6SJonas Devlieghere       AnalyzerTimers = std::make_unique<llvm::TimerGroup>(
1355a755b33SGeorge Karpenkov           "analyzer", "Analyzer timers");
1362b3d49b6SJonas Devlieghere       SyntaxCheckTimer = std::make_unique<llvm::Timer>(
137c48be7fcSArtem Dergachev           "syntaxchecks", "Syntax-based analysis time", *AnalyzerTimers);
1382b3d49b6SJonas Devlieghere       ExprEngineTimer = std::make_unique<llvm::Timer>(
139c48be7fcSArtem Dergachev           "exprengine", "Path exploration time", *AnalyzerTimers);
1402b3d49b6SJonas Devlieghere       BugReporterTimer = std::make_unique<llvm::Timer>(
141c48be7fcSArtem Dergachev           "bugreporter", "Path-sensitive report post-processing time",
142c48be7fcSArtem Dergachev           *AnalyzerTimers);
143cad9b7f7SSharmaRithik     }
144cad9b7f7SSharmaRithik 
145cad9b7f7SSharmaRithik     if (Opts->PrintStats || Opts->ShouldSerializeStats) {
14617d4bd3dSKazu Hirata       llvm::EnableStatistics(/* DoPrintOnExit= */ false);
1479bd4be96SAnna Zaks     }
1487c58fb6bSBalazs Benics 
1497c58fb6bSBalazs Benics     if (Opts->ShouldDisplayMacroExpansions)
1507c58fb6bSBalazs Benics       MacroExpansions.registerForPreprocessor(PP);
1519bd4be96SAnna Zaks   }
1529bd4be96SAnna Zaks 
~AnalysisConsumer()15334eb2072SAlexander Kornienko   ~AnalysisConsumer() override {
154abb6eea1SMatthias Braun     if (Opts->PrintStats) {
155abb6eea1SMatthias Braun       llvm::PrintStatistics();
156abb6eea1SMatthias Braun     }
157ecd3334dSArgyrios Kyrtzidis   }
158ecd3334dSArgyrios Kyrtzidis 
DigestAnalyzerOptions()159ecd3334dSArgyrios Kyrtzidis   void DigestAnalyzerOptions() {
16040ea0eaaSTed Kremenek     switch (Opts->AnalysisDiagOpt) {
1617bf871c3SKirstóf Umann     case PD_NONE:
1627bf871c3SKirstóf Umann       break;
163367843a0SJordan Rose #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN)                    \
1647a712ceaSAlexander Kornienko   case PD_##NAME:                                                              \
1657c58fb6bSBalazs Benics     CREATEFN(Opts->getDiagOpts(), PathConsumers, OutDir, PP, CTU,              \
1667c58fb6bSBalazs Benics              MacroExpansions);                                                 \
1673a081a03STed Kremenek     break;
1689c4b2225SAlexander Belyaev #include "clang/StaticAnalyzer/Core/Analyses.def"
1697bf871c3SKirstóf Umann     default:
170d4cf4c66SAaron Ballman       llvm_unreachable("Unknown analyzer output type!");
1717a712ceaSAlexander Kornienko     }
172ecd3334dSArgyrios Kyrtzidis 
173ecd3334dSArgyrios Kyrtzidis     // Create the analyzer component creators.
174*ffe7950eSBalazs Benics     CreateStoreMgr = &CreateRegionStoreManager;
175ecd3334dSArgyrios Kyrtzidis 
17640ea0eaaSTed Kremenek     switch (Opts->AnalysisConstraintsOpt) {
177ecd3334dSArgyrios Kyrtzidis     default:
178297176c3SAnna Zaks       llvm_unreachable("Unknown constraint manager.");
179ecd3334dSArgyrios Kyrtzidis #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN)     \
180ecd3334dSArgyrios Kyrtzidis       case NAME##Model: CreateConstraintMgr = CREATEFN; break;
181a5770cd1STed Kremenek #include "clang/StaticAnalyzer/Core/Analyses.def"
182ecd3334dSArgyrios Kyrtzidis     }
183ecd3334dSArgyrios Kyrtzidis   }
184ecd3334dSArgyrios Kyrtzidis 
DisplayTime(llvm::TimeRecord & Time)185cad9b7f7SSharmaRithik   void DisplayTime(llvm::TimeRecord &Time) {
186cad9b7f7SSharmaRithik     if (!Opts->AnalyzerDisplayProgress) {
187cad9b7f7SSharmaRithik       return;
188cad9b7f7SSharmaRithik     }
189cad9b7f7SSharmaRithik     llvm::errs() << " : " << llvm::format("%1.1f", Time.getWallTime() * 1000)
190cad9b7f7SSharmaRithik                  << " ms\n";
191cad9b7f7SSharmaRithik   }
192cad9b7f7SSharmaRithik 
DisplayFunction(const Decl * D,AnalysisMode Mode,ExprEngine::InliningModes IMode)193e9eb13abSAnna Zaks   void DisplayFunction(const Decl *D, AnalysisMode Mode,
194e9eb13abSAnna Zaks                        ExprEngine::InliningModes IMode) {
19540ea0eaaSTed Kremenek     if (!Opts->AnalyzerDisplayProgress)
196ecd3334dSArgyrios Kyrtzidis       return;
197ecd3334dSArgyrios Kyrtzidis 
198ecd3334dSArgyrios Kyrtzidis     SourceManager &SM = Mgr->getASTContext().getSourceManager();
199ecd3334dSArgyrios Kyrtzidis     PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
200ecd3334dSArgyrios Kyrtzidis     if (Loc.isValid()) {
20114189514SAnna Zaks       llvm::errs() << "ANALYZE";
202d8665b3dSJordan Rose 
203d8665b3dSJordan Rose       if (Mode == AM_Syntax)
204d8665b3dSJordan Rose         llvm::errs() << " (Syntax)";
205e9eb13abSAnna Zaks       else if (Mode == AM_Path) {
206e9eb13abSAnna Zaks         llvm::errs() << " (Path, ";
207e9eb13abSAnna Zaks         switch (IMode) {
208b13d21b6SAnna Zaks         case ExprEngine::Inline_Minimal:
209b13d21b6SAnna Zaks           llvm::errs() << " Inline_Minimal";
210e9eb13abSAnna Zaks           break;
211b13d21b6SAnna Zaks         case ExprEngine::Inline_Regular:
212b13d21b6SAnna Zaks           llvm::errs() << " Inline_Regular";
213e9eb13abSAnna Zaks           break;
214e9eb13abSAnna Zaks         }
215e9eb13abSAnna Zaks         llvm::errs() << ")";
2167bf871c3SKirstóf Umann       } else
217d8665b3dSJordan Rose         assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");
218d8665b3dSJordan Rose 
219d3e14fafSBalazs Benics       llvm::errs() << ": " << Loc.getFilename() << ' '
220cad9b7f7SSharmaRithik                    << AnalysisDeclContext::getFunctionName(D);
221ecd3334dSArgyrios Kyrtzidis     }
222ecd3334dSArgyrios Kyrtzidis   }
223ecd3334dSArgyrios Kyrtzidis 
Initialize(ASTContext & Context)224fb6b25b5SCraig Topper   void Initialize(ASTContext &Context) override {
225ecd3334dSArgyrios Kyrtzidis     Ctx = &Context;
2264dc84729SKirstóf Umann     checkerMgr = std::make_unique<CheckerManager>(*Ctx, *Opts, PP, Plugins,
2272aac0c47SKristóf Umann                                                   CheckerRegistrationFns);
228eeccb30bSTed Kremenek 
22938ab3b87SCharusso     Mgr = std::make_unique<AnalysisManager>(*Ctx, PP, PathConsumers,
23038ab3b87SCharusso                                             CreateStoreMgr, CreateConstraintMgr,
2316b9d7c9dSDmitri Gribenko                                             checkerMgr.get(), *Opts, Injector);
232ecd3334dSArgyrios Kyrtzidis   }
233ecd3334dSArgyrios Kyrtzidis 
2349fc8faf9SAdrian Prantl   /// Store the top level decls in the set to be processed later on.
2358e078528SAnna Zaks   /// (Doing this pre-processing avoids deserialization of data from PCH.)
236fb6b25b5SCraig Topper   bool HandleTopLevelDecl(DeclGroupRef D) override;
237fb6b25b5SCraig Topper   void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;
2388e078528SAnna Zaks 
239fb6b25b5SCraig Topper   void HandleTranslationUnit(ASTContext &C) override;
240ecd3334dSArgyrios Kyrtzidis 
2419fc8faf9SAdrian Prantl   /// Determine which inlining mode should be used when this function is
242b13d21b6SAnna Zaks   /// analyzed. This allows to redefine the default inlining policies when
243b13d21b6SAnna Zaks   /// analyzing a given function.
2445d484780SAnna Zaks   ExprEngine::InliningModes
245fe659987SAlexander Kornienko     getInliningModeForFunction(const Decl *D, const SetOfConstDecls &Visited);
2465d484780SAnna Zaks 
2479fc8faf9SAdrian Prantl   /// Build the call graph for all the top level decls of this TU and
2488e078528SAnna Zaks   /// use it to define the order in which the functions should be visited.
24985c8c819SJordan Rose   void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);
25014189514SAnna Zaks 
2519fc8faf9SAdrian Prantl   /// Run analyzes(syntax or path sensitive) on the given function.
25214189514SAnna Zaks   /// \param Mode - determines if we are requesting syntax only or path
25314189514SAnna Zaks   /// sensitive only analysis.
25414189514SAnna Zaks   /// \param VisitedCallees - The output parameter, which is populated with the
25514189514SAnna Zaks   /// set of functions which should be considered analyzed after analyzing the
25614189514SAnna Zaks   /// given root function.
2578e078528SAnna Zaks   void HandleCode(Decl *D, AnalysisMode Mode,
258b13d21b6SAnna Zaks                   ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal,
2590dbb783cSCraig Topper                   SetOfConstDecls *VisitedCallees = nullptr);
26014189514SAnna Zaks 
2615d484780SAnna Zaks   void RunPathSensitiveChecks(Decl *D,
2625d484780SAnna Zaks                               ExprEngine::InliningModes IMode,
2635d484780SAnna Zaks                               SetOfConstDecls *VisitedCallees);
26414189514SAnna Zaks 
26514189514SAnna Zaks   /// Visitors for the RecursiveASTVisitor.
shouldWalkTypesOfTypeLocs() const266e7e7c9ebSAnna Zaks   bool shouldWalkTypesOfTypeLocs() const { return false; }
26714189514SAnna Zaks 
26814189514SAnna Zaks   /// Handle callbacks for arbitrary Decls.
VisitDecl(Decl * D)26914189514SAnna Zaks   bool VisitDecl(Decl *D) {
270d8665b3dSJordan Rose     AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
271c48be7fcSArtem Dergachev     if (Mode & AM_Syntax) {
272c48be7fcSArtem Dergachev       if (SyntaxCheckTimer)
273c48be7fcSArtem Dergachev         SyntaxCheckTimer->startTimer();
27414189514SAnna Zaks       checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
275c48be7fcSArtem Dergachev       if (SyntaxCheckTimer)
276c48be7fcSArtem Dergachev         SyntaxCheckTimer->stopTimer();
277c48be7fcSArtem Dergachev     }
27814189514SAnna Zaks     return true;
27914189514SAnna Zaks   }
28014189514SAnna Zaks 
VisitVarDecl(VarDecl * VD)281850361f6SRafael Stahl   bool VisitVarDecl(VarDecl *VD) {
282850361f6SRafael Stahl     if (!Opts->IsNaiveCTUEnabled)
283850361f6SRafael Stahl       return true;
284850361f6SRafael Stahl 
285850361f6SRafael Stahl     if (VD->hasExternalStorage() || VD->isStaticDataMember()) {
286e63b81d1SGabor Marton       if (!cross_tu::shouldImport(VD, *Ctx))
287850361f6SRafael Stahl         return true;
288850361f6SRafael Stahl     } else {
289850361f6SRafael Stahl       // Cannot be initialized in another TU.
290850361f6SRafael Stahl       return true;
291850361f6SRafael Stahl     }
292850361f6SRafael Stahl 
293850361f6SRafael Stahl     if (VD->getAnyInitializer())
294850361f6SRafael Stahl       return true;
295850361f6SRafael Stahl 
296850361f6SRafael Stahl     llvm::Expected<const VarDecl *> CTUDeclOrError =
297850361f6SRafael Stahl       CTU.getCrossTUDefinition(VD, Opts->CTUDir, Opts->CTUIndexName,
298850361f6SRafael Stahl                                Opts->DisplayCTUProgress);
299850361f6SRafael Stahl 
300850361f6SRafael Stahl     if (!CTUDeclOrError) {
301850361f6SRafael Stahl       handleAllErrors(CTUDeclOrError.takeError(),
302850361f6SRafael Stahl                       [&](const cross_tu::IndexError &IE) {
303850361f6SRafael Stahl                         CTU.emitCrossTUDiagnostics(IE);
304850361f6SRafael Stahl                       });
305850361f6SRafael Stahl     }
306850361f6SRafael Stahl 
307850361f6SRafael Stahl     return true;
308850361f6SRafael Stahl   }
309850361f6SRafael Stahl 
VisitFunctionDecl(FunctionDecl * FD)31014189514SAnna Zaks   bool VisitFunctionDecl(FunctionDecl *FD) {
31114189514SAnna Zaks     IdentifierInfo *II = FD->getIdentifier();
31214189514SAnna Zaks     if (II && II->getName().startswith("__inline"))
31314189514SAnna Zaks       return true;
31414189514SAnna Zaks 
31514189514SAnna Zaks     // We skip function template definitions, as their semantics is
31614189514SAnna Zaks     // only determined when they are instantiated.
31714189514SAnna Zaks     if (FD->isThisDeclarationADefinition() &&
31814189514SAnna Zaks         !FD->isDependentContext()) {
3195d484780SAnna Zaks       assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
32014189514SAnna Zaks       HandleCode(FD, RecVisitorMode);
32114189514SAnna Zaks     }
32214189514SAnna Zaks     return true;
32314189514SAnna Zaks   }
32414189514SAnna Zaks 
VisitObjCMethodDecl(ObjCMethodDecl * MD)32514189514SAnna Zaks   bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
3265d484780SAnna Zaks     if (MD->isThisDeclarationADefinition()) {
3275d484780SAnna Zaks       assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
32814189514SAnna Zaks       HandleCode(MD, RecVisitorMode);
3295d484780SAnna Zaks     }
33014189514SAnna Zaks     return true;
33114189514SAnna Zaks   }
3328e078528SAnna Zaks 
VisitBlockDecl(BlockDecl * BD)3335c32dfc5SAnna Zaks   bool VisitBlockDecl(BlockDecl *BD) {
3345c32dfc5SAnna Zaks     if (BD->hasBody()) {
3355c32dfc5SAnna Zaks       assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
3366e644abdSDevin Coughlin       // Since we skip function template definitions, we should skip blocks
3376e644abdSDevin Coughlin       // declared in those functions as well.
3386e644abdSDevin Coughlin       if (!BD->isDependentContext()) {
3395c32dfc5SAnna Zaks         HandleCode(BD, RecVisitorMode);
3405c32dfc5SAnna Zaks       }
3416e644abdSDevin Coughlin     }
3425c32dfc5SAnna Zaks     return true;
3435c32dfc5SAnna Zaks   }
3445c32dfc5SAnna Zaks 
AddDiagnosticConsumer(PathDiagnosticConsumer * Consumer)34534eb2072SAlexander Kornienko   void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) override {
3467a712ceaSAlexander Kornienko     PathConsumers.push_back(Consumer);
3477a712ceaSAlexander Kornienko   }
3487a712ceaSAlexander Kornienko 
AddCheckerRegistrationFn(std::function<void (CheckerRegistry &)> Fn)349d00ed8e2SAlexander Kornienko   void AddCheckerRegistrationFn(std::function<void(CheckerRegistry&)> Fn) override {
350d00ed8e2SAlexander Kornienko     CheckerRegistrationFns.push_back(std::move(Fn));
351d00ed8e2SAlexander Kornienko   }
352d00ed8e2SAlexander Kornienko 
3538e078528SAnna Zaks private:
3548e078528SAnna Zaks   void storeTopLevelDecls(DeclGroupRef DG);
3558e078528SAnna Zaks 
3569fc8faf9SAdrian Prantl   /// Check if we should skip (not analyze) the given function.
357d8665b3dSJordan Rose   AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);
3581d3e49e7SGeorge Karpenkov   void runAnalysisOnTranslationUnit(ASTContext &C);
3598e078528SAnna Zaks 
3601d3e49e7SGeorge Karpenkov   /// Print \p S to stderr if \c Opts->AnalyzerDisplayProgress is set.
3611d3e49e7SGeorge Karpenkov   void reportAnalyzerProgress(StringRef S);
3627bf871c3SKirstóf Umann }; // namespace
363ecd3334dSArgyrios Kyrtzidis } // end anonymous namespace
364ecd3334dSArgyrios Kyrtzidis 
36514189514SAnna Zaks 
366ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
367ecd3334dSArgyrios Kyrtzidis // AnalysisConsumer implementation.
368ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
HandleTopLevelDecl(DeclGroupRef DG)3698e078528SAnna Zaks bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
3708e078528SAnna Zaks   storeTopLevelDecls(DG);
3718e078528SAnna Zaks   return true;
3728e078528SAnna Zaks }
3738e078528SAnna Zaks 
HandleTopLevelDeclInObjCContainer(DeclGroupRef DG)3748e078528SAnna Zaks void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
3758e078528SAnna Zaks   storeTopLevelDecls(DG);
3768e078528SAnna Zaks }
3778e078528SAnna Zaks 
storeTopLevelDecls(DeclGroupRef DG)3788e078528SAnna Zaks void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
37965adf7c2SJun Zhang   for (auto &I : DG) {
3808e078528SAnna Zaks 
3818e078528SAnna Zaks     // Skip ObjCMethodDecl, wait for the objc container to avoid
3828e078528SAnna Zaks     // analyzing twice.
38365adf7c2SJun Zhang     if (isa<ObjCMethodDecl>(I))
3848e078528SAnna Zaks       continue;
3858e078528SAnna Zaks 
38665adf7c2SJun Zhang     LocalTUDecls.push_back(I);
3878e078528SAnna Zaks   }
3888e078528SAnna Zaks }
3898e078528SAnna Zaks 
shouldSkipFunction(const Decl * D,const SetOfConstDecls & Visited,const SetOfConstDecls & VisitedAsTopLevel)3905f2af81eSAnna Zaks static bool shouldSkipFunction(const Decl *D,
391fe659987SAlexander Kornienko                                const SetOfConstDecls &Visited,
392fe659987SAlexander Kornienko                                const SetOfConstDecls &VisitedAsTopLevel) {
3935f2af81eSAnna Zaks   if (VisitedAsTopLevel.count(D))
3945d484780SAnna Zaks     return true;
3955d484780SAnna Zaks 
39659a960b8SGabor Marton   // Skip analysis of inheriting constructors as top-level functions. These
39759a960b8SGabor Marton   // constructors don't even have a body written down in the code, so even if
39859a960b8SGabor Marton   // we find a bug, we won't be able to display it.
39959a960b8SGabor Marton   if (const auto *CD = dyn_cast<CXXConstructorDecl>(D))
40059a960b8SGabor Marton     if (CD->isInheritingConstructor())
40159a960b8SGabor Marton       return true;
40259a960b8SGabor Marton 
4035d484780SAnna Zaks   // We want to re-analyse the functions as top level in the following cases:
404a8017ecaSAnna Zaks   // - The 'init' methods should be reanalyzed because
405a8017ecaSAnna Zaks   //   ObjCNonNilReturnValueChecker assumes that '[super init]' never returns
4065d484780SAnna Zaks   //   'nil' and unless we analyze the 'init' functions as top level, we will
4075d484780SAnna Zaks   //   not catch errors within defensive code.
408a8017ecaSAnna Zaks   // - We want to reanalyze all ObjC methods as top level to report Retain
409a8017ecaSAnna Zaks   //   Count naming convention errors more aggressively.
4105f2af81eSAnna Zaks   if (isa<ObjCMethodDecl>(D))
411a8017ecaSAnna Zaks     return false;
412f57f90dfSDevin Coughlin   // We also want to reanalyze all C++ copy and move assignment operators to
413f57f90dfSDevin Coughlin   // separately check the two cases where 'this' aliases with the parameter and
414f57f90dfSDevin Coughlin   // where it may not. (cplusplus.SelfAssignmentChecker)
415f57f90dfSDevin Coughlin   if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
416f57f90dfSDevin Coughlin     if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())
417f57f90dfSDevin Coughlin       return false;
418f57f90dfSDevin Coughlin   }
419a8017ecaSAnna Zaks 
420a8017ecaSAnna Zaks   // Otherwise, if we visited the function before, do not reanalyze it.
4215f2af81eSAnna Zaks   return Visited.count(D);
422a8017ecaSAnna Zaks }
423a8017ecaSAnna Zaks 
4245d484780SAnna Zaks ExprEngine::InliningModes
getInliningModeForFunction(const Decl * D,const SetOfConstDecls & Visited)4255f2af81eSAnna Zaks AnalysisConsumer::getInliningModeForFunction(const Decl *D,
426fe659987SAlexander Kornienko                                              const SetOfConstDecls &Visited) {
4275d484780SAnna Zaks   // We want to reanalyze all ObjC methods as top level to report Retain
428b13d21b6SAnna Zaks   // Count naming convention errors more aggressively. But we should tune down
4295d484780SAnna Zaks   // inlining when reanalyzing an already inlined function.
430f57f90dfSDevin Coughlin   if (Visited.count(D) && isa<ObjCMethodDecl>(D)) {
4315f2af81eSAnna Zaks     const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D);
4325d484780SAnna Zaks     if (ObjCM->getMethodFamily() != OMF_init)
433b13d21b6SAnna Zaks       return ExprEngine::Inline_Minimal;
4345d484780SAnna Zaks   }
4355d484780SAnna Zaks 
436b13d21b6SAnna Zaks   return ExprEngine::Inline_Regular;
4375d484780SAnna Zaks }
4385d484780SAnna Zaks 
HandleDeclsCallGraph(const unsigned LocalTUDeclsSize)43985c8c819SJordan Rose void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
4401ee76c1bSAnna Zaks   // Build the Call Graph by adding all the top level declarations to the graph.
4412774f999SAnna Zaks   // Note: CallGraph can trigger deserialization of more items from a pch
4422774f999SAnna Zaks   // (though HandleInterestingDecl); triggering additions to LocalTUDecls.
4432774f999SAnna Zaks   // We rely on random access to add the initially processed Decls to CG.
4441ee76c1bSAnna Zaks   CallGraph CG;
4452774f999SAnna Zaks   for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
44634d89b7dSAnna Zaks     CG.addToCallGraph(LocalTUDecls[i]);
44734d89b7dSAnna Zaks   }
448eee91107SAnna Zaks 
4491ee76c1bSAnna Zaks   // Walk over all of the call graph nodes in topological order, so that we
4501ee76c1bSAnna Zaks   // analyze parents before the children. Skip the functions inlined into
4511ee76c1bSAnna Zaks   // the previously processed functions. Use external Visited set to identify
4521ee76c1bSAnna Zaks   // inlined functions. The topological order allows the "do not reanalyze
4531ee76c1bSAnna Zaks   // previously inlined function" performance heuristic to be triggered more
4541ee76c1bSAnna Zaks   // often.
4555f2af81eSAnna Zaks   SetOfConstDecls Visited;
4565f2af81eSAnna Zaks   SetOfConstDecls VisitedAsTopLevel;
4571ee76c1bSAnna Zaks   llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
45865adf7c2SJun Zhang   for (auto &N : RPOT) {
4591ee76c1bSAnna Zaks     NumFunctionTopLevel++;
460ca70ed53SAnna Zaks 
4615f2af81eSAnna Zaks     Decl *D = N->getDecl();
4621ee76c1bSAnna Zaks 
4631ee76c1bSAnna Zaks     // Skip the abstract root node.
4641ee76c1bSAnna Zaks     if (!D)
4651ee76c1bSAnna Zaks       continue;
4665f2af81eSAnna Zaks 
467ca70ed53SAnna Zaks     // Skip the functions which have been processed already or previously
468ca70ed53SAnna Zaks     // inlined.
4695f2af81eSAnna Zaks     if (shouldSkipFunction(D, Visited, VisitedAsTopLevel))
470ca70ed53SAnna Zaks       continue;
471ca70ed53SAnna Zaks 
47256b9b97cSGabor Marton     // The CallGraph might have declarations as callees. However, during CTU
47356b9b97cSGabor Marton     // the declaration might form a declaration chain with the newly imported
47456b9b97cSGabor Marton     // definition from another TU. In this case we don't want to analyze the
47556b9b97cSGabor Marton     // function definition as toplevel.
47656b9b97cSGabor Marton     if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
47756b9b97cSGabor Marton       // Calling 'hasBody' replaces 'FD' in place with the FunctionDecl
47856b9b97cSGabor Marton       // that has the body.
47956b9b97cSGabor Marton       FD->hasBody(FD);
48056b9b97cSGabor Marton       if (CTU.isImportedAsNew(FD))
48156b9b97cSGabor Marton         continue;
48256b9b97cSGabor Marton     }
48356b9b97cSGabor Marton 
484ca70ed53SAnna Zaks     // Analyze the function.
4858e078528SAnna Zaks     SetOfConstDecls VisitedCallees;
4865d484780SAnna Zaks 
4875f2af81eSAnna Zaks     HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
4880dbb783cSCraig Topper                (Mgr->options.InliningMode == All ? nullptr : &VisitedCallees));
489eee91107SAnna Zaks 
490394d07eaSAnna Zaks     // Add the visited callees to the global visited set.
491054873b0SYury Gribov     for (const Decl *Callee : VisitedCallees)
492054873b0SYury Gribov       // Decls from CallGraph are already canonical. But Decls coming from
493054873b0SYury Gribov       // CallExprs may be not. We should canonicalize them manually.
494054873b0SYury Gribov       Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
495054873b0SYury Gribov                                                  : Callee->getCanonicalDecl());
4965f2af81eSAnna Zaks     VisitedAsTopLevel.insert(D);
497394d07eaSAnna Zaks   }
49860120fb1STed Kremenek }
49960120fb1STed Kremenek 
fileContainsString(StringRef Substring,ASTContext & C)5009873ef40SBalazs Benics static bool fileContainsString(StringRef Substring, ASTContext &C) {
5011d3e49e7SGeorge Karpenkov   const SourceManager &SM = C.getSourceManager();
5021d3e49e7SGeorge Karpenkov   FileID FID = SM.getMainFileID();
503af4fb416SDuncan P. N. Exon Smith   StringRef Buffer = SM.getBufferOrFake(FID).getBuffer();
5049873ef40SBalazs Benics   return Buffer.contains(Substring);
5051d3e49e7SGeorge Karpenkov }
506d5478fddSAnna Zaks 
reportAnalyzerFunctionMisuse(const AnalyzerOptions & Opts,const ASTContext & Ctx)507b3c0014eSBalazs Benics static void reportAnalyzerFunctionMisuse(const AnalyzerOptions &Opts,
508b3c0014eSBalazs Benics                                          const ASTContext &Ctx) {
509b3c0014eSBalazs Benics   llvm::errs() << "Every top-level function was skipped.\n";
510b3c0014eSBalazs Benics 
511b3c0014eSBalazs Benics   if (!Opts.AnalyzerDisplayProgress)
512b3c0014eSBalazs Benics     llvm::errs() << "Pass the -analyzer-display-progress for tracking which "
513b3c0014eSBalazs Benics                     "functions are analyzed.\n";
514b3c0014eSBalazs Benics 
515b3c0014eSBalazs Benics   bool HasBrackets =
516b3c0014eSBalazs Benics       Opts.AnalyzeSpecificFunction.find("(") != std::string::npos;
517b3c0014eSBalazs Benics 
518b3c0014eSBalazs Benics   if (Ctx.getLangOpts().CPlusPlus && !HasBrackets) {
519b3c0014eSBalazs Benics     llvm::errs()
520b3c0014eSBalazs Benics         << "For analyzing C++ code you need to pass the function parameter "
521b3c0014eSBalazs Benics            "list: -analyze-function=\"foobar(int, _Bool)\"\n";
522b3c0014eSBalazs Benics   } else if (!Ctx.getLangOpts().CPlusPlus && HasBrackets) {
523b3c0014eSBalazs Benics     llvm::errs() << "For analyzing C code you shouldn't pass the function "
524b3c0014eSBalazs Benics                     "parameter list, only the name of the function: "
525b3c0014eSBalazs Benics                     "-analyze-function=foobar\n";
526b3c0014eSBalazs Benics   }
527b3c0014eSBalazs Benics }
528b3c0014eSBalazs Benics 
runAnalysisOnTranslationUnit(ASTContext & C)5291d3e49e7SGeorge Karpenkov void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) {
53024ffc08fSArgyrios Kyrtzidis   BugReporter BR(*Mgr);
531ecd3334dSArgyrios Kyrtzidis   TranslationUnitDecl *TU = C.getTranslationUnitDecl();
532c48be7fcSArtem Dergachev   if (SyntaxCheckTimer)
533c48be7fcSArtem Dergachev     SyntaxCheckTimer->startTimer();
53424ffc08fSArgyrios Kyrtzidis   checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
535c48be7fcSArtem Dergachev   if (SyntaxCheckTimer)
536c48be7fcSArtem Dergachev     SyntaxCheckTimer->stopTimer();
53714189514SAnna Zaks 
53814189514SAnna Zaks   // Run the AST-only checks using the order in which functions are defined.
53914189514SAnna Zaks   // If inlining is not turned on, use the simplest function order for path
54014189514SAnna Zaks   // sensitive analyzes as well.
541d8665b3dSJordan Rose   RecVisitorMode = AM_Syntax;
542d8665b3dSJordan Rose   if (!Mgr->shouldInlineCall())
543d8665b3dSJordan Rose     RecVisitorMode |= AM_Path;
54414189514SAnna Zaks   RecVisitorBR = &BR;
5458e078528SAnna Zaks 
5468e078528SAnna Zaks   // Process all the top level declarations.
547b2a47064STed Kremenek   //
5482964aac0STed Kremenek   // Note: TraverseDecl may modify LocalTUDecls, but only by appending more
5492964aac0STed Kremenek   // entries.  Thus we don't use an iterator, but rely on LocalTUDecls
5502964aac0STed Kremenek   // random access.  By doing so, we automatically compensate for iterators
5512964aac0STed Kremenek   // possibly being invalidated, although this is a bit slower.
5522774f999SAnna Zaks   const unsigned LocalTUDeclsSize = LocalTUDecls.size();
5532774f999SAnna Zaks   for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
5542964aac0STed Kremenek     TraverseDecl(LocalTUDecls[i]);
555b2a47064STed Kremenek   }
55614189514SAnna Zaks 
55714189514SAnna Zaks   if (Mgr->shouldInlineCall())
55885c8c819SJordan Rose     HandleDeclsCallGraph(LocalTUDeclsSize);
559ecd3334dSArgyrios Kyrtzidis 
560e69ab05fSTed Kremenek   // After all decls handled, run checkers on the entire TranslationUnit.
561e69ab05fSTed Kremenek   checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
56214189514SAnna Zaks 
5633fdc427fSArtem Dergachev   BR.FlushReports();
5640dbb783cSCraig Topper   RecVisitorBR = nullptr;
565b3c0014eSBalazs Benics 
566b3c0014eSBalazs Benics   // If the user wanted to analyze a specific function and the number of basic
567b3c0014eSBalazs Benics   // blocks analyzed is zero, than the user might not specified the function
568b3c0014eSBalazs Benics   // name correctly.
569b3c0014eSBalazs Benics   // FIXME: The user might have analyzed the requested function in Syntax mode,
570b3c0014eSBalazs Benics   // but we are unaware of that.
571b3c0014eSBalazs Benics   if (!Opts->AnalyzeSpecificFunction.empty() && NumFunctionsAnalyzed == 0)
572b3c0014eSBalazs Benics     reportAnalyzerFunctionMisuse(*Opts, *Ctx);
57317f57b0aSAnna Zaks }
574e69ab05fSTed Kremenek 
reportAnalyzerProgress(StringRef S)5751d3e49e7SGeorge Karpenkov void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {
5761d3e49e7SGeorge Karpenkov   if (Opts->AnalyzerDisplayProgress)
5771d3e49e7SGeorge Karpenkov     llvm::errs() << S;
5781d3e49e7SGeorge Karpenkov }
5791d3e49e7SGeorge Karpenkov 
HandleTranslationUnit(ASTContext & C)5801d3e49e7SGeorge Karpenkov void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
5811d3e49e7SGeorge Karpenkov   // Don't run the actions if an error has occurred with parsing the file.
5821d3e49e7SGeorge Karpenkov   DiagnosticsEngine &Diags = PP.getDiagnostics();
5831d3e49e7SGeorge Karpenkov   if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
5841d3e49e7SGeorge Karpenkov     return;
5851d3e49e7SGeorge Karpenkov 
5869873ef40SBalazs Benics   // Explicitly destroy the PathDiagnosticConsumer.  This will flush its output.
5879873ef40SBalazs Benics   // FIXME: This should be replaced with something that doesn't rely on
5889873ef40SBalazs Benics   // side-effects in PathDiagnosticConsumer's destructor. This is required when
5899873ef40SBalazs Benics   // used with option -disable-free.
5909873ef40SBalazs Benics   const auto DiagFlusherScopeExit =
5919873ef40SBalazs Benics       llvm::make_scope_exit([this] { Mgr.reset(); });
5929873ef40SBalazs Benics 
5939873ef40SBalazs Benics   if (Opts->ShouldIgnoreBisonGeneratedFiles &&
5949873ef40SBalazs Benics       fileContainsString("/* A Bison parser, made by", C)) {
5951d3e49e7SGeorge Karpenkov     reportAnalyzerProgress("Skipping bison-generated file\n");
5969873ef40SBalazs Benics     return;
5979873ef40SBalazs Benics   }
5989873ef40SBalazs Benics 
5999873ef40SBalazs Benics   if (Opts->ShouldIgnoreFlexGeneratedFiles &&
6009873ef40SBalazs Benics       fileContainsString("/* A lexical scanner generated by flex", C)) {
6019873ef40SBalazs Benics     reportAnalyzerProgress("Skipping flex-generated file\n");
6029873ef40SBalazs Benics     return;
6039873ef40SBalazs Benics   }
6041d3e49e7SGeorge Karpenkov 
6051d3e49e7SGeorge Karpenkov   // Don't analyze if the user explicitly asked for no checks to be performed
6061d3e49e7SGeorge Karpenkov   // on this file.
6079873ef40SBalazs Benics   if (Opts->DisableAllCheckers) {
6081d3e49e7SGeorge Karpenkov     reportAnalyzerProgress("All checks are disabled using a supplied option\n");
6099873ef40SBalazs Benics     return;
6109873ef40SBalazs Benics   }
6119873ef40SBalazs Benics 
6121d3e49e7SGeorge Karpenkov   // Otherwise, just run the analysis.
6131d3e49e7SGeorge Karpenkov   runAnalysisOnTranslationUnit(C);
6141d3e49e7SGeorge Karpenkov 
6158382e454SAnna Zaks   // Count how many basic blocks we have not covered.
6168382e454SAnna Zaks   NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
6172a639858SGeorge Karpenkov   NumVisitedBlocksInAnalyzedFunctions =
6182a639858SGeorge Karpenkov       FunctionSummaries.getTotalNumVisitedBasicBlocks();
6198382e454SAnna Zaks   if (NumBlocksInAnalyzedFunctions > 0)
6208382e454SAnna Zaks     PercentReachableBlocks =
6218382e454SAnna Zaks         (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
6228382e454SAnna Zaks         NumBlocksInAnalyzedFunctions;
623ecd3334dSArgyrios Kyrtzidis }
624ecd3334dSArgyrios Kyrtzidis 
625d8665b3dSJordan Rose AnalysisConsumer::AnalysisMode
getModeForDecl(Decl * D,AnalysisMode Mode)626d8665b3dSJordan Rose AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
62740ea0eaaSTed Kremenek   if (!Opts->AnalyzeSpecificFunction.empty() &&
628d3e14fafSBalazs Benics       AnalysisDeclContext::getFunctionName(D) != Opts->AnalyzeSpecificFunction)
629d8665b3dSJordan Rose     return AM_None;
630ecd3334dSArgyrios Kyrtzidis 
631d8665b3dSJordan Rose   // Unless -analyze-all is specified, treat decls differently depending on
632d8665b3dSJordan Rose   // where they came from:
633d8665b3dSJordan Rose   // - Main source file: run both path-sensitive and non-path-sensitive checks.
634d8665b3dSJordan Rose   // - Header files: run non-path-sensitive checks only.
635d8665b3dSJordan Rose   // - System headers: don't run any checks.
636af37d4b6SBalazs Benics   if (Opts->AnalyzeAll)
637af37d4b6SBalazs Benics     return Mode;
638af37d4b6SBalazs Benics 
639af37d4b6SBalazs Benics   const SourceManager &SM = Ctx->getSourceManager();
640af37d4b6SBalazs Benics 
641af37d4b6SBalazs Benics   const SourceLocation Loc = [&SM](Decl *D) -> SourceLocation {
64265693873SAaron Ballman     const Stmt *Body = D->getBody();
643f2ceec48SStephen Kelly     SourceLocation SL = Body ? Body->getBeginLoc() : D->getLocation();
644af37d4b6SBalazs Benics     return SM.getExpansionLoc(SL);
645af37d4b6SBalazs Benics   }(D);
6463849dea8SAnna Zaks 
647af37d4b6SBalazs Benics   // Ignore system headers.
648af37d4b6SBalazs Benics   if (Loc.isInvalid() || SM.isInSystemHeader(Loc))
649d8665b3dSJordan Rose     return AM_None;
650af37d4b6SBalazs Benics 
651af37d4b6SBalazs Benics   // Disable path sensitive analysis in user-headers.
652af37d4b6SBalazs Benics   if (!Mgr->isInCodeFile(Loc))
653d8665b3dSJordan Rose     return Mode & ~AM_Path;
654aa19abe9SAnna Zaks 
655d8665b3dSJordan Rose   return Mode;
656aa19abe9SAnna Zaks }
657aa19abe9SAnna Zaks 
HandleCode(Decl * D,AnalysisMode Mode,ExprEngine::InliningModes IMode,SetOfConstDecls * VisitedCallees)65814189514SAnna Zaks void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
6595d484780SAnna Zaks                                   ExprEngine::InliningModes IMode,
6608e078528SAnna Zaks                                   SetOfConstDecls *VisitedCallees) {
6615c32dfc5SAnna Zaks   if (!D->hasBody())
6625c32dfc5SAnna Zaks     return;
663d8665b3dSJordan Rose   Mode = getModeForDecl(D, Mode);
664d8665b3dSJordan Rose   if (Mode == AM_None)
665ecd3334dSArgyrios Kyrtzidis     return;
666ecd3334dSArgyrios Kyrtzidis 
667a1fead29SAlexander Shaposhnikov   // Clear the AnalysisManager of old AnalysisDeclContexts.
668a1fead29SAlexander Shaposhnikov   Mgr->ClearContexts();
669a1fead29SAlexander Shaposhnikov   // Ignore autosynthesized code.
670a1fead29SAlexander Shaposhnikov   if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized())
671a1fead29SAlexander Shaposhnikov     return;
672a1fead29SAlexander Shaposhnikov 
67340b87fc1SAnna Zaks   CFG *DeclCFG = Mgr->getCFG(D);
674704b4fbbSCraig Topper   if (DeclCFG)
675704b4fbbSCraig Topper     MaxCFGSize.updateMax(DeclCFG->size());
67640b87fc1SAnna Zaks 
677cad9b7f7SSharmaRithik   DisplayFunction(D, Mode, IMode);
67824ffc08fSArgyrios Kyrtzidis   BugReporter BR(*Mgr);
6795c32dfc5SAnna Zaks 
680c48be7fcSArtem Dergachev   if (Mode & AM_Syntax) {
681cad9b7f7SSharmaRithik     llvm::TimeRecord CheckerStartTime;
682cad9b7f7SSharmaRithik     if (SyntaxCheckTimer) {
683cad9b7f7SSharmaRithik       CheckerStartTime = SyntaxCheckTimer->getTotalTime();
684c48be7fcSArtem Dergachev       SyntaxCheckTimer->startTimer();
685cad9b7f7SSharmaRithik     }
6865c32dfc5SAnna Zaks     checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
687cad9b7f7SSharmaRithik     if (SyntaxCheckTimer) {
688c48be7fcSArtem Dergachev       SyntaxCheckTimer->stopTimer();
689cad9b7f7SSharmaRithik       llvm::TimeRecord CheckerEndTime = SyntaxCheckTimer->getTotalTime();
690cad9b7f7SSharmaRithik       CheckerEndTime -= CheckerStartTime;
691cad9b7f7SSharmaRithik       DisplayTime(CheckerEndTime);
692cad9b7f7SSharmaRithik     }
693c48be7fcSArtem Dergachev   }
6943fdc427fSArtem Dergachev 
6953fdc427fSArtem Dergachev   BR.FlushReports();
6963fdc427fSArtem Dergachev 
697d8665b3dSJordan Rose   if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
6985c32dfc5SAnna Zaks     RunPathSensitiveChecks(D, IMode, VisitedCallees);
699b13d21b6SAnna Zaks     if (IMode != ExprEngine::Inline_Minimal)
700eee91107SAnna Zaks       NumFunctionsAnalyzed++;
701ecd3334dSArgyrios Kyrtzidis   }
70223df6bb1SAnna Zaks }
703ecd3334dSArgyrios Kyrtzidis 
704ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
7056a1c7607SArgyrios Kyrtzidis // Path-sensitive checking.
706ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
707ecd3334dSArgyrios Kyrtzidis 
RunPathSensitiveChecks(Decl * D,ExprEngine::InliningModes IMode,SetOfConstDecls * VisitedCallees)708c82d457dSGeorge Karpenkov void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
7095d484780SAnna Zaks                                               ExprEngine::InliningModes IMode,
7108e078528SAnna Zaks                                               SetOfConstDecls *VisitedCallees) {
711dccc2b22STed Kremenek   // Construct the analysis engine.  First check if the CFG is valid.
712ecd3334dSArgyrios Kyrtzidis   // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
713394d07eaSAnna Zaks   if (!Mgr->getCFG(D))
714ecd3334dSArgyrios Kyrtzidis     return;
715394d07eaSAnna Zaks 
716de21a1c9STed Kremenek   // See if the LiveVariables analysis scales.
717de21a1c9STed Kremenek   if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
718de21a1c9STed Kremenek     return;
719de21a1c9STed Kremenek 
720c82d457dSGeorge Karpenkov   ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
721ecd3334dSArgyrios Kyrtzidis 
722ecd3334dSArgyrios Kyrtzidis   // Execute the worklist algorithm.
723cad9b7f7SSharmaRithik   llvm::TimeRecord ExprEngineStartTime;
724cad9b7f7SSharmaRithik   if (ExprEngineTimer) {
725cad9b7f7SSharmaRithik     ExprEngineStartTime = ExprEngineTimer->getTotalTime();
726c48be7fcSArtem Dergachev     ExprEngineTimer->startTimer();
727cad9b7f7SSharmaRithik   }
7284f8198e7SJordy Rose   Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
729549f9cd4SKristof Umann                       Mgr->options.MaxNodesPerTopLevelFunction);
730cad9b7f7SSharmaRithik   if (ExprEngineTimer) {
731c48be7fcSArtem Dergachev     ExprEngineTimer->stopTimer();
732cad9b7f7SSharmaRithik     llvm::TimeRecord ExprEngineEndTime = ExprEngineTimer->getTotalTime();
733cad9b7f7SSharmaRithik     ExprEngineEndTime -= ExprEngineStartTime;
734cad9b7f7SSharmaRithik     DisplayTime(ExprEngineEndTime);
735cad9b7f7SSharmaRithik   }
736ecd3334dSArgyrios Kyrtzidis 
737c704f4fbSGeorge Karpenkov   if (!Mgr->options.DumpExplodedGraphTo.empty())
738c704f4fbSGeorge Karpenkov     Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo);
739c704f4fbSGeorge Karpenkov 
740ecd3334dSArgyrios Kyrtzidis   // Visualize the exploded graph.
741b8f8b357STed Kremenek   if (Mgr->options.visualizeExplodedGraphWithGraphViz)
7428756c4a1STed Kremenek     Eng.ViewGraph(Mgr->options.TrimGraph);
743ecd3334dSArgyrios Kyrtzidis 
744ecd3334dSArgyrios Kyrtzidis   // Display warnings.
745c48be7fcSArtem Dergachev   if (BugReporterTimer)
746c48be7fcSArtem Dergachev     BugReporterTimer->startTimer();
747ecd3334dSArgyrios Kyrtzidis   Eng.getBugReporter().FlushReports();
748c48be7fcSArtem Dergachev   if (BugReporterTimer)
749c48be7fcSArtem Dergachev     BugReporterTimer->stopTimer();
750ecd3334dSArgyrios Kyrtzidis }
751ecd3334dSArgyrios Kyrtzidis 
752ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
753ecd3334dSArgyrios Kyrtzidis // AnalysisConsumer creation.
754ecd3334dSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
755ecd3334dSArgyrios Kyrtzidis 
7566beb6aa8SDavid Blaikie std::unique_ptr<AnalysisASTConsumer>
CreateAnalysisConsumer(CompilerInstance & CI)757eeccb30bSTed Kremenek ento::CreateAnalysisConsumer(CompilerInstance &CI) {
75859cce71aSJordy Rose   // Disable the effects of '-Werror' when using the AnalysisConsumer.
759eeccb30bSTed Kremenek   CI.getPreprocessor().getDiagnostics().setWarningsAsErrors(false);
760ecd3334dSArgyrios Kyrtzidis 
761eeccb30bSTed Kremenek   AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
762eeccb30bSTed Kremenek   bool hasModelPath = analyzerOpts->Config.count("model-path") > 0;
763eeccb30bSTed Kremenek 
7642b3d49b6SJonas Devlieghere   return std::make_unique<AnalysisConsumer>(
7658b9b3bd0SIlya Biryukov       CI, CI.getFrontendOpts().OutputFile, analyzerOpts,
766eeccb30bSTed Kremenek       CI.getFrontendOpts().Plugins,
767eeccb30bSTed Kremenek       hasModelPath ? new ModelInjector(CI) : nullptr);
768ecd3334dSArgyrios Kyrtzidis }
769