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