1 //===- BugReporter.cpp - Generate PathDiagnostics for bugs ----------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines BugReporter, a utility class for generating
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
15 #include "clang/AST/ASTTypeTraits.h"
16 #include "clang/AST/Attr.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/DeclBase.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/Expr.h"
21 #include "clang/AST/ExprCXX.h"
22 #include "clang/AST/ParentMap.h"
23 #include "clang/AST/ParentMapContext.h"
24 #include "clang/AST/Stmt.h"
25 #include "clang/AST/StmtCXX.h"
26 #include "clang/AST/StmtObjC.h"
27 #include "clang/Analysis/AnalysisDeclContext.h"
28 #include "clang/Analysis/CFG.h"
29 #include "clang/Analysis/CFGStmtMap.h"
30 #include "clang/Analysis/PathDiagnostic.h"
31 #include "clang/Analysis/ProgramPoint.h"
32 #include "clang/Basic/LLVM.h"
33 #include "clang/Basic/SourceLocation.h"
34 #include "clang/Basic/SourceManager.h"
35 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
36 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
37 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
38 #include "clang/StaticAnalyzer/Core/Checker.h"
39 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
40 #include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
41 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
42 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
43 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
44 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
45 #include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
46 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
47 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
48 #include "llvm/ADT/ArrayRef.h"
49 #include "llvm/ADT/DenseMap.h"
50 #include "llvm/ADT/DenseSet.h"
51 #include "llvm/ADT/FoldingSet.h"
52 #include "llvm/ADT/STLExtras.h"
53 #include "llvm/ADT/SmallPtrSet.h"
54 #include "llvm/ADT/SmallString.h"
55 #include "llvm/ADT/SmallVector.h"
56 #include "llvm/ADT/Statistic.h"
57 #include "llvm/ADT/StringExtras.h"
58 #include "llvm/ADT/StringRef.h"
59 #include "llvm/ADT/iterator_range.h"
60 #include "llvm/Support/Casting.h"
61 #include "llvm/Support/Compiler.h"
62 #include "llvm/Support/ErrorHandling.h"
63 #include "llvm/Support/MemoryBuffer.h"
64 #include "llvm/Support/raw_ostream.h"
77 using namespace clang
;
81 #define DEBUG_TYPE "BugReporter"
83 STATISTIC(MaxBugClassSize
,
84 "The maximum number of bug reports in the same equivalence class");
85 STATISTIC(MaxValidBugClassSize
,
86 "The maximum number of bug reports in the same equivalence class "
87 "where at least one report is valid (not suppressed)");
89 BugReporterVisitor::~BugReporterVisitor() = default;
91 void BugReporterContext::anchor() {}
93 //===----------------------------------------------------------------------===//
94 // PathDiagnosticBuilder and its associated routines and helper objects.
95 //===----------------------------------------------------------------------===//
99 /// A (CallPiece, node assiciated with its CallEnter) pair.
100 using CallWithEntry
=
101 std::pair
<PathDiagnosticCallPiece
*, const ExplodedNode
*>;
102 using CallWithEntryStack
= SmallVector
<CallWithEntry
, 6>;
104 /// Map from each node to the diagnostic pieces visitors emit for them.
105 using VisitorsDiagnosticsTy
=
106 llvm::DenseMap
<const ExplodedNode
*, std::vector
<PathDiagnosticPieceRef
>>;
108 /// A map from PathDiagnosticPiece to the LocationContext of the inlined
109 /// function call it represents.
110 using LocationContextMap
=
111 llvm::DenseMap
<const PathPieces
*, const LocationContext
*>;
113 /// A helper class that contains everything needed to construct a
114 /// PathDiagnostic object. It does no much more then providing convenient
115 /// getters and some well placed asserts for extra security.
116 class PathDiagnosticConstruct
{
117 /// The consumer we're constructing the bug report for.
118 const PathDiagnosticConsumer
*Consumer
;
119 /// Our current position in the bug path, which is owned by
120 /// PathDiagnosticBuilder.
121 const ExplodedNode
*CurrentNode
;
122 /// A mapping from parts of the bug path (for example, a function call, which
123 /// would span backwards from a CallExit to a CallEnter with the nodes in
124 /// between them) with the location contexts it is associated with.
125 LocationContextMap LCM
;
126 const SourceManager
&SM
;
129 /// We keep stack of calls to functions as we're ascending the bug path.
130 /// TODO: PathDiagnostic has a stack doing the same thing, shouldn't we use
132 CallWithEntryStack CallStack
;
133 /// The bug report we're constructing. For ease of use, this field is kept
134 /// public, though some "shortcut" getters are provided for commonly used
135 /// methods of PathDiagnostic.
136 std::unique_ptr
<PathDiagnostic
> PD
;
139 PathDiagnosticConstruct(const PathDiagnosticConsumer
*PDC
,
140 const ExplodedNode
*ErrorNode
,
141 const PathSensitiveBugReport
*R
);
143 /// \returns the location context associated with the current position in the
145 const LocationContext
*getCurrLocationContext() const {
146 assert(CurrentNode
&& "Already reached the root!");
147 return CurrentNode
->getLocationContext();
150 /// Same as getCurrLocationContext (they should always return the same
151 /// location context), but works after reaching the root of the bug path as
153 const LocationContext
*getLocationContextForActivePath() const {
154 return LCM
.find(&PD
->getActivePath())->getSecond();
157 const ExplodedNode
*getCurrentNode() const { return CurrentNode
; }
159 /// Steps the current node to its predecessor.
160 /// \returns whether we reached the root of the bug path.
161 bool ascendToPrevNode() {
162 CurrentNode
= CurrentNode
->getFirstPred();
163 return static_cast<bool>(CurrentNode
);
166 const ParentMap
&getParentMap() const {
167 return getCurrLocationContext()->getParentMap();
170 const SourceManager
&getSourceManager() const { return SM
; }
172 const Stmt
*getParent(const Stmt
*S
) const {
173 return getParentMap().getParent(S
);
176 void updateLocCtxMap(const PathPieces
*Path
, const LocationContext
*LC
) {
181 const LocationContext
*getLocationContextFor(const PathPieces
*Path
) const {
182 assert(LCM
.count(Path
) &&
183 "Failed to find the context associated with these pieces!");
184 return LCM
.find(Path
)->getSecond();
187 bool isInLocCtxMap(const PathPieces
*Path
) const { return LCM
.count(Path
); }
189 PathPieces
&getActivePath() { return PD
->getActivePath(); }
190 PathPieces
&getMutablePieces() { return PD
->getMutablePieces(); }
192 bool shouldAddPathEdges() const { return Consumer
->shouldAddPathEdges(); }
193 bool shouldAddControlNotes() const {
194 return Consumer
->shouldAddControlNotes();
196 bool shouldGenerateDiagnostics() const {
197 return Consumer
->shouldGenerateDiagnostics();
199 bool supportsLogicalOpControlFlow() const {
200 return Consumer
->supportsLogicalOpControlFlow();
204 /// Contains every contextual information needed for constructing a
205 /// PathDiagnostic object for a given bug report. This class and its fields are
206 /// immutable, and passes a BugReportConstruct object around during the
208 class PathDiagnosticBuilder
: public BugReporterContext
{
209 /// A linear path from the error node to the root.
210 std::unique_ptr
<const ExplodedGraph
> BugPath
;
211 /// The bug report we're describing. Visitors create their diagnostics with
212 /// them being the last entities being able to modify it (for example,
213 /// changing interestingness here would cause inconsistencies as to how this
214 /// file and visitors construct diagnostics), hence its const.
215 const PathSensitiveBugReport
*R
;
216 /// The leaf of the bug path. This isn't the same as the bug reports error
217 /// node, which refers to the *original* graph, not the bug path.
218 const ExplodedNode
*const ErrorNode
;
219 /// The diagnostic pieces visitors emitted, which is expected to be collected
220 /// by the time this builder is constructed.
221 std::unique_ptr
<const VisitorsDiagnosticsTy
> VisitorsDiagnostics
;
224 /// Find a non-invalidated report for a given equivalence class, and returns
225 /// a PathDiagnosticBuilder able to construct bug reports for different
226 /// consumers. Returns std::nullopt if no valid report is found.
227 static std::optional
<PathDiagnosticBuilder
>
228 findValidReport(ArrayRef
<PathSensitiveBugReport
*> &bugReports
,
229 PathSensitiveBugReporter
&Reporter
);
231 PathDiagnosticBuilder(
232 BugReporterContext BRC
, std::unique_ptr
<ExplodedGraph
> BugPath
,
233 PathSensitiveBugReport
*r
, const ExplodedNode
*ErrorNode
,
234 std::unique_ptr
<VisitorsDiagnosticsTy
> VisitorsDiagnostics
);
236 /// This function is responsible for generating diagnostic pieces that are
237 /// *not* provided by bug report visitors.
238 /// These diagnostics may differ depending on the consumer's settings,
239 /// and are therefore constructed separately for each consumer.
241 /// There are two path diagnostics generation modes: with adding edges (used
242 /// for plists) and without (used for HTML and text). When edges are added,
243 /// the path is modified to insert artificially generated edges.
244 /// Otherwise, more detailed diagnostics is emitted for block edges,
245 /// explaining the transitions in words.
246 std::unique_ptr
<PathDiagnostic
>
247 generate(const PathDiagnosticConsumer
*PDC
) const;
250 void updateStackPiecesWithMessage(PathDiagnosticPieceRef P
,
251 const CallWithEntryStack
&CallStack
) const;
252 void generatePathDiagnosticsForNode(PathDiagnosticConstruct
&C
,
253 PathDiagnosticLocation
&PrevLoc
) const;
255 void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct
&C
,
258 PathDiagnosticPieceRef
259 generateDiagForGotoOP(const PathDiagnosticConstruct
&C
, const Stmt
*S
,
260 PathDiagnosticLocation
&Start
) const;
262 PathDiagnosticPieceRef
263 generateDiagForSwitchOP(const PathDiagnosticConstruct
&C
, const CFGBlock
*Dst
,
264 PathDiagnosticLocation
&Start
) const;
266 PathDiagnosticPieceRef
267 generateDiagForBinaryOP(const PathDiagnosticConstruct
&C
, const Stmt
*T
,
268 const CFGBlock
*Src
, const CFGBlock
*DstC
) const;
270 PathDiagnosticLocation
271 ExecutionContinues(const PathDiagnosticConstruct
&C
) const;
273 PathDiagnosticLocation
274 ExecutionContinues(llvm::raw_string_ostream
&os
,
275 const PathDiagnosticConstruct
&C
) const;
277 const PathSensitiveBugReport
*getBugReport() const { return R
; }
282 //===----------------------------------------------------------------------===//
283 // Base implementation of stack hint generators.
284 //===----------------------------------------------------------------------===//
286 StackHintGenerator::~StackHintGenerator() = default;
288 std::string
StackHintGeneratorForSymbol::getMessage(const ExplodedNode
*N
){
290 return getMessageForSymbolNotFound();
292 ProgramPoint P
= N
->getLocation();
293 CallExitEnd CExit
= P
.castAs
<CallExitEnd
>();
295 // FIXME: Use CallEvent to abstract this over all calls.
296 const Stmt
*CallSite
= CExit
.getCalleeContext()->getCallSite();
297 const auto *CE
= dyn_cast_or_null
<CallExpr
>(CallSite
);
301 // Check if one of the parameters are set to the interesting symbol.
302 for (auto [Idx
, ArgExpr
] : llvm::enumerate(CE
->arguments())) {
303 SVal SV
= N
->getSVal(ArgExpr
);
305 // Check if the variable corresponding to the symbol is passed by value.
306 SymbolRef AS
= SV
.getAsLocSymbol();
308 return getMessageForArg(ArgExpr
, Idx
);
311 // Check if the parameter is a pointer to the symbol.
312 if (std::optional
<loc::MemRegionVal
> Reg
= SV
.getAs
<loc::MemRegionVal
>()) {
313 // Do not attempt to dereference void*.
314 if (ArgExpr
->getType()->isVoidPointerType())
316 SVal PSV
= N
->getState()->getSVal(Reg
->getRegion());
317 SymbolRef AS
= PSV
.getAsLocSymbol();
319 return getMessageForArg(ArgExpr
, Idx
);
324 // Check if we are returning the interesting symbol.
325 SVal SV
= N
->getSVal(CE
);
326 SymbolRef RetSym
= SV
.getAsLocSymbol();
328 return getMessageForReturn(CE
);
331 return getMessageForSymbolNotFound();
334 std::string
StackHintGeneratorForSymbol::getMessageForArg(const Expr
*ArgE
,
336 // Printed parameters start at 1, not 0.
339 return (llvm::Twine(Msg
) + " via " + std::to_string(ArgIndex
) +
340 llvm::getOrdinalSuffix(ArgIndex
) + " parameter").str();
343 //===----------------------------------------------------------------------===//
344 // Diagnostic cleanup.
345 //===----------------------------------------------------------------------===//
347 static PathDiagnosticEventPiece
*
348 eventsDescribeSameCondition(PathDiagnosticEventPiece
*X
,
349 PathDiagnosticEventPiece
*Y
) {
350 // Prefer diagnostics that come from ConditionBRVisitor over
351 // those that came from TrackConstraintBRVisitor,
352 // unless the one from ConditionBRVisitor is
353 // its generic fallback diagnostic.
354 const void *tagPreferred
= ConditionBRVisitor::getTag();
355 const void *tagLesser
= TrackConstraintBRVisitor::getTag();
357 if (X
->getLocation() != Y
->getLocation())
360 if (X
->getTag() == tagPreferred
&& Y
->getTag() == tagLesser
)
361 return ConditionBRVisitor::isPieceMessageGeneric(X
) ? Y
: X
;
363 if (Y
->getTag() == tagPreferred
&& X
->getTag() == tagLesser
)
364 return ConditionBRVisitor::isPieceMessageGeneric(Y
) ? X
: Y
;
369 /// An optimization pass over PathPieces that removes redundant diagnostics
370 /// generated by both ConditionBRVisitor and TrackConstraintBRVisitor. Both
371 /// BugReporterVisitors use different methods to generate diagnostics, with
372 /// one capable of emitting diagnostics in some cases but not in others. This
373 /// can lead to redundant diagnostic pieces at the same point in a path.
374 static void removeRedundantMsgs(PathPieces
&path
) {
375 unsigned N
= path
.size();
378 // NOTE: this loop intentionally is not using an iterator. Instead, we
379 // are streaming the path and modifying it in place. This is done by
380 // grabbing the front, processing it, and if we decide to keep it append
381 // it to the end of the path. The entire path is processed in this way.
382 for (unsigned i
= 0; i
< N
; ++i
) {
383 auto piece
= std::move(path
.front());
386 switch (piece
->getKind()) {
387 case PathDiagnosticPiece::Call
:
388 removeRedundantMsgs(cast
<PathDiagnosticCallPiece
>(*piece
).path
);
390 case PathDiagnosticPiece::Macro
:
391 removeRedundantMsgs(cast
<PathDiagnosticMacroPiece
>(*piece
).subPieces
);
393 case PathDiagnosticPiece::Event
: {
397 if (auto *nextEvent
=
398 dyn_cast
<PathDiagnosticEventPiece
>(path
.front().get())) {
399 auto *event
= cast
<PathDiagnosticEventPiece
>(piece
.get());
400 // Check to see if we should keep one of the two pieces. If we
401 // come up with a preference, record which piece to keep, and consume
402 // another piece from the path.
403 if (auto *pieceToKeep
=
404 eventsDescribeSameCondition(event
, nextEvent
)) {
405 piece
= std::move(pieceToKeep
== event
? piece
: path
.front());
412 case PathDiagnosticPiece::ControlFlow
:
413 case PathDiagnosticPiece::Note
:
414 case PathDiagnosticPiece::PopUp
:
417 path
.push_back(std::move(piece
));
421 /// Recursively scan through a path and prune out calls and macros pieces
422 /// that aren't needed. Return true if afterwards the path contains
423 /// "interesting stuff" which means it shouldn't be pruned from the parent path.
424 static bool removeUnneededCalls(const PathDiagnosticConstruct
&C
,
426 const PathSensitiveBugReport
*R
,
427 bool IsInteresting
= false) {
428 bool containsSomethingInteresting
= IsInteresting
;
429 const unsigned N
= pieces
.size();
431 for (unsigned i
= 0 ; i
< N
; ++i
) {
432 // Remove the front piece from the path. If it is still something we
433 // want to keep once we are done, we will push it back on the end.
434 auto piece
= std::move(pieces
.front());
437 switch (piece
->getKind()) {
438 case PathDiagnosticPiece::Call
: {
439 auto &call
= cast
<PathDiagnosticCallPiece
>(*piece
);
440 // Check if the location context is interesting.
441 if (!removeUnneededCalls(
443 R
->isInteresting(C
.getLocationContextFor(&call
.path
))))
446 containsSomethingInteresting
= true;
449 case PathDiagnosticPiece::Macro
: {
450 auto ¯o
= cast
<PathDiagnosticMacroPiece
>(*piece
);
451 if (!removeUnneededCalls(C
, macro
.subPieces
, R
, IsInteresting
))
453 containsSomethingInteresting
= true;
456 case PathDiagnosticPiece::Event
: {
457 auto &event
= cast
<PathDiagnosticEventPiece
>(*piece
);
459 // We never throw away an event, but we do throw it away wholesale
460 // as part of a path if we throw the entire path away.
461 containsSomethingInteresting
|= !event
.isPrunable();
464 case PathDiagnosticPiece::ControlFlow
:
465 case PathDiagnosticPiece::Note
:
466 case PathDiagnosticPiece::PopUp
:
470 pieces
.push_back(std::move(piece
));
473 return containsSomethingInteresting
;
476 /// Same logic as above to remove extra pieces.
477 static void removePopUpNotes(PathPieces
&Path
) {
478 for (unsigned int i
= 0; i
< Path
.size(); ++i
) {
479 auto Piece
= std::move(Path
.front());
481 if (!isa
<PathDiagnosticPopUpPiece
>(*Piece
))
482 Path
.push_back(std::move(Piece
));
486 /// Returns true if the given decl has been implicitly given a body, either by
487 /// the analyzer or by the compiler proper.
488 static bool hasImplicitBody(const Decl
*D
) {
490 return D
->isImplicit() || !D
->hasBody();
493 /// Recursively scan through a path and make sure that all call pieces have
496 adjustCallLocations(PathPieces
&Pieces
,
497 PathDiagnosticLocation
*LastCallLocation
= nullptr) {
498 for (const auto &I
: Pieces
) {
499 auto *Call
= dyn_cast
<PathDiagnosticCallPiece
>(I
.get());
504 if (LastCallLocation
) {
505 bool CallerIsImplicit
= hasImplicitBody(Call
->getCaller());
506 if (CallerIsImplicit
|| !Call
->callEnter
.asLocation().isValid())
507 Call
->callEnter
= *LastCallLocation
;
508 if (CallerIsImplicit
|| !Call
->callReturn
.asLocation().isValid())
509 Call
->callReturn
= *LastCallLocation
;
512 // Recursively clean out the subclass. Keep this call around if
513 // it contains any informative diagnostics.
514 PathDiagnosticLocation
*ThisCallLocation
;
515 if (Call
->callEnterWithin
.asLocation().isValid() &&
516 !hasImplicitBody(Call
->getCallee()))
517 ThisCallLocation
= &Call
->callEnterWithin
;
519 ThisCallLocation
= &Call
->callEnter
;
521 assert(ThisCallLocation
&& "Outermost call has an invalid location");
522 adjustCallLocations(Call
->path
, ThisCallLocation
);
526 /// Remove edges in and out of C++ default initializer expressions. These are
527 /// for fields that have in-class initializers, as opposed to being initialized
528 /// explicitly in a constructor or braced list.
529 static void removeEdgesToDefaultInitializers(PathPieces
&Pieces
) {
530 for (PathPieces::iterator I
= Pieces
.begin(), E
= Pieces
.end(); I
!= E
;) {
531 if (auto *C
= dyn_cast
<PathDiagnosticCallPiece
>(I
->get()))
532 removeEdgesToDefaultInitializers(C
->path
);
534 if (auto *M
= dyn_cast
<PathDiagnosticMacroPiece
>(I
->get()))
535 removeEdgesToDefaultInitializers(M
->subPieces
);
537 if (auto *CF
= dyn_cast
<PathDiagnosticControlFlowPiece
>(I
->get())) {
538 const Stmt
*Start
= CF
->getStartLocation().asStmt();
539 const Stmt
*End
= CF
->getEndLocation().asStmt();
540 if (isa_and_nonnull
<CXXDefaultInitExpr
>(Start
)) {
543 } else if (isa_and_nonnull
<CXXDefaultInitExpr
>(End
)) {
544 PathPieces::iterator Next
= std::next(I
);
547 dyn_cast
<PathDiagnosticControlFlowPiece
>(Next
->get())) {
548 NextCF
->setStartLocation(CF
->getStartLocation());
560 /// Remove all pieces with invalid locations as these cannot be serialized.
561 /// We might have pieces with invalid locations as a result of inlining Body
562 /// Farm generated functions.
563 static void removePiecesWithInvalidLocations(PathPieces
&Pieces
) {
564 for (PathPieces::iterator I
= Pieces
.begin(), E
= Pieces
.end(); I
!= E
;) {
565 if (auto *C
= dyn_cast
<PathDiagnosticCallPiece
>(I
->get()))
566 removePiecesWithInvalidLocations(C
->path
);
568 if (auto *M
= dyn_cast
<PathDiagnosticMacroPiece
>(I
->get()))
569 removePiecesWithInvalidLocations(M
->subPieces
);
571 if (!(*I
)->getLocation().isValid() ||
572 !(*I
)->getLocation().asLocation().isValid()) {
580 PathDiagnosticLocation
PathDiagnosticBuilder::ExecutionContinues(
581 const PathDiagnosticConstruct
&C
) const {
582 if (const Stmt
*S
= C
.getCurrentNode()->getNextStmtForDiagnostics())
583 return PathDiagnosticLocation(S
, getSourceManager(),
584 C
.getCurrLocationContext());
586 return PathDiagnosticLocation::createDeclEnd(C
.getCurrLocationContext(),
590 PathDiagnosticLocation
PathDiagnosticBuilder::ExecutionContinues(
591 llvm::raw_string_ostream
&os
, const PathDiagnosticConstruct
&C
) const {
592 // Slow, but probably doesn't matter.
593 if (os
.str().empty())
596 const PathDiagnosticLocation
&Loc
= ExecutionContinues(C
);
599 os
<< "Execution continues on line "
600 << getSourceManager().getExpansionLineNumber(Loc
.asLocation())
603 os
<< "Execution jumps to the end of the ";
604 const Decl
*D
= C
.getCurrLocationContext()->getDecl();
605 if (isa
<ObjCMethodDecl
>(D
))
607 else if (isa
<FunctionDecl
>(D
))
610 assert(isa
<BlockDecl
>(D
));
611 os
<< "anonymous block";
619 static const Stmt
*getEnclosingParent(const Stmt
*S
, const ParentMap
&PM
) {
620 if (isa
<Expr
>(S
) && PM
.isConsumedExpr(cast
<Expr
>(S
)))
621 return PM
.getParentIgnoreParens(S
);
623 const Stmt
*Parent
= PM
.getParentIgnoreParens(S
);
627 switch (Parent
->getStmtClass()) {
628 case Stmt::ForStmtClass
:
629 case Stmt::DoStmtClass
:
630 case Stmt::WhileStmtClass
:
631 case Stmt::ObjCForCollectionStmtClass
:
632 case Stmt::CXXForRangeStmtClass
:
641 static PathDiagnosticLocation
642 getEnclosingStmtLocation(const Stmt
*S
, const LocationContext
*LC
,
643 bool allowNestedContexts
= false) {
647 const SourceManager
&SMgr
= LC
->getDecl()->getASTContext().getSourceManager();
649 while (const Stmt
*Parent
= getEnclosingParent(S
, LC
->getParentMap())) {
650 switch (Parent
->getStmtClass()) {
651 case Stmt::BinaryOperatorClass
: {
652 const auto *B
= cast
<BinaryOperator
>(Parent
);
653 if (B
->isLogicalOp())
654 return PathDiagnosticLocation(allowNestedContexts
? B
: S
, SMgr
, LC
);
657 case Stmt::CompoundStmtClass
:
658 case Stmt::StmtExprClass
:
659 return PathDiagnosticLocation(S
, SMgr
, LC
);
660 case Stmt::ChooseExprClass
:
661 // Similar to '?' if we are referring to condition, just have the edge
662 // point to the entire choose expression.
663 if (allowNestedContexts
|| cast
<ChooseExpr
>(Parent
)->getCond() == S
)
664 return PathDiagnosticLocation(Parent
, SMgr
, LC
);
666 return PathDiagnosticLocation(S
, SMgr
, LC
);
667 case Stmt::BinaryConditionalOperatorClass
:
668 case Stmt::ConditionalOperatorClass
:
669 // For '?', if we are referring to condition, just have the edge point
670 // to the entire '?' expression.
671 if (allowNestedContexts
||
672 cast
<AbstractConditionalOperator
>(Parent
)->getCond() == S
)
673 return PathDiagnosticLocation(Parent
, SMgr
, LC
);
675 return PathDiagnosticLocation(S
, SMgr
, LC
);
676 case Stmt::CXXForRangeStmtClass
:
677 if (cast
<CXXForRangeStmt
>(Parent
)->getBody() == S
)
678 return PathDiagnosticLocation(S
, SMgr
, LC
);
680 case Stmt::DoStmtClass
:
681 return PathDiagnosticLocation(S
, SMgr
, LC
);
682 case Stmt::ForStmtClass
:
683 if (cast
<ForStmt
>(Parent
)->getBody() == S
)
684 return PathDiagnosticLocation(S
, SMgr
, LC
);
686 case Stmt::IfStmtClass
:
687 if (cast
<IfStmt
>(Parent
)->getCond() != S
)
688 return PathDiagnosticLocation(S
, SMgr
, LC
);
690 case Stmt::ObjCForCollectionStmtClass
:
691 if (cast
<ObjCForCollectionStmt
>(Parent
)->getBody() == S
)
692 return PathDiagnosticLocation(S
, SMgr
, LC
);
694 case Stmt::WhileStmtClass
:
695 if (cast
<WhileStmt
>(Parent
)->getCond() != S
)
696 return PathDiagnosticLocation(S
, SMgr
, LC
);
705 assert(S
&& "Cannot have null Stmt for PathDiagnosticLocation");
707 return PathDiagnosticLocation(S
, SMgr
, LC
);
710 //===----------------------------------------------------------------------===//
711 // "Minimal" path diagnostic generation algorithm.
712 //===----------------------------------------------------------------------===//
714 /// If the piece contains a special message, add it to all the call pieces on
715 /// the active stack. For example, my_malloc allocated memory, so MallocChecker
716 /// will construct an event at the call to malloc(), and add a stack hint that
717 /// an allocated memory was returned. We'll use this hint to construct a message
718 /// when returning from the call to my_malloc
720 /// void *my_malloc() { return malloc(sizeof(int)); }
722 /// void *ptr = my_malloc(); // returned allocated memory
724 void PathDiagnosticBuilder::updateStackPiecesWithMessage(
725 PathDiagnosticPieceRef P
, const CallWithEntryStack
&CallStack
) const {
726 if (R
->hasCallStackHint(P
))
727 for (const auto &I
: CallStack
) {
728 PathDiagnosticCallPiece
*CP
= I
.first
;
729 const ExplodedNode
*N
= I
.second
;
730 std::string stackMsg
= R
->getCallStackMessage(P
, N
);
732 // The last message on the path to final bug is the most important
733 // one. Since we traverse the path backwards, do not add the message
734 // if one has been previously added.
735 if (!CP
->hasCallStackMessage())
736 CP
->setCallStackMessage(stackMsg
);
740 static void CompactMacroExpandedPieces(PathPieces
&path
,
741 const SourceManager
& SM
);
743 PathDiagnosticPieceRef
PathDiagnosticBuilder::generateDiagForSwitchOP(
744 const PathDiagnosticConstruct
&C
, const CFGBlock
*Dst
,
745 PathDiagnosticLocation
&Start
) const {
747 const SourceManager
&SM
= getSourceManager();
748 // Figure out what case arm we took.
750 llvm::raw_string_ostream
os(sbuf
);
751 PathDiagnosticLocation End
;
753 if (const Stmt
*S
= Dst
->getLabel()) {
754 End
= PathDiagnosticLocation(S
, SM
, C
.getCurrLocationContext());
756 switch (S
->getStmtClass()) {
758 os
<< "No cases match in the switch statement. "
759 "Control jumps to line "
760 << End
.asLocation().getExpansionLineNumber();
762 case Stmt::DefaultStmtClass
:
763 os
<< "Control jumps to the 'default' case at line "
764 << End
.asLocation().getExpansionLineNumber();
767 case Stmt::CaseStmtClass
: {
768 os
<< "Control jumps to 'case ";
769 const auto *Case
= cast
<CaseStmt
>(S
);
770 const Expr
*LHS
= Case
->getLHS()->IgnoreParenImpCasts();
772 // Determine if it is an enum.
773 bool GetRawInt
= true;
775 if (const auto *DR
= dyn_cast
<DeclRefExpr
>(LHS
)) {
776 // FIXME: Maybe this should be an assertion. Are there cases
777 // were it is not an EnumConstantDecl?
778 const auto *D
= dyn_cast
<EnumConstantDecl
>(DR
->getDecl());
787 os
<< LHS
->EvaluateKnownConstInt(getASTContext());
789 os
<< ":' at line " << End
.asLocation().getExpansionLineNumber();
794 os
<< "'Default' branch taken. ";
795 End
= ExecutionContinues(os
, C
);
797 return std::make_shared
<PathDiagnosticControlFlowPiece
>(Start
, End
,
801 PathDiagnosticPieceRef
PathDiagnosticBuilder::generateDiagForGotoOP(
802 const PathDiagnosticConstruct
&C
, const Stmt
*S
,
803 PathDiagnosticLocation
&Start
) const {
805 llvm::raw_string_ostream
os(sbuf
);
806 const PathDiagnosticLocation
&End
=
807 getEnclosingStmtLocation(S
, C
.getCurrLocationContext());
808 os
<< "Control jumps to line " << End
.asLocation().getExpansionLineNumber();
809 return std::make_shared
<PathDiagnosticControlFlowPiece
>(Start
, End
, os
.str());
812 PathDiagnosticPieceRef
PathDiagnosticBuilder::generateDiagForBinaryOP(
813 const PathDiagnosticConstruct
&C
, const Stmt
*T
, const CFGBlock
*Src
,
814 const CFGBlock
*Dst
) const {
816 const SourceManager
&SM
= getSourceManager();
818 const auto *B
= cast
<BinaryOperator
>(T
);
820 llvm::raw_string_ostream
os(sbuf
);
821 os
<< "Left side of '";
822 PathDiagnosticLocation Start
, End
;
824 if (B
->getOpcode() == BO_LAnd
) {
828 if (*(Src
->succ_begin() + 1) == Dst
) {
830 End
= PathDiagnosticLocation(B
->getLHS(), SM
, C
.getCurrLocationContext());
832 PathDiagnosticLocation::createOperatorLoc(B
, SM
);
836 PathDiagnosticLocation(B
->getLHS(), SM
, C
.getCurrLocationContext());
837 End
= ExecutionContinues(C
);
840 assert(B
->getOpcode() == BO_LOr
);
844 if (*(Src
->succ_begin() + 1) == Dst
) {
847 PathDiagnosticLocation(B
->getLHS(), SM
, C
.getCurrLocationContext());
848 End
= ExecutionContinues(C
);
851 End
= PathDiagnosticLocation(B
->getLHS(), SM
, C
.getCurrLocationContext());
853 PathDiagnosticLocation::createOperatorLoc(B
, SM
);
856 return std::make_shared
<PathDiagnosticControlFlowPiece
>(Start
, End
,
860 void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
861 PathDiagnosticConstruct
&C
, BlockEdge BE
) const {
862 const SourceManager
&SM
= getSourceManager();
863 const LocationContext
*LC
= C
.getCurrLocationContext();
864 const CFGBlock
*Src
= BE
.getSrc();
865 const CFGBlock
*Dst
= BE
.getDst();
866 const Stmt
*T
= Src
->getTerminatorStmt();
870 auto Start
= PathDiagnosticLocation::createBegin(T
, SM
, LC
);
871 switch (T
->getStmtClass()) {
875 case Stmt::GotoStmtClass
:
876 case Stmt::IndirectGotoStmtClass
: {
877 if (const Stmt
*S
= C
.getCurrentNode()->getNextStmtForDiagnostics())
878 C
.getActivePath().push_front(generateDiagForGotoOP(C
, S
, Start
));
882 case Stmt::SwitchStmtClass
: {
883 C
.getActivePath().push_front(generateDiagForSwitchOP(C
, Dst
, Start
));
887 case Stmt::BreakStmtClass
:
888 case Stmt::ContinueStmtClass
: {
890 llvm::raw_string_ostream
os(sbuf
);
891 PathDiagnosticLocation End
= ExecutionContinues(os
, C
);
892 C
.getActivePath().push_front(
893 std::make_shared
<PathDiagnosticControlFlowPiece
>(Start
, End
, os
.str()));
897 // Determine control-flow for ternary '?'.
898 case Stmt::BinaryConditionalOperatorClass
:
899 case Stmt::ConditionalOperatorClass
: {
901 llvm::raw_string_ostream
os(sbuf
);
902 os
<< "'?' condition is ";
904 if (*(Src
->succ_begin() + 1) == Dst
)
909 PathDiagnosticLocation End
= ExecutionContinues(C
);
911 if (const Stmt
*S
= End
.asStmt())
912 End
= getEnclosingStmtLocation(S
, C
.getCurrLocationContext());
914 C
.getActivePath().push_front(
915 std::make_shared
<PathDiagnosticControlFlowPiece
>(Start
, End
, os
.str()));
919 // Determine control-flow for short-circuited '&&' and '||'.
920 case Stmt::BinaryOperatorClass
: {
921 if (!C
.supportsLogicalOpControlFlow())
924 C
.getActivePath().push_front(generateDiagForBinaryOP(C
, T
, Src
, Dst
));
928 case Stmt::DoStmtClass
:
929 if (*(Src
->succ_begin()) == Dst
) {
931 llvm::raw_string_ostream
os(sbuf
);
933 os
<< "Loop condition is true. ";
934 PathDiagnosticLocation End
= ExecutionContinues(os
, C
);
936 if (const Stmt
*S
= End
.asStmt())
937 End
= getEnclosingStmtLocation(S
, C
.getCurrLocationContext());
939 C
.getActivePath().push_front(
940 std::make_shared
<PathDiagnosticControlFlowPiece
>(Start
, End
,
943 PathDiagnosticLocation End
= ExecutionContinues(C
);
945 if (const Stmt
*S
= End
.asStmt())
946 End
= getEnclosingStmtLocation(S
, C
.getCurrLocationContext());
948 C
.getActivePath().push_front(
949 std::make_shared
<PathDiagnosticControlFlowPiece
>(
950 Start
, End
, "Loop condition is false. Exiting loop"));
954 case Stmt::WhileStmtClass
:
955 case Stmt::ForStmtClass
:
956 if (*(Src
->succ_begin() + 1) == Dst
) {
958 llvm::raw_string_ostream
os(sbuf
);
960 os
<< "Loop condition is false. ";
961 PathDiagnosticLocation End
= ExecutionContinues(os
, C
);
962 if (const Stmt
*S
= End
.asStmt())
963 End
= getEnclosingStmtLocation(S
, C
.getCurrLocationContext());
965 C
.getActivePath().push_front(
966 std::make_shared
<PathDiagnosticControlFlowPiece
>(Start
, End
,
969 PathDiagnosticLocation End
= ExecutionContinues(C
);
970 if (const Stmt
*S
= End
.asStmt())
971 End
= getEnclosingStmtLocation(S
, C
.getCurrLocationContext());
973 C
.getActivePath().push_front(
974 std::make_shared
<PathDiagnosticControlFlowPiece
>(
975 Start
, End
, "Loop condition is true. Entering loop body"));
980 case Stmt::IfStmtClass
: {
981 PathDiagnosticLocation End
= ExecutionContinues(C
);
983 if (const Stmt
*S
= End
.asStmt())
984 End
= getEnclosingStmtLocation(S
, C
.getCurrLocationContext());
986 if (*(Src
->succ_begin() + 1) == Dst
)
987 C
.getActivePath().push_front(
988 std::make_shared
<PathDiagnosticControlFlowPiece
>(
989 Start
, End
, "Taking false branch"));
991 C
.getActivePath().push_front(
992 std::make_shared
<PathDiagnosticControlFlowPiece
>(
993 Start
, End
, "Taking true branch"));
1000 //===----------------------------------------------------------------------===//
1001 // Functions for determining if a loop was executed 0 times.
1002 //===----------------------------------------------------------------------===//
1004 static bool isLoop(const Stmt
*Term
) {
1005 switch (Term
->getStmtClass()) {
1006 case Stmt::ForStmtClass
:
1007 case Stmt::WhileStmtClass
:
1008 case Stmt::ObjCForCollectionStmtClass
:
1009 case Stmt::CXXForRangeStmtClass
:
1012 // Note that we intentionally do not include do..while here.
1017 static bool isJumpToFalseBranch(const BlockEdge
*BE
) {
1018 const CFGBlock
*Src
= BE
->getSrc();
1019 assert(Src
->succ_size() == 2);
1020 return (*(Src
->succ_begin()+1) == BE
->getDst());
1023 static bool isContainedByStmt(const ParentMap
&PM
, const Stmt
*S
,
1028 SubS
= PM
.getParent(SubS
);
1033 static const Stmt
*getStmtBeforeCond(const ParentMap
&PM
, const Stmt
*Term
,
1034 const ExplodedNode
*N
) {
1036 std::optional
<StmtPoint
> SP
= N
->getLocation().getAs
<StmtPoint
>();
1038 const Stmt
*S
= SP
->getStmt();
1039 if (!isContainedByStmt(PM
, Term
, S
))
1042 N
= N
->getFirstPred();
1047 static bool isInLoopBody(const ParentMap
&PM
, const Stmt
*S
, const Stmt
*Term
) {
1048 const Stmt
*LoopBody
= nullptr;
1049 switch (Term
->getStmtClass()) {
1050 case Stmt::CXXForRangeStmtClass
: {
1051 const auto *FR
= cast
<CXXForRangeStmt
>(Term
);
1052 if (isContainedByStmt(PM
, FR
->getInc(), S
))
1054 if (isContainedByStmt(PM
, FR
->getLoopVarStmt(), S
))
1056 LoopBody
= FR
->getBody();
1059 case Stmt::ForStmtClass
: {
1060 const auto *FS
= cast
<ForStmt
>(Term
);
1061 if (isContainedByStmt(PM
, FS
->getInc(), S
))
1063 LoopBody
= FS
->getBody();
1066 case Stmt::ObjCForCollectionStmtClass
: {
1067 const auto *FC
= cast
<ObjCForCollectionStmt
>(Term
);
1068 LoopBody
= FC
->getBody();
1071 case Stmt::WhileStmtClass
:
1072 LoopBody
= cast
<WhileStmt
>(Term
)->getBody();
1077 return isContainedByStmt(PM
, LoopBody
, S
);
1080 /// Adds a sanitized control-flow diagnostic edge to a path.
1081 static void addEdgeToPath(PathPieces
&path
,
1082 PathDiagnosticLocation
&PrevLoc
,
1083 PathDiagnosticLocation NewLoc
) {
1084 if (!NewLoc
.isValid())
1087 SourceLocation NewLocL
= NewLoc
.asLocation();
1088 if (NewLocL
.isInvalid())
1091 if (!PrevLoc
.isValid() || !PrevLoc
.asLocation().isValid()) {
1096 // Ignore self-edges, which occur when there are multiple nodes at the same
1098 if (NewLoc
.asStmt() && NewLoc
.asStmt() == PrevLoc
.asStmt())
1102 std::make_shared
<PathDiagnosticControlFlowPiece
>(NewLoc
, PrevLoc
));
1106 /// A customized wrapper for CFGBlock::getTerminatorCondition()
1107 /// which returns the element for ObjCForCollectionStmts.
1108 static const Stmt
*getTerminatorCondition(const CFGBlock
*B
) {
1109 const Stmt
*S
= B
->getTerminatorCondition();
1110 if (const auto *FS
= dyn_cast_or_null
<ObjCForCollectionStmt
>(S
))
1111 return FS
->getElement();
1115 constexpr llvm::StringLiteral StrEnteringLoop
= "Entering loop body";
1116 constexpr llvm::StringLiteral StrLoopBodyZero
= "Loop body executed 0 times";
1117 constexpr llvm::StringLiteral StrLoopRangeEmpty
=
1118 "Loop body skipped when range is empty";
1119 constexpr llvm::StringLiteral StrLoopCollectionEmpty
=
1120 "Loop body skipped when collection is empty";
1122 static std::unique_ptr
<FilesToLineNumsMap
>
1123 findExecutedLines(const SourceManager
&SM
, const ExplodedNode
*N
);
1125 void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
1126 PathDiagnosticConstruct
&C
, PathDiagnosticLocation
&PrevLoc
) const {
1127 ProgramPoint P
= C
.getCurrentNode()->getLocation();
1128 const SourceManager
&SM
= getSourceManager();
1130 // Have we encountered an entrance to a call? It may be
1131 // the case that we have not encountered a matching
1132 // call exit before this point. This means that the path
1133 // terminated within the call itself.
1134 if (auto CE
= P
.getAs
<CallEnter
>()) {
1136 if (C
.shouldAddPathEdges()) {
1137 // Add an edge to the start of the function.
1138 const StackFrameContext
*CalleeLC
= CE
->getCalleeContext();
1139 const Decl
*D
= CalleeLC
->getDecl();
1140 // Add the edge only when the callee has body. We jump to the beginning
1141 // of the *declaration*, however we expect it to be followed by the
1142 // body. This isn't the case for autosynthesized property accessors in
1143 // Objective-C. No need for a similar extra check for CallExit points
1144 // because the exit edge comes from a statement (i.e. return),
1145 // not from declaration.
1147 addEdgeToPath(C
.getActivePath(), PrevLoc
,
1148 PathDiagnosticLocation::createBegin(D
, SM
));
1151 // Did we visit an entire call?
1152 bool VisitedEntireCall
= C
.PD
->isWithinCall();
1153 C
.PD
->popActivePath();
1155 PathDiagnosticCallPiece
*Call
;
1156 if (VisitedEntireCall
) {
1157 Call
= cast
<PathDiagnosticCallPiece
>(C
.getActivePath().front().get());
1159 // The path terminated within a nested location context, create a new
1160 // call piece to encapsulate the rest of the path pieces.
1161 const Decl
*Caller
= CE
->getLocationContext()->getDecl();
1162 Call
= PathDiagnosticCallPiece::construct(C
.getActivePath(), Caller
);
1163 assert(C
.getActivePath().size() == 1 &&
1164 C
.getActivePath().front().get() == Call
);
1166 // Since we just transferred the path over to the call piece, reset the
1167 // mapping of the active path to the current location context.
1168 assert(C
.isInLocCtxMap(&C
.getActivePath()) &&
1169 "When we ascend to a previously unvisited call, the active path's "
1170 "address shouldn't change, but rather should be compacted into "
1171 "a single CallEvent!");
1172 C
.updateLocCtxMap(&C
.getActivePath(), C
.getCurrLocationContext());
1174 // Record the location context mapping for the path within the call.
1175 assert(!C
.isInLocCtxMap(&Call
->path
) &&
1176 "When we ascend to a previously unvisited call, this must be the "
1177 "first time we encounter the caller context!");
1178 C
.updateLocCtxMap(&Call
->path
, CE
->getCalleeContext());
1180 Call
->setCallee(*CE
, SM
);
1182 // Update the previous location in the active path.
1183 PrevLoc
= Call
->getLocation();
1185 if (!C
.CallStack
.empty()) {
1186 assert(C
.CallStack
.back().first
== Call
);
1187 C
.CallStack
.pop_back();
1192 assert(C
.getCurrLocationContext() == C
.getLocationContextForActivePath() &&
1193 "The current position in the bug path is out of sync with the "
1194 "location context associated with the active path!");
1196 // Have we encountered an exit from a function call?
1197 if (std::optional
<CallExitEnd
> CE
= P
.getAs
<CallExitEnd
>()) {
1199 // We are descending into a call (backwards). Construct
1200 // a new call piece to contain the path pieces for that call.
1201 auto Call
= PathDiagnosticCallPiece::construct(*CE
, SM
);
1202 // Record the mapping from call piece to LocationContext.
1203 assert(!C
.isInLocCtxMap(&Call
->path
) &&
1204 "We just entered a call, this must've been the first time we "
1205 "encounter its context!");
1206 C
.updateLocCtxMap(&Call
->path
, CE
->getCalleeContext());
1208 if (C
.shouldAddPathEdges()) {
1209 // Add the edge to the return site.
1210 addEdgeToPath(C
.getActivePath(), PrevLoc
, Call
->callReturn
);
1211 PrevLoc
.invalidate();
1214 auto *P
= Call
.get();
1215 C
.getActivePath().push_front(std::move(Call
));
1217 // Make the contents of the call the active path for now.
1218 C
.PD
->pushActivePath(&P
->path
);
1219 C
.CallStack
.push_back(CallWithEntry(P
, C
.getCurrentNode()));
1223 if (auto PS
= P
.getAs
<PostStmt
>()) {
1224 if (!C
.shouldAddPathEdges())
1227 // Add an edge. If this is an ObjCForCollectionStmt do
1228 // not add an edge here as it appears in the CFG both
1229 // as a terminator and as a terminator condition.
1230 if (!isa
<ObjCForCollectionStmt
>(PS
->getStmt())) {
1231 PathDiagnosticLocation L
=
1232 PathDiagnosticLocation(PS
->getStmt(), SM
, C
.getCurrLocationContext());
1233 addEdgeToPath(C
.getActivePath(), PrevLoc
, L
);
1236 } else if (auto BE
= P
.getAs
<BlockEdge
>()) {
1238 if (C
.shouldAddControlNotes()) {
1239 generateMinimalDiagForBlockEdge(C
, *BE
);
1242 if (!C
.shouldAddPathEdges()) {
1246 // Are we jumping to the head of a loop? Add a special diagnostic.
1247 if (const Stmt
*Loop
= BE
->getSrc()->getLoopTarget()) {
1248 PathDiagnosticLocation
L(Loop
, SM
, C
.getCurrLocationContext());
1249 const Stmt
*Body
= nullptr;
1251 if (const auto *FS
= dyn_cast
<ForStmt
>(Loop
))
1252 Body
= FS
->getBody();
1253 else if (const auto *WS
= dyn_cast
<WhileStmt
>(Loop
))
1254 Body
= WS
->getBody();
1255 else if (const auto *OFS
= dyn_cast
<ObjCForCollectionStmt
>(Loop
)) {
1256 Body
= OFS
->getBody();
1257 } else if (const auto *FRS
= dyn_cast
<CXXForRangeStmt
>(Loop
)) {
1258 Body
= FRS
->getBody();
1260 // do-while statements are explicitly excluded here
1262 auto p
= std::make_shared
<PathDiagnosticEventPiece
>(
1263 L
, "Looping back to the head of the loop");
1264 p
->setPrunable(true);
1266 addEdgeToPath(C
.getActivePath(), PrevLoc
, p
->getLocation());
1267 // We might've added a very similar control node already
1268 if (!C
.shouldAddControlNotes()) {
1269 C
.getActivePath().push_front(std::move(p
));
1272 if (const auto *CS
= dyn_cast_or_null
<CompoundStmt
>(Body
)) {
1273 addEdgeToPath(C
.getActivePath(), PrevLoc
,
1274 PathDiagnosticLocation::createEndBrace(CS
, SM
));
1278 const CFGBlock
*BSrc
= BE
->getSrc();
1279 const ParentMap
&PM
= C
.getParentMap();
1281 if (const Stmt
*Term
= BSrc
->getTerminatorStmt()) {
1282 // Are we jumping past the loop body without ever executing the
1283 // loop (because the condition was false)?
1285 const Stmt
*TermCond
= getTerminatorCondition(BSrc
);
1286 bool IsInLoopBody
= isInLoopBody(
1287 PM
, getStmtBeforeCond(PM
, TermCond
, C
.getCurrentNode()), Term
);
1291 if (isJumpToFalseBranch(&*BE
)) {
1292 if (!IsInLoopBody
) {
1293 if (isa
<ObjCForCollectionStmt
>(Term
)) {
1294 str
= StrLoopCollectionEmpty
;
1295 } else if (isa
<CXXForRangeStmt
>(Term
)) {
1296 str
= StrLoopRangeEmpty
;
1298 str
= StrLoopBodyZero
;
1302 str
= StrEnteringLoop
;
1306 PathDiagnosticLocation
L(TermCond
? TermCond
: Term
, SM
,
1307 C
.getCurrLocationContext());
1308 auto PE
= std::make_shared
<PathDiagnosticEventPiece
>(L
, str
);
1309 PE
->setPrunable(true);
1310 addEdgeToPath(C
.getActivePath(), PrevLoc
, PE
->getLocation());
1312 // We might've added a very similar control node already
1313 if (!C
.shouldAddControlNotes()) {
1314 C
.getActivePath().push_front(std::move(PE
));
1317 } else if (isa
<BreakStmt
, ContinueStmt
, GotoStmt
>(Term
)) {
1318 PathDiagnosticLocation
L(Term
, SM
, C
.getCurrLocationContext());
1319 addEdgeToPath(C
.getActivePath(), PrevLoc
, L
);
1325 static std::unique_ptr
<PathDiagnostic
>
1326 generateDiagnosticForBasicReport(const BasicBugReport
*R
) {
1327 const BugType
&BT
= R
->getBugType();
1328 return std::make_unique
<PathDiagnostic
>(
1329 BT
.getCheckerName(), R
->getDeclWithIssue(), BT
.getDescription(),
1330 R
->getDescription(), R
->getShortDescription(/*UseFallback=*/false),
1331 BT
.getCategory(), R
->getUniqueingLocation(), R
->getUniqueingDecl(),
1332 std::make_unique
<FilesToLineNumsMap
>());
1335 static std::unique_ptr
<PathDiagnostic
>
1336 generateEmptyDiagnosticForReport(const PathSensitiveBugReport
*R
,
1337 const SourceManager
&SM
) {
1338 const BugType
&BT
= R
->getBugType();
1339 return std::make_unique
<PathDiagnostic
>(
1340 BT
.getCheckerName(), R
->getDeclWithIssue(), BT
.getDescription(),
1341 R
->getDescription(), R
->getShortDescription(/*UseFallback=*/false),
1342 BT
.getCategory(), R
->getUniqueingLocation(), R
->getUniqueingDecl(),
1343 findExecutedLines(SM
, R
->getErrorNode()));
1346 static const Stmt
*getStmtParent(const Stmt
*S
, const ParentMap
&PM
) {
1351 S
= PM
.getParentIgnoreParens(S
);
1356 if (isa
<FullExpr
, CXXBindTemporaryExpr
, SubstNonTypeTemplateParmExpr
>(S
))
1365 static bool isConditionForTerminator(const Stmt
*S
, const Stmt
*Cond
) {
1366 switch (S
->getStmtClass()) {
1367 case Stmt::BinaryOperatorClass
: {
1368 const auto *BO
= cast
<BinaryOperator
>(S
);
1369 if (!BO
->isLogicalOp())
1371 return BO
->getLHS() == Cond
|| BO
->getRHS() == Cond
;
1373 case Stmt::IfStmtClass
:
1374 return cast
<IfStmt
>(S
)->getCond() == Cond
;
1375 case Stmt::ForStmtClass
:
1376 return cast
<ForStmt
>(S
)->getCond() == Cond
;
1377 case Stmt::WhileStmtClass
:
1378 return cast
<WhileStmt
>(S
)->getCond() == Cond
;
1379 case Stmt::DoStmtClass
:
1380 return cast
<DoStmt
>(S
)->getCond() == Cond
;
1381 case Stmt::ChooseExprClass
:
1382 return cast
<ChooseExpr
>(S
)->getCond() == Cond
;
1383 case Stmt::IndirectGotoStmtClass
:
1384 return cast
<IndirectGotoStmt
>(S
)->getTarget() == Cond
;
1385 case Stmt::SwitchStmtClass
:
1386 return cast
<SwitchStmt
>(S
)->getCond() == Cond
;
1387 case Stmt::BinaryConditionalOperatorClass
:
1388 return cast
<BinaryConditionalOperator
>(S
)->getCond() == Cond
;
1389 case Stmt::ConditionalOperatorClass
: {
1390 const auto *CO
= cast
<ConditionalOperator
>(S
);
1391 return CO
->getCond() == Cond
||
1392 CO
->getLHS() == Cond
||
1393 CO
->getRHS() == Cond
;
1395 case Stmt::ObjCForCollectionStmtClass
:
1396 return cast
<ObjCForCollectionStmt
>(S
)->getElement() == Cond
;
1397 case Stmt::CXXForRangeStmtClass
: {
1398 const auto *FRS
= cast
<CXXForRangeStmt
>(S
);
1399 return FRS
->getCond() == Cond
|| FRS
->getRangeInit() == Cond
;
1406 static bool isIncrementOrInitInForLoop(const Stmt
*S
, const Stmt
*FL
) {
1407 if (const auto *FS
= dyn_cast
<ForStmt
>(FL
))
1408 return FS
->getInc() == S
|| FS
->getInit() == S
;
1409 if (const auto *FRS
= dyn_cast
<CXXForRangeStmt
>(FL
))
1410 return FRS
->getInc() == S
|| FRS
->getRangeStmt() == S
||
1411 FRS
->getLoopVarStmt() || FRS
->getRangeInit() == S
;
1415 using OptimizedCallsSet
= llvm::DenseSet
<const PathDiagnosticCallPiece
*>;
1417 /// Adds synthetic edges from top-level statements to their subexpressions.
1419 /// This avoids a "swoosh" effect, where an edge from a top-level statement A
1420 /// points to a sub-expression B.1 that's not at the start of B. In these cases,
1421 /// we'd like to see an edge from A to B, then another one from B to B.1.
1422 static void addContextEdges(PathPieces
&pieces
, const LocationContext
*LC
) {
1423 const ParentMap
&PM
= LC
->getParentMap();
1424 PathPieces::iterator Prev
= pieces
.end();
1425 for (PathPieces::iterator I
= pieces
.begin(), E
= Prev
; I
!= E
;
1427 auto *Piece
= dyn_cast
<PathDiagnosticControlFlowPiece
>(I
->get());
1432 PathDiagnosticLocation SrcLoc
= Piece
->getStartLocation();
1433 SmallVector
<PathDiagnosticLocation
, 4> SrcContexts
;
1435 PathDiagnosticLocation NextSrcContext
= SrcLoc
;
1436 const Stmt
*InnerStmt
= nullptr;
1437 while (NextSrcContext
.isValid() && NextSrcContext
.asStmt() != InnerStmt
) {
1438 SrcContexts
.push_back(NextSrcContext
);
1439 InnerStmt
= NextSrcContext
.asStmt();
1440 NextSrcContext
= getEnclosingStmtLocation(InnerStmt
, LC
,
1441 /*allowNested=*/true);
1444 // Repeatedly split the edge as necessary.
1445 // This is important for nested logical expressions (||, &&, ?:) where we
1446 // want to show all the levels of context.
1448 const Stmt
*Dst
= Piece
->getEndLocation().getStmtOrNull();
1450 // We are looking at an edge. Is the destination within a larger
1452 PathDiagnosticLocation DstContext
=
1453 getEnclosingStmtLocation(Dst
, LC
, /*allowNested=*/true);
1454 if (!DstContext
.isValid() || DstContext
.asStmt() == Dst
)
1457 // If the source is in the same context, we're already good.
1458 if (llvm::is_contained(SrcContexts
, DstContext
))
1461 // Update the subexpression node to point to the context edge.
1462 Piece
->setStartLocation(DstContext
);
1464 // Try to extend the previous edge if it's at the same level as the source
1467 auto *PrevPiece
= dyn_cast
<PathDiagnosticControlFlowPiece
>(Prev
->get());
1470 if (const Stmt
*PrevSrc
=
1471 PrevPiece
->getStartLocation().getStmtOrNull()) {
1472 const Stmt
*PrevSrcParent
= getStmtParent(PrevSrc
, PM
);
1473 if (PrevSrcParent
==
1474 getStmtParent(DstContext
.getStmtOrNull(), PM
)) {
1475 PrevPiece
->setEndLocation(DstContext
);
1482 // Otherwise, split the current edge into a context edge and a
1483 // subexpression edge. Note that the context statement may itself have
1486 std::make_shared
<PathDiagnosticControlFlowPiece
>(SrcLoc
, DstContext
);
1488 I
= pieces
.insert(I
, std::move(P
));
1493 /// Move edges from a branch condition to a branch target
1494 /// when the condition is simple.
1496 /// This restructures some of the work of addContextEdges. That function
1497 /// creates edges this may destroy, but they work together to create a more
1498 /// aesthetically set of edges around branches. After the call to
1499 /// addContextEdges, we may have (1) an edge to the branch, (2) an edge from
1500 /// the branch to the branch condition, and (3) an edge from the branch
1501 /// condition to the branch target. We keep (1), but may wish to remove (2)
1502 /// and move the source of (3) to the branch if the branch condition is simple.
1503 static void simplifySimpleBranches(PathPieces
&pieces
) {
1504 for (PathPieces::iterator I
= pieces
.begin(), E
= pieces
.end(); I
!= E
; ++I
) {
1505 const auto *PieceI
= dyn_cast
<PathDiagnosticControlFlowPiece
>(I
->get());
1510 const Stmt
*s1Start
= PieceI
->getStartLocation().getStmtOrNull();
1511 const Stmt
*s1End
= PieceI
->getEndLocation().getStmtOrNull();
1513 if (!s1Start
|| !s1End
)
1516 PathPieces::iterator NextI
= I
; ++NextI
;
1520 PathDiagnosticControlFlowPiece
*PieceNextI
= nullptr;
1526 const auto *EV
= dyn_cast
<PathDiagnosticEventPiece
>(NextI
->get());
1528 StringRef S
= EV
->getString();
1529 if (S
== StrEnteringLoop
|| S
== StrLoopBodyZero
||
1530 S
== StrLoopCollectionEmpty
|| S
== StrLoopRangeEmpty
) {
1537 PieceNextI
= dyn_cast
<PathDiagnosticControlFlowPiece
>(NextI
->get());
1544 const Stmt
*s2Start
= PieceNextI
->getStartLocation().getStmtOrNull();
1545 const Stmt
*s2End
= PieceNextI
->getEndLocation().getStmtOrNull();
1547 if (!s2Start
|| !s2End
|| s1End
!= s2Start
)
1550 // We only perform this transformation for specific branch kinds.
1551 // We don't want to do this for do..while, for example.
1552 if (!isa
<ForStmt
, WhileStmt
, IfStmt
, ObjCForCollectionStmt
,
1553 CXXForRangeStmt
>(s1Start
))
1556 // Is s1End the branch condition?
1557 if (!isConditionForTerminator(s1Start
, s1End
))
1560 // Perform the hoisting by eliminating (2) and changing the start
1562 PieceNextI
->setStartLocation(PieceI
->getStartLocation());
1563 I
= pieces
.erase(I
);
1567 /// Returns the number of bytes in the given (character-based) SourceRange.
1569 /// If the locations in the range are not on the same line, returns
1572 /// Note that this does not do a precise user-visible character or column count.
1573 static std::optional
<size_t> getLengthOnSingleLine(const SourceManager
&SM
,
1574 SourceRange Range
) {
1575 SourceRange
ExpansionRange(SM
.getExpansionLoc(Range
.getBegin()),
1576 SM
.getExpansionRange(Range
.getEnd()).getEnd());
1578 FileID FID
= SM
.getFileID(ExpansionRange
.getBegin());
1579 if (FID
!= SM
.getFileID(ExpansionRange
.getEnd()))
1580 return std::nullopt
;
1582 std::optional
<MemoryBufferRef
> Buffer
= SM
.getBufferOrNone(FID
);
1584 return std::nullopt
;
1586 unsigned BeginOffset
= SM
.getFileOffset(ExpansionRange
.getBegin());
1587 unsigned EndOffset
= SM
.getFileOffset(ExpansionRange
.getEnd());
1588 StringRef Snippet
= Buffer
->getBuffer().slice(BeginOffset
, EndOffset
);
1590 // We're searching the raw bytes of the buffer here, which might include
1591 // escaped newlines and such. That's okay; we're trying to decide whether the
1592 // SourceRange is covering a large or small amount of space in the user's
1594 if (Snippet
.find_first_of("\r\n") != StringRef::npos
)
1595 return std::nullopt
;
1597 // This isn't Unicode-aware, but it doesn't need to be.
1598 return Snippet
.size();
1601 /// \sa getLengthOnSingleLine(SourceManager, SourceRange)
1602 static std::optional
<size_t> getLengthOnSingleLine(const SourceManager
&SM
,
1604 return getLengthOnSingleLine(SM
, S
->getSourceRange());
1607 /// Eliminate two-edge cycles created by addContextEdges().
1609 /// Once all the context edges are in place, there are plenty of cases where
1610 /// there's a single edge from a top-level statement to a subexpression,
1611 /// followed by a single path note, and then a reverse edge to get back out to
1612 /// the top level. If the statement is simple enough, the subexpression edges
1613 /// just add noise and make it harder to understand what's going on.
1615 /// This function only removes edges in pairs, because removing only one edge
1616 /// might leave other edges dangling.
1618 /// This will not remove edges in more complicated situations:
1619 /// - if there is more than one "hop" leading to or from a subexpression.
1620 /// - if there is an inlined call between the edges instead of a single event.
1621 /// - if the whole statement is large enough that having subexpression arrows
1622 /// might be helpful.
1623 static void removeContextCycles(PathPieces
&Path
, const SourceManager
&SM
) {
1624 for (PathPieces::iterator I
= Path
.begin(), E
= Path
.end(); I
!= E
; ) {
1625 // Pattern match the current piece and its successor.
1626 const auto *PieceI
= dyn_cast
<PathDiagnosticControlFlowPiece
>(I
->get());
1633 const Stmt
*s1Start
= PieceI
->getStartLocation().getStmtOrNull();
1634 const Stmt
*s1End
= PieceI
->getEndLocation().getStmtOrNull();
1636 PathPieces::iterator NextI
= I
; ++NextI
;
1640 const auto *PieceNextI
=
1641 dyn_cast
<PathDiagnosticControlFlowPiece
>(NextI
->get());
1644 if (isa
<PathDiagnosticEventPiece
>(NextI
->get())) {
1648 PieceNextI
= dyn_cast
<PathDiagnosticControlFlowPiece
>(NextI
->get());
1657 const Stmt
*s2Start
= PieceNextI
->getStartLocation().getStmtOrNull();
1658 const Stmt
*s2End
= PieceNextI
->getEndLocation().getStmtOrNull();
1660 if (s1Start
&& s2Start
&& s1Start
== s2End
&& s2Start
== s1End
) {
1661 const size_t MAX_SHORT_LINE_LENGTH
= 80;
1662 std::optional
<size_t> s1Length
= getLengthOnSingleLine(SM
, s1Start
);
1663 if (s1Length
&& *s1Length
<= MAX_SHORT_LINE_LENGTH
) {
1664 std::optional
<size_t> s2Length
= getLengthOnSingleLine(SM
, s2Start
);
1665 if (s2Length
&& *s2Length
<= MAX_SHORT_LINE_LENGTH
) {
1667 I
= Path
.erase(NextI
);
1677 /// Return true if X is contained by Y.
1678 static bool lexicalContains(const ParentMap
&PM
, const Stmt
*X
, const Stmt
*Y
) {
1682 X
= PM
.getParent(X
);
1687 // Remove short edges on the same line less than 3 columns in difference.
1688 static void removePunyEdges(PathPieces
&path
, const SourceManager
&SM
,
1689 const ParentMap
&PM
) {
1690 bool erased
= false;
1692 for (PathPieces::iterator I
= path
.begin(), E
= path
.end(); I
!= E
;
1696 const auto *PieceI
= dyn_cast
<PathDiagnosticControlFlowPiece
>(I
->get());
1701 const Stmt
*start
= PieceI
->getStartLocation().getStmtOrNull();
1702 const Stmt
*end
= PieceI
->getEndLocation().getStmtOrNull();
1707 const Stmt
*endParent
= PM
.getParent(end
);
1711 if (isConditionForTerminator(end
, endParent
))
1714 SourceLocation FirstLoc
= start
->getBeginLoc();
1715 SourceLocation SecondLoc
= end
->getBeginLoc();
1717 if (!SM
.isWrittenInSameFile(FirstLoc
, SecondLoc
))
1719 if (SM
.isBeforeInTranslationUnit(SecondLoc
, FirstLoc
))
1720 std::swap(SecondLoc
, FirstLoc
);
1722 SourceRange
EdgeRange(FirstLoc
, SecondLoc
);
1723 std::optional
<size_t> ByteWidth
= getLengthOnSingleLine(SM
, EdgeRange
);
1725 // If the statements are on different lines, continue.
1729 const size_t MAX_PUNY_EDGE_LENGTH
= 2;
1730 if (*ByteWidth
<= MAX_PUNY_EDGE_LENGTH
) {
1731 // FIXME: There are enough /bytes/ between the endpoints of the edge, but
1732 // there might not be enough /columns/. A proper user-visible column count
1733 // is probably too expensive, though.
1741 static void removeIdenticalEvents(PathPieces
&path
) {
1742 for (PathPieces::iterator I
= path
.begin(), E
= path
.end(); I
!= E
; ++I
) {
1743 const auto *PieceI
= dyn_cast
<PathDiagnosticEventPiece
>(I
->get());
1748 PathPieces::iterator NextI
= I
; ++NextI
;
1752 const auto *PieceNextI
= dyn_cast
<PathDiagnosticEventPiece
>(NextI
->get());
1757 // Erase the second piece if it has the same exact message text.
1758 if (PieceI
->getString() == PieceNextI
->getString()) {
1764 static bool optimizeEdges(const PathDiagnosticConstruct
&C
, PathPieces
&path
,
1765 OptimizedCallsSet
&OCS
) {
1766 bool hasChanges
= false;
1767 const LocationContext
*LC
= C
.getLocationContextFor(&path
);
1769 const ParentMap
&PM
= LC
->getParentMap();
1770 const SourceManager
&SM
= C
.getSourceManager();
1772 for (PathPieces::iterator I
= path
.begin(), E
= path
.end(); I
!= E
; ) {
1773 // Optimize subpaths.
1774 if (auto *CallI
= dyn_cast
<PathDiagnosticCallPiece
>(I
->get())) {
1775 // Record the fact that a call has been optimized so we only do the
1777 if (!OCS
.count(CallI
)) {
1778 while (optimizeEdges(C
, CallI
->path
, OCS
)) {
1786 // Pattern match the current piece and its successor.
1787 auto *PieceI
= dyn_cast
<PathDiagnosticControlFlowPiece
>(I
->get());
1794 const Stmt
*s1Start
= PieceI
->getStartLocation().getStmtOrNull();
1795 const Stmt
*s1End
= PieceI
->getEndLocation().getStmtOrNull();
1796 const Stmt
*level1
= getStmtParent(s1Start
, PM
);
1797 const Stmt
*level2
= getStmtParent(s1End
, PM
);
1799 PathPieces::iterator NextI
= I
; ++NextI
;
1803 const auto *PieceNextI
= dyn_cast
<PathDiagnosticControlFlowPiece
>(NextI
->get());
1810 const Stmt
*s2Start
= PieceNextI
->getStartLocation().getStmtOrNull();
1811 const Stmt
*s2End
= PieceNextI
->getEndLocation().getStmtOrNull();
1812 const Stmt
*level3
= getStmtParent(s2Start
, PM
);
1813 const Stmt
*level4
= getStmtParent(s2End
, PM
);
1817 // If we have two consecutive control edges whose end/begin locations
1818 // are at the same level (e.g. statements or top-level expressions within
1819 // a compound statement, or siblings share a single ancestor expression),
1820 // then merge them if they have no interesting intermediate event.
1824 // (1.1 -> 1.2) -> (1.2 -> 1.3) becomes (1.1 -> 1.3) because the common
1825 // parent is '1'. Here 'x.y.z' represents the hierarchy of statements.
1827 // NOTE: this will be limited later in cases where we add barriers
1828 // to prevent this optimization.
1829 if (level1
&& level1
== level2
&& level1
== level3
&& level1
== level4
) {
1830 PieceI
->setEndLocation(PieceNextI
->getEndLocation());
1838 // Eliminate edges between subexpressions and parent expressions
1839 // when the subexpression is consumed.
1841 // NOTE: this will be limited later in cases where we add barriers
1842 // to prevent this optimization.
1843 if (s1End
&& s1End
== s2Start
&& level2
) {
1844 bool removeEdge
= false;
1845 // Remove edges into the increment or initialization of a
1846 // loop that have no interleaving event. This means that
1847 // they aren't interesting.
1848 if (isIncrementOrInitInForLoop(s1End
, level2
))
1850 // Next only consider edges that are not anchored on
1851 // the condition of a terminator. This are intermediate edges
1852 // that we might want to trim.
1853 else if (!isConditionForTerminator(level2
, s1End
)) {
1854 // Trim edges on expressions that are consumed by
1855 // the parent expression.
1856 if (isa
<Expr
>(s1End
) && PM
.isConsumedExpr(cast
<Expr
>(s1End
))) {
1859 // Trim edges where a lexical containment doesn't exist.
1864 // If 'Z' lexically contains Y (it is an ancestor) and
1865 // 'X' does not lexically contain Y (it is a descendant OR
1866 // it has no lexical relationship at all) then trim.
1868 // This can eliminate edges where we dive into a subexpression
1869 // and then pop back out, etc.
1870 else if (s1Start
&& s2End
&&
1871 lexicalContains(PM
, s2Start
, s2End
) &&
1872 !lexicalContains(PM
, s1End
, s1Start
)) {
1875 // Trim edges from a subexpression back to the top level if the
1876 // subexpression is on a different line.
1882 // These edges just look ugly and don't usually add anything.
1883 else if (s1Start
&& s2End
&&
1884 lexicalContains(PM
, s1Start
, s1End
)) {
1885 SourceRange
EdgeRange(PieceI
->getEndLocation().asLocation(),
1886 PieceI
->getStartLocation().asLocation());
1887 if (!getLengthOnSingleLine(SM
, EdgeRange
))
1893 PieceI
->setEndLocation(PieceNextI
->getEndLocation());
1900 // Optimize edges for ObjC fast-enumeration loops.
1902 // (X -> collection) -> (collection -> element)
1907 if (s1End
== s2Start
) {
1908 const auto *FS
= dyn_cast_or_null
<ObjCForCollectionStmt
>(level3
);
1909 if (FS
&& FS
->getCollection()->IgnoreParens() == s2Start
&&
1910 s2End
== FS
->getElement()) {
1911 PieceI
->setEndLocation(PieceNextI
->getEndLocation());
1918 // No changes at this index? Move to the next one.
1923 // Adjust edges into subexpressions to make them more uniform
1924 // and aesthetically pleasing.
1925 addContextEdges(path
, LC
);
1926 // Remove "cyclical" edges that include one or more context edges.
1927 removeContextCycles(path
, SM
);
1928 // Hoist edges originating from branch conditions to branches
1929 // for simple branches.
1930 simplifySimpleBranches(path
);
1931 // Remove any puny edges left over after primary optimization pass.
1932 removePunyEdges(path
, SM
, PM
);
1933 // Remove identical events.
1934 removeIdenticalEvents(path
);
1940 /// Drop the very first edge in a path, which should be a function entry edge.
1942 /// If the first edge is not a function entry edge (say, because the first
1943 /// statement had an invalid source location), this function does nothing.
1944 // FIXME: We should just generate invalid edges anyway and have the optimizer
1946 static void dropFunctionEntryEdge(const PathDiagnosticConstruct
&C
,
1948 const auto *FirstEdge
=
1949 dyn_cast
<PathDiagnosticControlFlowPiece
>(Path
.front().get());
1953 const Decl
*D
= C
.getLocationContextFor(&Path
)->getDecl();
1954 PathDiagnosticLocation EntryLoc
=
1955 PathDiagnosticLocation::createBegin(D
, C
.getSourceManager());
1956 if (FirstEdge
->getStartLocation() != EntryLoc
)
1962 /// Populate executes lines with lines containing at least one diagnostics.
1963 static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic
&PD
) {
1965 PathPieces path
= PD
.path
.flatten(/*ShouldFlattenMacros=*/true);
1966 FilesToLineNumsMap
&ExecutedLines
= PD
.getExecutedLines();
1968 for (const auto &P
: path
) {
1969 FullSourceLoc Loc
= P
->getLocation().asLocation().getExpansionLoc();
1970 FileID FID
= Loc
.getFileID();
1971 unsigned LineNo
= Loc
.getLineNumber();
1972 assert(FID
.isValid());
1973 ExecutedLines
[FID
].insert(LineNo
);
1977 PathDiagnosticConstruct::PathDiagnosticConstruct(
1978 const PathDiagnosticConsumer
*PDC
, const ExplodedNode
*ErrorNode
,
1979 const PathSensitiveBugReport
*R
)
1980 : Consumer(PDC
), CurrentNode(ErrorNode
),
1981 SM(CurrentNode
->getCodeDecl().getASTContext().getSourceManager()),
1982 PD(generateEmptyDiagnosticForReport(R
, getSourceManager())) {
1983 LCM
[&PD
->getActivePath()] = ErrorNode
->getLocationContext();
1986 PathDiagnosticBuilder::PathDiagnosticBuilder(
1987 BugReporterContext BRC
, std::unique_ptr
<ExplodedGraph
> BugPath
,
1988 PathSensitiveBugReport
*r
, const ExplodedNode
*ErrorNode
,
1989 std::unique_ptr
<VisitorsDiagnosticsTy
> VisitorsDiagnostics
)
1990 : BugReporterContext(BRC
), BugPath(std::move(BugPath
)), R(r
),
1991 ErrorNode(ErrorNode
),
1992 VisitorsDiagnostics(std::move(VisitorsDiagnostics
)) {}
1994 std::unique_ptr
<PathDiagnostic
>
1995 PathDiagnosticBuilder::generate(const PathDiagnosticConsumer
*PDC
) const {
1996 PathDiagnosticConstruct
Construct(PDC
, ErrorNode
, R
);
1998 const SourceManager
&SM
= getSourceManager();
1999 const AnalyzerOptions
&Opts
= getAnalyzerOptions();
2001 if (!PDC
->shouldGenerateDiagnostics())
2002 return generateEmptyDiagnosticForReport(R
, getSourceManager());
2004 // Construct the final (warning) event for the bug report.
2005 auto EndNotes
= VisitorsDiagnostics
->find(ErrorNode
);
2006 PathDiagnosticPieceRef LastPiece
;
2007 if (EndNotes
!= VisitorsDiagnostics
->end()) {
2008 assert(!EndNotes
->second
.empty());
2009 LastPiece
= EndNotes
->second
[0];
2011 LastPiece
= BugReporterVisitor::getDefaultEndPath(*this, ErrorNode
,
2014 Construct
.PD
->setEndOfPath(LastPiece
);
2016 PathDiagnosticLocation PrevLoc
= Construct
.PD
->getLocation();
2017 // From the error node to the root, ascend the bug path and construct the bug
2019 while (Construct
.ascendToPrevNode()) {
2020 generatePathDiagnosticsForNode(Construct
, PrevLoc
);
2022 auto VisitorNotes
= VisitorsDiagnostics
->find(Construct
.getCurrentNode());
2023 if (VisitorNotes
== VisitorsDiagnostics
->end())
2026 // This is a workaround due to inability to put shared PathDiagnosticPiece
2027 // into a FoldingSet.
2028 std::set
<llvm::FoldingSetNodeID
> DeduplicationSet
;
2030 // Add pieces from custom visitors.
2031 for (const PathDiagnosticPieceRef
&Note
: VisitorNotes
->second
) {
2032 llvm::FoldingSetNodeID ID
;
2034 if (!DeduplicationSet
.insert(ID
).second
)
2037 if (PDC
->shouldAddPathEdges())
2038 addEdgeToPath(Construct
.getActivePath(), PrevLoc
, Note
->getLocation());
2039 updateStackPiecesWithMessage(Note
, Construct
.CallStack
);
2040 Construct
.getActivePath().push_front(Note
);
2044 if (PDC
->shouldAddPathEdges()) {
2045 // Add an edge to the start of the function.
2046 // We'll prune it out later, but it helps make diagnostics more uniform.
2047 const StackFrameContext
*CalleeLC
=
2048 Construct
.getLocationContextForActivePath()->getStackFrame();
2049 const Decl
*D
= CalleeLC
->getDecl();
2050 addEdgeToPath(Construct
.getActivePath(), PrevLoc
,
2051 PathDiagnosticLocation::createBegin(D
, SM
));
2055 // Finally, prune the diagnostic path of uninteresting stuff.
2056 if (!Construct
.PD
->path
.empty()) {
2057 if (R
->shouldPrunePath() && Opts
.ShouldPrunePaths
) {
2058 bool stillHasNotes
=
2059 removeUnneededCalls(Construct
, Construct
.getMutablePieces(), R
);
2060 assert(stillHasNotes
);
2061 (void)stillHasNotes
;
2064 // Remove pop-up notes if needed.
2065 if (!Opts
.ShouldAddPopUpNotes
)
2066 removePopUpNotes(Construct
.getMutablePieces());
2068 // Redirect all call pieces to have valid locations.
2069 adjustCallLocations(Construct
.getMutablePieces());
2070 removePiecesWithInvalidLocations(Construct
.getMutablePieces());
2072 if (PDC
->shouldAddPathEdges()) {
2074 // Reduce the number of edges from a very conservative set
2075 // to an aesthetically pleasing subset that conveys the
2076 // necessary information.
2077 OptimizedCallsSet OCS
;
2078 while (optimizeEdges(Construct
, Construct
.getMutablePieces(), OCS
)) {
2081 // Drop the very first function-entry edge. It's not really necessary
2082 // for top-level functions.
2083 dropFunctionEntryEdge(Construct
, Construct
.getMutablePieces());
2086 // Remove messages that are basically the same, and edges that may not
2088 // We have to do this after edge optimization in the Extensive mode.
2089 removeRedundantMsgs(Construct
.getMutablePieces());
2090 removeEdgesToDefaultInitializers(Construct
.getMutablePieces());
2093 if (Opts
.ShouldDisplayMacroExpansions
)
2094 CompactMacroExpandedPieces(Construct
.getMutablePieces(), SM
);
2096 return std::move(Construct
.PD
);
2099 //===----------------------------------------------------------------------===//
2100 // Methods for BugType and subclasses.
2101 //===----------------------------------------------------------------------===//
2103 void BugType::anchor() {}
2105 //===----------------------------------------------------------------------===//
2106 // Methods for BugReport and subclasses.
2107 //===----------------------------------------------------------------------===//
2109 LLVM_ATTRIBUTE_USED
static bool
2110 isDependency(const CheckerRegistryData
&Registry
, StringRef CheckerName
) {
2111 for (const std::pair
<StringRef
, StringRef
> &Pair
: Registry
.Dependencies
) {
2112 if (Pair
.second
== CheckerName
)
2118 LLVM_ATTRIBUTE_USED
static bool isHidden(const CheckerRegistryData
&Registry
,
2119 StringRef CheckerName
) {
2120 for (const CheckerInfo
&Checker
: Registry
.Checkers
) {
2121 if (Checker
.FullName
== CheckerName
)
2122 return Checker
.IsHidden
;
2125 "Checker name not found in CheckerRegistry -- did you retrieve it "
2126 "correctly from CheckerManager::getCurrentCheckerName?");
2129 PathSensitiveBugReport::PathSensitiveBugReport(
2130 const BugType
&bt
, StringRef shortDesc
, StringRef desc
,
2131 const ExplodedNode
*errorNode
, PathDiagnosticLocation LocationToUnique
,
2132 const Decl
*DeclToUnique
)
2133 : BugReport(Kind::PathSensitive
, bt
, shortDesc
, desc
), ErrorNode(errorNode
),
2134 ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() : SourceRange()),
2135 UniqueingLocation(LocationToUnique
), UniqueingDecl(DeclToUnique
) {
2136 assert(!isDependency(ErrorNode
->getState()
2137 ->getAnalysisManager()
2138 .getCheckerManager()
2139 ->getCheckerRegistryData(),
2140 bt
.getCheckerName()) &&
2141 "Some checkers depend on this one! We don't allow dependency "
2142 "checkers to emit warnings, because checkers should depend on "
2143 "*modeling*, not *diagnostics*.");
2145 assert((bt
.getCheckerName().starts_with("debug") ||
2146 !isHidden(ErrorNode
->getState()
2147 ->getAnalysisManager()
2148 .getCheckerManager()
2149 ->getCheckerRegistryData(),
2150 bt
.getCheckerName())) &&
2151 "Hidden checkers musn't emit diagnostics as they are by definition "
2152 "non-user facing!");
2155 void PathSensitiveBugReport::addVisitor(
2156 std::unique_ptr
<BugReporterVisitor
> visitor
) {
2160 llvm::FoldingSetNodeID ID
;
2161 visitor
->Profile(ID
);
2163 void *InsertPos
= nullptr;
2164 if (CallbacksSet
.FindNodeOrInsertPos(ID
, InsertPos
)) {
2168 Callbacks
.push_back(std::move(visitor
));
2171 void PathSensitiveBugReport::clearVisitors() {
2175 const Decl
*PathSensitiveBugReport::getDeclWithIssue() const {
2176 const ExplodedNode
*N
= getErrorNode();
2180 const LocationContext
*LC
= N
->getLocationContext();
2181 return LC
->getStackFrame()->getDecl();
2184 void BasicBugReport::Profile(llvm::FoldingSetNodeID
& hash
) const {
2185 hash
.AddInteger(static_cast<int>(getKind()));
2186 hash
.AddPointer(&BT
);
2187 hash
.AddString(Description
);
2188 assert(Location
.isValid());
2189 Location
.Profile(hash
);
2191 for (SourceRange range
: Ranges
) {
2192 if (!range
.isValid())
2194 hash
.Add(range
.getBegin());
2195 hash
.Add(range
.getEnd());
2199 void PathSensitiveBugReport::Profile(llvm::FoldingSetNodeID
&hash
) const {
2200 hash
.AddInteger(static_cast<int>(getKind()));
2201 hash
.AddPointer(&BT
);
2202 hash
.AddString(Description
);
2203 PathDiagnosticLocation UL
= getUniqueingLocation();
2207 // TODO: The statement may be null if the report was emitted before any
2208 // statements were executed. In particular, some checkers by design
2209 // occasionally emit their reports in empty functions (that have no
2210 // statements in their body). Do we profile correctly in this case?
2211 hash
.AddPointer(ErrorNode
->getCurrentOrPreviousStmtForDiagnostics());
2214 for (SourceRange range
: Ranges
) {
2215 if (!range
.isValid())
2217 hash
.Add(range
.getBegin());
2218 hash
.Add(range
.getEnd());
2223 static void insertToInterestingnessMap(
2224 llvm::DenseMap
<T
, bugreporter::TrackingKind
> &InterestingnessMap
, T Val
,
2225 bugreporter::TrackingKind TKind
) {
2226 auto Result
= InterestingnessMap
.insert({Val
, TKind
});
2231 // Even if this symbol/region was already marked as interesting as a
2232 // condition, if we later mark it as interesting again but with
2233 // thorough tracking, overwrite it. Entities marked with thorough
2234 // interestiness are the most important (or most interesting, if you will),
2235 // and we wouldn't like to downplay their importance.
2238 case bugreporter::TrackingKind::Thorough
:
2239 Result
.first
->getSecond() = bugreporter::TrackingKind::Thorough
;
2241 case bugreporter::TrackingKind::Condition
:
2246 "BugReport::markInteresting currently can only handle 2 different "
2247 "tracking kinds! Please define what tracking kind should this entitiy"
2248 "have, if it was already marked as interesting with a different kind!");
2251 void PathSensitiveBugReport::markInteresting(SymbolRef sym
,
2252 bugreporter::TrackingKind TKind
) {
2256 insertToInterestingnessMap(InterestingSymbols
, sym
, TKind
);
2258 // FIXME: No tests exist for this code and it is questionable:
2259 // How to handle multiple metadata for the same region?
2260 if (const auto *meta
= dyn_cast
<SymbolMetadata
>(sym
))
2261 markInteresting(meta
->getRegion(), TKind
);
2264 void PathSensitiveBugReport::markNotInteresting(SymbolRef sym
) {
2267 InterestingSymbols
.erase(sym
);
2269 // The metadata part of markInteresting is not reversed here.
2270 // Just making the same region not interesting is incorrect
2271 // in specific cases.
2272 if (const auto *meta
= dyn_cast
<SymbolMetadata
>(sym
))
2273 markNotInteresting(meta
->getRegion());
2276 void PathSensitiveBugReport::markInteresting(const MemRegion
*R
,
2277 bugreporter::TrackingKind TKind
) {
2281 R
= R
->getBaseRegion();
2282 insertToInterestingnessMap(InterestingRegions
, R
, TKind
);
2284 if (const auto *SR
= dyn_cast
<SymbolicRegion
>(R
))
2285 markInteresting(SR
->getSymbol(), TKind
);
2288 void PathSensitiveBugReport::markNotInteresting(const MemRegion
*R
) {
2292 R
= R
->getBaseRegion();
2293 InterestingRegions
.erase(R
);
2295 if (const auto *SR
= dyn_cast
<SymbolicRegion
>(R
))
2296 markNotInteresting(SR
->getSymbol());
2299 void PathSensitiveBugReport::markInteresting(SVal V
,
2300 bugreporter::TrackingKind TKind
) {
2301 markInteresting(V
.getAsRegion(), TKind
);
2302 markInteresting(V
.getAsSymbol(), TKind
);
2305 void PathSensitiveBugReport::markInteresting(const LocationContext
*LC
) {
2308 InterestingLocationContexts
.insert(LC
);
2311 std::optional
<bugreporter::TrackingKind
>
2312 PathSensitiveBugReport::getInterestingnessKind(SVal V
) const {
2313 auto RKind
= getInterestingnessKind(V
.getAsRegion());
2314 auto SKind
= getInterestingnessKind(V
.getAsSymbol());
2320 // If either is marked with throrough tracking, return that, we wouldn't like
2321 // to downplay a note's importance by 'only' mentioning it as a condition.
2323 case bugreporter::TrackingKind::Thorough
:
2325 case bugreporter::TrackingKind::Condition
:
2330 "BugReport::getInterestingnessKind currently can only handle 2 different "
2331 "tracking kinds! Please define what tracking kind should we return here "
2332 "when the kind of getAsRegion() and getAsSymbol() is different!");
2333 return std::nullopt
;
2336 std::optional
<bugreporter::TrackingKind
>
2337 PathSensitiveBugReport::getInterestingnessKind(SymbolRef sym
) const {
2339 return std::nullopt
;
2340 // We don't currently consider metadata symbols to be interesting
2341 // even if we know their region is interesting. Is that correct behavior?
2342 auto It
= InterestingSymbols
.find(sym
);
2343 if (It
== InterestingSymbols
.end())
2344 return std::nullopt
;
2345 return It
->getSecond();
2348 std::optional
<bugreporter::TrackingKind
>
2349 PathSensitiveBugReport::getInterestingnessKind(const MemRegion
*R
) const {
2351 return std::nullopt
;
2353 R
= R
->getBaseRegion();
2354 auto It
= InterestingRegions
.find(R
);
2355 if (It
!= InterestingRegions
.end())
2356 return It
->getSecond();
2358 if (const auto *SR
= dyn_cast
<SymbolicRegion
>(R
))
2359 return getInterestingnessKind(SR
->getSymbol());
2360 return std::nullopt
;
2363 bool PathSensitiveBugReport::isInteresting(SVal V
) const {
2364 return getInterestingnessKind(V
).has_value();
2367 bool PathSensitiveBugReport::isInteresting(SymbolRef sym
) const {
2368 return getInterestingnessKind(sym
).has_value();
2371 bool PathSensitiveBugReport::isInteresting(const MemRegion
*R
) const {
2372 return getInterestingnessKind(R
).has_value();
2375 bool PathSensitiveBugReport::isInteresting(const LocationContext
*LC
) const {
2378 return InterestingLocationContexts
.count(LC
);
2381 const Stmt
*PathSensitiveBugReport::getStmt() const {
2385 ProgramPoint ProgP
= ErrorNode
->getLocation();
2386 const Stmt
*S
= nullptr;
2388 if (std::optional
<BlockEntrance
> BE
= ProgP
.getAs
<BlockEntrance
>()) {
2389 CFGBlock
&Exit
= ProgP
.getLocationContext()->getCFG()->getExit();
2390 if (BE
->getBlock() == &Exit
)
2391 S
= ErrorNode
->getPreviousStmtForDiagnostics();
2394 S
= ErrorNode
->getStmtForDiagnostics();
2399 ArrayRef
<SourceRange
>
2400 PathSensitiveBugReport::getRanges() const {
2401 // If no custom ranges, add the range of the statement corresponding to
2403 if (Ranges
.empty() && isa_and_nonnull
<Expr
>(getStmt()))
2404 return ErrorNodeRange
;
2409 PathDiagnosticLocation
2410 PathSensitiveBugReport::getLocation() const {
2411 assert(ErrorNode
&& "Cannot create a location with a null node.");
2412 const Stmt
*S
= ErrorNode
->getStmtForDiagnostics();
2413 ProgramPoint P
= ErrorNode
->getLocation();
2414 const LocationContext
*LC
= P
.getLocationContext();
2416 ErrorNode
->getState()->getStateManager().getContext().getSourceManager();
2419 // If this is an implicit call, return the implicit call point location.
2420 if (std::optional
<PreImplicitCall
> PIE
= P
.getAs
<PreImplicitCall
>())
2421 return PathDiagnosticLocation(PIE
->getLocation(), SM
);
2422 if (auto FE
= P
.getAs
<FunctionExitPoint
>()) {
2423 if (const ReturnStmt
*RS
= FE
->getStmt())
2424 return PathDiagnosticLocation::createBegin(RS
, SM
, LC
);
2426 S
= ErrorNode
->getNextStmtForDiagnostics();
2430 // Attributed statements usually have corrupted begin locations,
2431 // it's OK to ignore attributes for our purposes and deal with
2432 // the actual annotated statement.
2433 if (const auto *AS
= dyn_cast
<AttributedStmt
>(S
))
2434 S
= AS
->getSubStmt();
2436 // For member expressions, return the location of the '.' or '->'.
2437 if (const auto *ME
= dyn_cast
<MemberExpr
>(S
))
2438 return PathDiagnosticLocation::createMemberLoc(ME
, SM
);
2440 // For binary operators, return the location of the operator.
2441 if (const auto *B
= dyn_cast
<BinaryOperator
>(S
))
2442 return PathDiagnosticLocation::createOperatorLoc(B
, SM
);
2444 if (P
.getAs
<PostStmtPurgeDeadSymbols
>())
2445 return PathDiagnosticLocation::createEnd(S
, SM
, LC
);
2447 if (S
->getBeginLoc().isValid())
2448 return PathDiagnosticLocation(S
, SM
, LC
);
2450 return PathDiagnosticLocation(
2451 PathDiagnosticLocation::getValidSourceLocation(S
, LC
), SM
);
2454 return PathDiagnosticLocation::createDeclEnd(ErrorNode
->getLocationContext(),
2458 //===----------------------------------------------------------------------===//
2459 // Methods for BugReporter and subclasses.
2460 //===----------------------------------------------------------------------===//
2462 const ExplodedGraph
&PathSensitiveBugReporter::getGraph() const {
2463 return Eng
.getGraph();
2466 ProgramStateManager
&PathSensitiveBugReporter::getStateManager() const {
2467 return Eng
.getStateManager();
2470 BugReporter::BugReporter(BugReporterData
&d
) : D(d
) {}
2471 BugReporter::~BugReporter() {
2472 // Make sure reports are flushed.
2473 assert(StrBugTypes
.empty() &&
2474 "Destroying BugReporter before diagnostics are emitted!");
2476 // Free the bug reports we are tracking.
2477 for (const auto I
: EQClassesVector
)
2481 void BugReporter::FlushReports() {
2482 // We need to flush reports in deterministic order to ensure the order
2483 // of the reports is consistent between runs.
2484 for (const auto EQ
: EQClassesVector
)
2487 // BugReporter owns and deletes only BugTypes created implicitly through
2489 // FIXME: There are leaks from checkers that assume that the BugTypes they
2490 // create will be destroyed by the BugReporter.
2491 StrBugTypes
.clear();
2494 //===----------------------------------------------------------------------===//
2495 // PathDiagnostics generation.
2496 //===----------------------------------------------------------------------===//
2500 /// A wrapper around an ExplodedGraph that contains a single path from the root
2501 /// to the error node.
2504 std::unique_ptr
<ExplodedGraph
> BugPath
;
2505 PathSensitiveBugReport
*Report
;
2506 const ExplodedNode
*ErrorNode
;
2509 /// A wrapper around an ExplodedGraph whose leafs are all error nodes. Can
2510 /// conveniently retrieve bug paths from a single error node to the root.
2511 class BugPathGetter
{
2512 std::unique_ptr
<ExplodedGraph
> TrimmedGraph
;
2514 using PriorityMapTy
= llvm::DenseMap
<const ExplodedNode
*, unsigned>;
2516 /// Assign each node with its distance from the root.
2517 PriorityMapTy PriorityMap
;
2519 /// Since the getErrorNode() or BugReport refers to the original ExplodedGraph,
2520 /// we need to pair it to the error node of the constructed trimmed graph.
2521 using ReportNewNodePair
=
2522 std::pair
<PathSensitiveBugReport
*, const ExplodedNode
*>;
2523 SmallVector
<ReportNewNodePair
, 32> ReportNodes
;
2525 BugPathInfo CurrentBugPath
;
2527 /// A helper class for sorting ExplodedNodes by priority.
2528 template <bool Descending
>
2529 class PriorityCompare
{
2530 const PriorityMapTy
&PriorityMap
;
2533 PriorityCompare(const PriorityMapTy
&M
) : PriorityMap(M
) {}
2535 bool operator()(const ExplodedNode
*LHS
, const ExplodedNode
*RHS
) const {
2536 PriorityMapTy::const_iterator LI
= PriorityMap
.find(LHS
);
2537 PriorityMapTy::const_iterator RI
= PriorityMap
.find(RHS
);
2538 PriorityMapTy::const_iterator E
= PriorityMap
.end();
2545 return Descending
? LI
->second
> RI
->second
2546 : LI
->second
< RI
->second
;
2549 bool operator()(const ReportNewNodePair
&LHS
,
2550 const ReportNewNodePair
&RHS
) const {
2551 return (*this)(LHS
.second
, RHS
.second
);
2556 BugPathGetter(const ExplodedGraph
*OriginalGraph
,
2557 ArrayRef
<PathSensitiveBugReport
*> &bugReports
);
2559 BugPathInfo
*getNextBugPath();
2564 BugPathGetter::BugPathGetter(const ExplodedGraph
*OriginalGraph
,
2565 ArrayRef
<PathSensitiveBugReport
*> &bugReports
) {
2566 SmallVector
<const ExplodedNode
*, 32> Nodes
;
2567 for (const auto I
: bugReports
) {
2568 assert(I
->isValid() &&
2569 "We only allow BugReporterVisitors and BugReporter itself to "
2570 "invalidate reports!");
2571 Nodes
.emplace_back(I
->getErrorNode());
2574 // The trimmed graph is created in the body of the constructor to ensure
2575 // that the DenseMaps have been initialized already.
2576 InterExplodedGraphMap ForwardMap
;
2577 TrimmedGraph
= OriginalGraph
->trim(Nodes
, &ForwardMap
);
2579 // Find the (first) error node in the trimmed graph. We just need to consult
2580 // the node map which maps from nodes in the original graph to nodes
2581 // in the new graph.
2582 llvm::SmallPtrSet
<const ExplodedNode
*, 32> RemainingNodes
;
2584 for (PathSensitiveBugReport
*Report
: bugReports
) {
2585 const ExplodedNode
*NewNode
= ForwardMap
.lookup(Report
->getErrorNode());
2587 "Failed to construct a trimmed graph that contains this error "
2589 ReportNodes
.emplace_back(Report
, NewNode
);
2590 RemainingNodes
.insert(NewNode
);
2593 assert(!RemainingNodes
.empty() && "No error node found in the trimmed graph");
2595 // Perform a forward BFS to find all the shortest paths.
2596 std::queue
<const ExplodedNode
*> WS
;
2598 assert(TrimmedGraph
->num_roots() == 1);
2599 WS
.push(*TrimmedGraph
->roots_begin());
2600 unsigned Priority
= 0;
2602 while (!WS
.empty()) {
2603 const ExplodedNode
*Node
= WS
.front();
2606 PriorityMapTy::iterator PriorityEntry
;
2608 std::tie(PriorityEntry
, IsNew
) = PriorityMap
.insert({Node
, Priority
});
2612 assert(PriorityEntry
->second
<= Priority
);
2616 if (RemainingNodes
.erase(Node
))
2617 if (RemainingNodes
.empty())
2620 for (const ExplodedNode
*Succ
: Node
->succs())
2624 // Sort the error paths from longest to shortest.
2625 llvm::sort(ReportNodes
, PriorityCompare
<true>(PriorityMap
));
2628 BugPathInfo
*BugPathGetter::getNextBugPath() {
2629 if (ReportNodes
.empty())
2632 const ExplodedNode
*OrigN
;
2633 std::tie(CurrentBugPath
.Report
, OrigN
) = ReportNodes
.pop_back_val();
2634 assert(PriorityMap
.contains(OrigN
) && "error node not accessible from root");
2636 // Create a new graph with a single path. This is the graph that will be
2637 // returned to the caller.
2638 auto GNew
= std::make_unique
<ExplodedGraph
>();
2640 // Now walk from the error node up the BFS path, always taking the
2641 // predeccessor with the lowest number.
2642 ExplodedNode
*Succ
= nullptr;
2644 // Create the equivalent node in the new graph with the same state
2646 ExplodedNode
*NewN
= GNew
->createUncachedNode(
2647 OrigN
->getLocation(), OrigN
->getState(),
2648 OrigN
->getID(), OrigN
->isSink());
2650 // Link up the new node with the previous node.
2652 Succ
->addPredecessor(NewN
, *GNew
);
2654 CurrentBugPath
.ErrorNode
= NewN
;
2658 // Are we at the final node?
2659 if (OrigN
->pred_empty()) {
2660 GNew
->addRoot(NewN
);
2664 // Find the next predeccessor node. We choose the node that is marked
2665 // with the lowest BFS number.
2666 OrigN
= *std::min_element(OrigN
->pred_begin(), OrigN
->pred_end(),
2667 PriorityCompare
<false>(PriorityMap
));
2670 CurrentBugPath
.BugPath
= std::move(GNew
);
2672 return &CurrentBugPath
;
2675 /// CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic
2676 /// object and collapses PathDiagosticPieces that are expanded by macros.
2677 static void CompactMacroExpandedPieces(PathPieces
&path
,
2678 const SourceManager
& SM
) {
2679 using MacroStackTy
= std::vector
<
2680 std::pair
<std::shared_ptr
<PathDiagnosticMacroPiece
>, SourceLocation
>>;
2682 using PiecesTy
= std::vector
<PathDiagnosticPieceRef
>;
2684 MacroStackTy MacroStack
;
2687 for (PathPieces::const_iterator I
= path
.begin(), E
= path
.end();
2689 const auto &piece
= *I
;
2691 // Recursively compact calls.
2692 if (auto *call
= dyn_cast
<PathDiagnosticCallPiece
>(&*piece
)) {
2693 CompactMacroExpandedPieces(call
->path
, SM
);
2696 // Get the location of the PathDiagnosticPiece.
2697 const FullSourceLoc Loc
= piece
->getLocation().asLocation();
2699 // Determine the instantiation location, which is the location we group
2700 // related PathDiagnosticPieces.
2701 SourceLocation InstantiationLoc
= Loc
.isMacroID() ?
2702 SM
.getExpansionLoc(Loc
) :
2705 if (Loc
.isFileID()) {
2707 Pieces
.push_back(piece
);
2711 assert(Loc
.isMacroID());
2713 // Is the PathDiagnosticPiece within the same macro group?
2714 if (!MacroStack
.empty() && InstantiationLoc
== MacroStack
.back().second
) {
2715 MacroStack
.back().first
->subPieces
.push_back(piece
);
2719 // We aren't in the same group. Are we descending into a new macro
2720 // or are part of an old one?
2721 std::shared_ptr
<PathDiagnosticMacroPiece
> MacroGroup
;
2723 SourceLocation ParentInstantiationLoc
= InstantiationLoc
.isMacroID() ?
2724 SM
.getExpansionLoc(Loc
) :
2727 // Walk the entire macro stack.
2728 while (!MacroStack
.empty()) {
2729 if (InstantiationLoc
== MacroStack
.back().second
) {
2730 MacroGroup
= MacroStack
.back().first
;
2734 if (ParentInstantiationLoc
== MacroStack
.back().second
) {
2735 MacroGroup
= MacroStack
.back().first
;
2739 MacroStack
.pop_back();
2742 if (!MacroGroup
|| ParentInstantiationLoc
== MacroStack
.back().second
) {
2743 // Create a new macro group and add it to the stack.
2744 auto NewGroup
= std::make_shared
<PathDiagnosticMacroPiece
>(
2745 PathDiagnosticLocation::createSingleLocation(piece
->getLocation()));
2748 MacroGroup
->subPieces
.push_back(NewGroup
);
2750 assert(InstantiationLoc
.isFileID());
2751 Pieces
.push_back(NewGroup
);
2754 MacroGroup
= NewGroup
;
2755 MacroStack
.push_back(std::make_pair(MacroGroup
, InstantiationLoc
));
2758 // Finally, add the PathDiagnosticPiece to the group.
2759 MacroGroup
->subPieces
.push_back(piece
);
2762 // Now take the pieces and construct a new PathDiagnostic.
2765 path
.insert(path
.end(), Pieces
.begin(), Pieces
.end());
2768 /// Generate notes from all visitors.
2769 /// Notes associated with @c ErrorNode are generated using
2770 /// @c getEndPath, and the rest are generated with @c VisitNode.
2771 static std::unique_ptr
<VisitorsDiagnosticsTy
>
2772 generateVisitorsDiagnostics(PathSensitiveBugReport
*R
,
2773 const ExplodedNode
*ErrorNode
,
2774 BugReporterContext
&BRC
) {
2775 std::unique_ptr
<VisitorsDiagnosticsTy
> Notes
=
2776 std::make_unique
<VisitorsDiagnosticsTy
>();
2777 PathSensitiveBugReport::VisitorList visitors
;
2779 // Run visitors on all nodes starting from the node *before* the last one.
2780 // The last node is reserved for notes generated with @c getEndPath.
2781 const ExplodedNode
*NextNode
= ErrorNode
->getFirstPred();
2784 // At each iteration, move all visitors from report to visitor list. This is
2785 // important, because the Profile() functions of the visitors make sure that
2786 // a visitor isn't added multiple times for the same node, but it's fine
2787 // to add the a visitor with Profile() for different nodes (e.g. tracking
2788 // a region at different points of the symbolic execution).
2789 for (std::unique_ptr
<BugReporterVisitor
> &Visitor
: R
->visitors())
2790 visitors
.push_back(std::move(Visitor
));
2794 const ExplodedNode
*Pred
= NextNode
->getFirstPred();
2796 PathDiagnosticPieceRef LastPiece
;
2797 for (auto &V
: visitors
) {
2798 V
->finalizeVisitor(BRC
, ErrorNode
, *R
);
2800 if (auto Piece
= V
->getEndPath(BRC
, ErrorNode
, *R
)) {
2801 assert(!LastPiece
&&
2802 "There can only be one final piece in a diagnostic.");
2803 assert(Piece
->getKind() == PathDiagnosticPiece::Kind::Event
&&
2804 "The final piece must contain a message!");
2805 LastPiece
= std::move(Piece
);
2806 (*Notes
)[ErrorNode
].push_back(LastPiece
);
2812 for (auto &V
: visitors
) {
2813 auto P
= V
->VisitNode(NextNode
, BRC
, *R
);
2815 (*Notes
)[NextNode
].push_back(std::move(P
));
2827 std::optional
<PathDiagnosticBuilder
> PathDiagnosticBuilder::findValidReport(
2828 ArrayRef
<PathSensitiveBugReport
*> &bugReports
,
2829 PathSensitiveBugReporter
&Reporter
) {
2831 BugPathGetter
BugGraph(&Reporter
.getGraph(), bugReports
);
2833 while (BugPathInfo
*BugPath
= BugGraph
.getNextBugPath()) {
2834 // Find the BugReport with the original location.
2835 PathSensitiveBugReport
*R
= BugPath
->Report
;
2836 assert(R
&& "No original report found for sliced graph.");
2837 assert(R
->isValid() && "Report selected by trimmed graph marked invalid.");
2838 const ExplodedNode
*ErrorNode
= BugPath
->ErrorNode
;
2840 // Register refutation visitors first, if they mark the bug invalid no
2841 // further analysis is required
2842 R
->addVisitor
<LikelyFalsePositiveSuppressionBRVisitor
>();
2844 // Register additional node visitors.
2845 R
->addVisitor
<NilReceiverBRVisitor
>();
2846 R
->addVisitor
<ConditionBRVisitor
>();
2847 R
->addVisitor
<TagVisitor
>();
2849 BugReporterContext
BRC(Reporter
);
2851 // Run all visitors on a given graph, once.
2852 std::unique_ptr
<VisitorsDiagnosticsTy
> visitorNotes
=
2853 generateVisitorsDiagnostics(R
, ErrorNode
, BRC
);
2856 if (Reporter
.getAnalyzerOptions().ShouldCrosscheckWithZ3
) {
2857 // If crosscheck is enabled, remove all visitors, add the refutation
2858 // visitor and check again
2860 R
->addVisitor
<FalsePositiveRefutationBRVisitor
>();
2862 // We don't overwrite the notes inserted by other visitors because the
2863 // refutation manager does not add any new note to the path
2864 generateVisitorsDiagnostics(R
, BugPath
->ErrorNode
, BRC
);
2867 // Check if the bug is still valid
2869 return PathDiagnosticBuilder(
2870 std::move(BRC
), std::move(BugPath
->BugPath
), BugPath
->Report
,
2871 BugPath
->ErrorNode
, std::move(visitorNotes
));
2878 std::unique_ptr
<DiagnosticForConsumerMapTy
>
2879 PathSensitiveBugReporter::generatePathDiagnostics(
2880 ArrayRef
<PathDiagnosticConsumer
*> consumers
,
2881 ArrayRef
<PathSensitiveBugReport
*> &bugReports
) {
2882 assert(!bugReports
.empty());
2884 auto Out
= std::make_unique
<DiagnosticForConsumerMapTy
>();
2886 std::optional
<PathDiagnosticBuilder
> PDB
=
2887 PathDiagnosticBuilder::findValidReport(bugReports
, *this);
2890 for (PathDiagnosticConsumer
*PC
: consumers
) {
2891 if (std::unique_ptr
<PathDiagnostic
> PD
= PDB
->generate(PC
)) {
2892 (*Out
)[PC
] = std::move(PD
);
2900 void BugReporter::emitReport(std::unique_ptr
<BugReport
> R
) {
2901 bool ValidSourceLoc
= R
->getLocation().isValid();
2902 assert(ValidSourceLoc
);
2903 // If we mess up in a release build, we'd still prefer to just drop the bug
2904 // instead of trying to go on.
2905 if (!ValidSourceLoc
)
2908 // If the user asked to suppress this report, we should skip it.
2909 if (UserSuppressions
.isSuppressed(*R
))
2912 // Compute the bug report's hash to determine its equivalence class.
2913 llvm::FoldingSetNodeID ID
;
2916 // Lookup the equivance class. If there isn't one, create it.
2918 BugReportEquivClass
* EQ
= EQClasses
.FindNodeOrInsertPos(ID
, InsertPos
);
2921 EQ
= new BugReportEquivClass(std::move(R
));
2922 EQClasses
.InsertNode(EQ
, InsertPos
);
2923 EQClassesVector
.push_back(EQ
);
2925 EQ
->AddReport(std::move(R
));
2928 void PathSensitiveBugReporter::emitReport(std::unique_ptr
<BugReport
> R
) {
2929 if (auto PR
= dyn_cast
<PathSensitiveBugReport
>(R
.get()))
2930 if (const ExplodedNode
*E
= PR
->getErrorNode()) {
2931 // An error node must either be a sink or have a tag, otherwise
2932 // it could get reclaimed before the path diagnostic is created.
2933 assert((E
->isSink() || E
->getLocation().getTag()) &&
2934 "Error node must either be a sink or have a tag");
2936 const AnalysisDeclContext
*DeclCtx
=
2937 E
->getLocationContext()->getAnalysisDeclContext();
2938 // The source of autosynthesized body can be handcrafted AST or a model
2939 // file. The locations from handcrafted ASTs have no valid source
2940 // locations and have to be discarded. Locations from model files should
2941 // be preserved for processing and reporting.
2942 if (DeclCtx
->isBodyAutosynthesized() &&
2943 !DeclCtx
->isBodyAutosynthesizedFromModelFile())
2947 BugReporter::emitReport(std::move(R
));
2950 //===----------------------------------------------------------------------===//
2951 // Emitting reports in equivalence classes.
2952 //===----------------------------------------------------------------------===//
2956 struct FRIEC_WLItem
{
2957 const ExplodedNode
*N
;
2958 ExplodedNode::const_succ_iterator I
, E
;
2960 FRIEC_WLItem(const ExplodedNode
*n
)
2961 : N(n
), I(N
->succ_begin()), E(N
->succ_end()) {}
2966 BugReport
*PathSensitiveBugReporter::findReportInEquivalenceClass(
2967 BugReportEquivClass
&EQ
, SmallVectorImpl
<BugReport
*> &bugReports
) {
2968 // If we don't need to suppress any of the nodes because they are
2969 // post-dominated by a sink, simply add all the nodes in the equivalence class
2970 // to 'Nodes'. Any of the reports will serve as a "representative" report.
2971 assert(EQ
.getReports().size() > 0);
2972 const BugType
& BT
= EQ
.getReports()[0]->getBugType();
2973 if (!BT
.isSuppressOnSink()) {
2974 BugReport
*R
= EQ
.getReports()[0].get();
2975 for (auto &J
: EQ
.getReports()) {
2976 if (auto *PR
= dyn_cast
<PathSensitiveBugReport
>(J
.get())) {
2978 bugReports
.push_back(PR
);
2984 // For bug reports that should be suppressed when all paths are post-dominated
2985 // by a sink node, iterate through the reports in the equivalence class
2986 // until we find one that isn't post-dominated (if one exists). We use a
2987 // DFS traversal of the ExplodedGraph to find a non-sink node. We could write
2988 // this as a recursive function, but we don't want to risk blowing out the
2989 // stack for very long paths.
2990 BugReport
*exampleReport
= nullptr;
2992 for (const auto &I
: EQ
.getReports()) {
2993 auto *R
= dyn_cast
<PathSensitiveBugReport
>(I
.get());
2997 const ExplodedNode
*errorNode
= R
->getErrorNode();
2998 if (errorNode
->isSink()) {
3000 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3002 // No successors? By definition this nodes isn't post-dominated by a sink.
3003 if (errorNode
->succ_empty()) {
3004 bugReports
.push_back(R
);
3010 // See if we are in a no-return CFG block. If so, treat this similarly
3011 // to being post-dominated by a sink. This works better when the analysis
3012 // is incomplete and we have never reached the no-return function call(s)
3013 // that we'd inevitably bump into on this path.
3014 if (const CFGBlock
*ErrorB
= errorNode
->getCFGBlock())
3015 if (ErrorB
->isInevitablySinking())
3018 // At this point we know that 'N' is not a sink and it has at least one
3019 // successor. Use a DFS worklist to find a non-sink end-of-path node.
3020 using WLItem
= FRIEC_WLItem
;
3021 using DFSWorkList
= SmallVector
<WLItem
, 10>;
3023 llvm::DenseMap
<const ExplodedNode
*, unsigned> Visited
;
3026 WL
.push_back(errorNode
);
3027 Visited
[errorNode
] = 1;
3029 while (!WL
.empty()) {
3030 WLItem
&WI
= WL
.back();
3031 assert(!WI
.N
->succ_empty());
3033 for (; WI
.I
!= WI
.E
; ++WI
.I
) {
3034 const ExplodedNode
*Succ
= *WI
.I
;
3035 // End-of-path node?
3036 if (Succ
->succ_empty()) {
3037 // If we found an end-of-path node that is not a sink.
3038 if (!Succ
->isSink()) {
3039 bugReports
.push_back(R
);
3045 // Found a sink? Continue on to the next successor.
3048 // Mark the successor as visited. If it hasn't been explored,
3049 // enqueue it to the DFS worklist.
3050 unsigned &mark
= Visited
[Succ
];
3058 // The worklist may have been cleared at this point. First
3059 // check if it is empty before checking the last item.
3060 if (!WL
.empty() && &WL
.back() == &WI
)
3065 // ExampleReport will be NULL if all the nodes in the equivalence class
3066 // were post-dominated by sinks.
3067 return exampleReport
;
3070 void BugReporter::FlushReport(BugReportEquivClass
& EQ
) {
3071 SmallVector
<BugReport
*, 10> bugReports
;
3072 BugReport
*report
= findReportInEquivalenceClass(EQ
, bugReports
);
3076 // See whether we need to silence the checker/package.
3077 for (const std::string
&CheckerOrPackage
:
3078 getAnalyzerOptions().SilencedCheckersAndPackages
) {
3079 if (report
->getBugType().getCheckerName().starts_with(CheckerOrPackage
))
3083 ArrayRef
<PathDiagnosticConsumer
*> Consumers
= getPathDiagnosticConsumers();
3084 std::unique_ptr
<DiagnosticForConsumerMapTy
> Diagnostics
=
3085 generateDiagnosticForConsumerMap(report
, Consumers
, bugReports
);
3087 for (auto &P
: *Diagnostics
) {
3088 PathDiagnosticConsumer
*Consumer
= P
.first
;
3089 std::unique_ptr
<PathDiagnostic
> &PD
= P
.second
;
3091 // If the path is empty, generate a single step path with the location
3093 if (PD
->path
.empty()) {
3094 PathDiagnosticLocation L
= report
->getLocation();
3095 auto piece
= std::make_unique
<PathDiagnosticEventPiece
>(
3096 L
, report
->getDescription());
3097 for (SourceRange Range
: report
->getRanges())
3098 piece
->addRange(Range
);
3099 PD
->setEndOfPath(std::move(piece
));
3102 PathPieces
&Pieces
= PD
->getMutablePieces();
3103 if (getAnalyzerOptions().ShouldDisplayNotesAsEvents
) {
3104 // For path diagnostic consumers that don't support extra notes,
3105 // we may optionally convert those to path notes.
3106 for (const auto &I
: llvm::reverse(report
->getNotes())) {
3107 PathDiagnosticNotePiece
*Piece
= I
.get();
3108 auto ConvertedPiece
= std::make_shared
<PathDiagnosticEventPiece
>(
3109 Piece
->getLocation(), Piece
->getString());
3110 for (const auto &R
: Piece
->getRanges())
3111 ConvertedPiece
->addRange(R
);
3113 Pieces
.push_front(std::move(ConvertedPiece
));
3116 for (const auto &I
: llvm::reverse(report
->getNotes()))
3117 Pieces
.push_front(I
);
3120 for (const auto &I
: report
->getFixits())
3121 Pieces
.back()->addFixit(I
);
3123 updateExecutedLinesWithDiagnosticPieces(*PD
);
3124 Consumer
->HandlePathDiagnostic(std::move(PD
));
3128 /// Insert all lines participating in the function signature \p Signature
3129 /// into \p ExecutedLines.
3130 static void populateExecutedLinesWithFunctionSignature(
3131 const Decl
*Signature
, const SourceManager
&SM
,
3132 FilesToLineNumsMap
&ExecutedLines
) {
3133 SourceRange SignatureSourceRange
;
3134 const Stmt
* Body
= Signature
->getBody();
3135 if (const auto FD
= dyn_cast
<FunctionDecl
>(Signature
)) {
3136 SignatureSourceRange
= FD
->getSourceRange();
3137 } else if (const auto OD
= dyn_cast
<ObjCMethodDecl
>(Signature
)) {
3138 SignatureSourceRange
= OD
->getSourceRange();
3142 SourceLocation Start
= SignatureSourceRange
.getBegin();
3143 SourceLocation End
= Body
? Body
->getSourceRange().getBegin()
3144 : SignatureSourceRange
.getEnd();
3145 if (!Start
.isValid() || !End
.isValid())
3147 unsigned StartLine
= SM
.getExpansionLineNumber(Start
);
3148 unsigned EndLine
= SM
.getExpansionLineNumber(End
);
3150 FileID FID
= SM
.getFileID(SM
.getExpansionLoc(Start
));
3151 for (unsigned Line
= StartLine
; Line
<= EndLine
; Line
++)
3152 ExecutedLines
[FID
].insert(Line
);
3155 static void populateExecutedLinesWithStmt(
3156 const Stmt
*S
, const SourceManager
&SM
,
3157 FilesToLineNumsMap
&ExecutedLines
) {
3158 SourceLocation Loc
= S
->getSourceRange().getBegin();
3161 SourceLocation ExpansionLoc
= SM
.getExpansionLoc(Loc
);
3162 FileID FID
= SM
.getFileID(ExpansionLoc
);
3163 unsigned LineNo
= SM
.getExpansionLineNumber(ExpansionLoc
);
3164 ExecutedLines
[FID
].insert(LineNo
);
3167 /// \return all executed lines including function signatures on the path
3168 /// starting from \p N.
3169 static std::unique_ptr
<FilesToLineNumsMap
>
3170 findExecutedLines(const SourceManager
&SM
, const ExplodedNode
*N
) {
3171 auto ExecutedLines
= std::make_unique
<FilesToLineNumsMap
>();
3174 if (N
->getFirstPred() == nullptr) {
3175 // First node: show signature of the entrance point.
3176 const Decl
*D
= N
->getLocationContext()->getDecl();
3177 populateExecutedLinesWithFunctionSignature(D
, SM
, *ExecutedLines
);
3178 } else if (auto CE
= N
->getLocationAs
<CallEnter
>()) {
3179 // Inlined function: show signature.
3180 const Decl
* D
= CE
->getCalleeContext()->getDecl();
3181 populateExecutedLinesWithFunctionSignature(D
, SM
, *ExecutedLines
);
3182 } else if (const Stmt
*S
= N
->getStmtForDiagnostics()) {
3183 populateExecutedLinesWithStmt(S
, SM
, *ExecutedLines
);
3185 // Show extra context for some parent kinds.
3186 const Stmt
*P
= N
->getParentMap().getParent(S
);
3188 // The path exploration can die before the node with the associated
3189 // return statement is generated, but we do want to show the whole
3191 if (const auto *RS
= dyn_cast_or_null
<ReturnStmt
>(P
)) {
3192 populateExecutedLinesWithStmt(RS
, SM
, *ExecutedLines
);
3193 P
= N
->getParentMap().getParent(RS
);
3196 if (isa_and_nonnull
<SwitchCase
, LabelStmt
>(P
))
3197 populateExecutedLinesWithStmt(P
, SM
, *ExecutedLines
);
3200 N
= N
->getFirstPred();
3202 return ExecutedLines
;
3205 std::unique_ptr
<DiagnosticForConsumerMapTy
>
3206 BugReporter::generateDiagnosticForConsumerMap(
3207 BugReport
*exampleReport
, ArrayRef
<PathDiagnosticConsumer
*> consumers
,
3208 ArrayRef
<BugReport
*> bugReports
) {
3209 auto *basicReport
= cast
<BasicBugReport
>(exampleReport
);
3210 auto Out
= std::make_unique
<DiagnosticForConsumerMapTy
>();
3211 for (auto *Consumer
: consumers
)
3212 (*Out
)[Consumer
] = generateDiagnosticForBasicReport(basicReport
);
3216 static PathDiagnosticCallPiece
*
3217 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece
*CP
,
3218 const SourceManager
&SMgr
) {
3219 SourceLocation CallLoc
= CP
->callEnter
.asLocation();
3221 // If the call is within a macro, don't do anything (for now).
3222 if (CallLoc
.isMacroID())
3225 assert(AnalysisManager::isInCodeFile(CallLoc
, SMgr
) &&
3226 "The call piece should not be in a header file.");
3228 // Check if CP represents a path through a function outside of the main file.
3229 if (!AnalysisManager::isInCodeFile(CP
->callEnterWithin
.asLocation(), SMgr
))
3232 const PathPieces
&Path
= CP
->path
;
3236 // Check if the last piece in the callee path is a call to a function outside
3237 // of the main file.
3238 if (auto *CPInner
= dyn_cast
<PathDiagnosticCallPiece
>(Path
.back().get()))
3239 return getFirstStackedCallToHeaderFile(CPInner
, SMgr
);
3241 // Otherwise, the last piece is in the main file.
3245 static void resetDiagnosticLocationToMainFile(PathDiagnostic
&PD
) {
3246 if (PD
.path
.empty())
3249 PathDiagnosticPiece
*LastP
= PD
.path
.back().get();
3251 const SourceManager
&SMgr
= LastP
->getLocation().getManager();
3253 // We only need to check if the report ends inside headers, if the last piece
3255 if (auto *CP
= dyn_cast
<PathDiagnosticCallPiece
>(LastP
)) {
3256 CP
= getFirstStackedCallToHeaderFile(CP
, SMgr
);
3259 CP
->setAsLastInMainSourceFile();
3261 // Update the path diagnostic message.
3262 const auto *ND
= dyn_cast
<NamedDecl
>(CP
->getCallee());
3264 SmallString
<200> buf
;
3265 llvm::raw_svector_ostream
os(buf
);
3266 os
<< " (within a call to '" << ND
->getDeclName() << "')";
3267 PD
.appendToDesc(os
.str());
3270 // Reset the report containing declaration and location.
3271 PD
.setDeclWithIssue(CP
->getCaller());
3272 PD
.setLocation(CP
->getLocation());
3281 std::unique_ptr
<DiagnosticForConsumerMapTy
>
3282 PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
3283 BugReport
*exampleReport
, ArrayRef
<PathDiagnosticConsumer
*> consumers
,
3284 ArrayRef
<BugReport
*> bugReports
) {
3285 std::vector
<BasicBugReport
*> BasicBugReports
;
3286 std::vector
<PathSensitiveBugReport
*> PathSensitiveBugReports
;
3287 if (isa
<BasicBugReport
>(exampleReport
))
3288 return BugReporter::generateDiagnosticForConsumerMap(exampleReport
,
3289 consumers
, bugReports
);
3291 // Generate the full path sensitive diagnostic, using the generation scheme
3292 // specified by the PathDiagnosticConsumer. Note that we have to generate
3293 // path diagnostics even for consumers which do not support paths, because
3294 // the BugReporterVisitors may mark this bug as a false positive.
3295 assert(!bugReports
.empty());
3296 MaxBugClassSize
.updateMax(bugReports
.size());
3298 // Avoid copying the whole array because there may be a lot of reports.
3299 ArrayRef
<PathSensitiveBugReport
*> convertedArrayOfReports(
3300 reinterpret_cast<PathSensitiveBugReport
*const *>(&*bugReports
.begin()),
3301 reinterpret_cast<PathSensitiveBugReport
*const *>(&*bugReports
.end()));
3302 std::unique_ptr
<DiagnosticForConsumerMapTy
> Out
= generatePathDiagnostics(
3303 consumers
, convertedArrayOfReports
);
3308 MaxValidBugClassSize
.updateMax(bugReports
.size());
3310 // Examine the report and see if the last piece is in a header. Reset the
3311 // report location to the last piece in the main source file.
3312 const AnalyzerOptions
&Opts
= getAnalyzerOptions();
3313 for (auto const &P
: *Out
)
3314 if (Opts
.ShouldReportIssuesInMainSourceFile
&& !Opts
.AnalyzeAll
)
3315 resetDiagnosticLocationToMainFile(*P
.second
);
3320 void BugReporter::EmitBasicReport(const Decl
*DeclWithIssue
,
3321 const CheckerBase
*Checker
, StringRef Name
,
3322 StringRef Category
, StringRef Str
,
3323 PathDiagnosticLocation Loc
,
3324 ArrayRef
<SourceRange
> Ranges
,
3325 ArrayRef
<FixItHint
> Fixits
) {
3326 EmitBasicReport(DeclWithIssue
, Checker
->getCheckerName(), Name
, Category
, Str
,
3327 Loc
, Ranges
, Fixits
);
3330 void BugReporter::EmitBasicReport(const Decl
*DeclWithIssue
,
3331 CheckerNameRef CheckName
,
3332 StringRef name
, StringRef category
,
3333 StringRef str
, PathDiagnosticLocation Loc
,
3334 ArrayRef
<SourceRange
> Ranges
,
3335 ArrayRef
<FixItHint
> Fixits
) {
3336 // 'BT' is owned by BugReporter.
3337 BugType
*BT
= getBugTypeForName(CheckName
, name
, category
);
3338 auto R
= std::make_unique
<BasicBugReport
>(*BT
, str
, Loc
);
3339 R
->setDeclWithIssue(DeclWithIssue
);
3340 for (const auto &SR
: Ranges
)
3342 for (const auto &FH
: Fixits
)
3343 R
->addFixItHint(FH
);
3344 emitReport(std::move(R
));
3347 BugType
*BugReporter::getBugTypeForName(CheckerNameRef CheckName
,
3348 StringRef name
, StringRef category
) {
3349 SmallString
<136> fullDesc
;
3350 llvm::raw_svector_ostream(fullDesc
) << CheckName
.getName() << ":" << name
3352 std::unique_ptr
<BugType
> &BT
= StrBugTypes
[fullDesc
];
3354 BT
= std::make_unique
<BugType
>(CheckName
, name
, category
);