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