1 //===- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -------------===//
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 the PathDiagnostic-related interfaces.
11 //===----------------------------------------------------------------------===//
13 #include "clang/Analysis/PathDiagnostic.h"
14 #include "clang/AST/Decl.h"
15 #include "clang/AST/DeclBase.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/DeclObjC.h"
18 #include "clang/AST/DeclTemplate.h"
19 #include "clang/AST/Expr.h"
20 #include "clang/AST/ExprCXX.h"
21 #include "clang/AST/OperationKinds.h"
22 #include "clang/AST/ParentMap.h"
23 #include "clang/AST/PrettyPrinter.h"
24 #include "clang/AST/Stmt.h"
25 #include "clang/AST/Type.h"
26 #include "clang/Analysis/AnalysisDeclContext.h"
27 #include "clang/Analysis/CFG.h"
28 #include "clang/Analysis/ProgramPoint.h"
29 #include "clang/Basic/FileManager.h"
30 #include "clang/Basic/LLVM.h"
31 #include "clang/Basic/SourceLocation.h"
32 #include "clang/Basic/SourceManager.h"
33 #include "llvm/ADT/ArrayRef.h"
34 #include "llvm/ADT/FoldingSet.h"
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/SmallString.h"
37 #include "llvm/ADT/SmallVector.h"
38 #include "llvm/ADT/StringExtras.h"
39 #include "llvm/ADT/StringRef.h"
40 #include "llvm/Support/Casting.h"
41 #include "llvm/Support/ErrorHandling.h"
42 #include "llvm/Support/raw_ostream.h"
50 using namespace clang
;
53 static StringRef
StripTrailingDots(StringRef s
) {
54 for (StringRef::size_type i
= s
.size(); i
!= 0; --i
)
56 return s
.substr(0, i
);
60 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s
,
61 Kind k
, DisplayHint hint
)
62 : str(StripTrailingDots(s
)), kind(k
), Hint(hint
) {}
64 PathDiagnosticPiece::PathDiagnosticPiece(Kind k
, DisplayHint hint
)
65 : kind(k
), Hint(hint
) {}
67 PathDiagnosticPiece::~PathDiagnosticPiece() = default;
69 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default;
71 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default;
73 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default;
75 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default;
77 PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default;
79 PathDiagnosticPopUpPiece::~PathDiagnosticPopUpPiece() = default;
81 void PathPieces::flattenTo(PathPieces
&Primary
, PathPieces
&Current
,
82 bool ShouldFlattenMacros
) const {
83 for (auto &Piece
: *this) {
84 switch (Piece
->getKind()) {
85 case PathDiagnosticPiece::Call
: {
86 auto &Call
= cast
<PathDiagnosticCallPiece
>(*Piece
);
87 if (auto CallEnter
= Call
.getCallEnterEvent())
88 Current
.push_back(std::move(CallEnter
));
89 Call
.path
.flattenTo(Primary
, Primary
, ShouldFlattenMacros
);
90 if (auto callExit
= Call
.getCallExitEvent())
91 Current
.push_back(std::move(callExit
));
94 case PathDiagnosticPiece::Macro
: {
95 auto &Macro
= cast
<PathDiagnosticMacroPiece
>(*Piece
);
96 if (ShouldFlattenMacros
) {
97 Macro
.subPieces
.flattenTo(Primary
, Primary
, ShouldFlattenMacros
);
99 Current
.push_back(Piece
);
101 Macro
.subPieces
.flattenTo(Primary
, NewPath
, ShouldFlattenMacros
);
102 // FIXME: This probably shouldn't mutate the original path piece.
103 Macro
.subPieces
= NewPath
;
107 case PathDiagnosticPiece::Event
:
108 case PathDiagnosticPiece::ControlFlow
:
109 case PathDiagnosticPiece::Note
:
110 case PathDiagnosticPiece::PopUp
:
111 Current
.push_back(Piece
);
117 PathDiagnostic::~PathDiagnostic() = default;
119 PathDiagnostic::PathDiagnostic(
120 StringRef CheckerName
, const Decl
*declWithIssue
, StringRef bugtype
,
121 StringRef verboseDesc
, StringRef shortDesc
, StringRef category
,
122 PathDiagnosticLocation LocationToUnique
, const Decl
*DeclToUnique
,
123 std::unique_ptr
<FilesToLineNumsMap
> ExecutedLines
)
124 : CheckerName(CheckerName
), DeclWithIssue(declWithIssue
),
125 BugType(StripTrailingDots(bugtype
)),
126 VerboseDesc(StripTrailingDots(verboseDesc
)),
127 ShortDesc(StripTrailingDots(shortDesc
)),
128 Category(StripTrailingDots(category
)), UniqueingLoc(LocationToUnique
),
129 UniqueingDecl(DeclToUnique
), ExecutedLines(std::move(ExecutedLines
)),
132 void PathDiagnosticConsumer::anchor() {}
134 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
135 // Delete the contents of the FoldingSet if it isn't empty already.
136 for (auto &Diag
: Diags
)
140 void PathDiagnosticConsumer::HandlePathDiagnostic(
141 std::unique_ptr
<PathDiagnostic
> D
) {
142 if (!D
|| D
->path
.empty())
145 // We need to flatten the locations (convert Stmt* to locations) because
146 // the referenced statements may be freed by the time the diagnostics
148 D
->flattenLocations();
150 // If the PathDiagnosticConsumer does not support diagnostics that
151 // cross file boundaries, prune out such diagnostics now.
152 if (!supportsCrossFileDiagnostics()) {
153 // Verify that the entire path is from the same FileID.
155 const SourceManager
&SMgr
= D
->path
.front()->getLocation().getManager();
156 SmallVector
<const PathPieces
*, 5> WorkList
;
157 WorkList
.push_back(&D
->path
);
158 SmallString
<128> buf
;
159 llvm::raw_svector_ostream
warning(buf
);
160 warning
<< "warning: Path diagnostic report is not generated. Current "
161 << "output format does not support diagnostics that cross file "
162 << "boundaries. Refer to --analyzer-output for valid output "
165 while (!WorkList
.empty()) {
166 const PathPieces
&path
= *WorkList
.pop_back_val();
168 for (const auto &I
: path
) {
169 const PathDiagnosticPiece
*piece
= I
.get();
170 FullSourceLoc L
= piece
->getLocation().asLocation().getExpansionLoc();
172 if (FID
.isInvalid()) {
173 FID
= SMgr
.getFileID(L
);
174 } else if (SMgr
.getFileID(L
) != FID
) {
175 llvm::errs() << warning
.str();
179 // Check the source ranges.
180 ArrayRef
<SourceRange
> Ranges
= piece
->getRanges();
181 for (const auto &I
: Ranges
) {
182 SourceLocation L
= SMgr
.getExpansionLoc(I
.getBegin());
183 if (!L
.isFileID() || SMgr
.getFileID(L
) != FID
) {
184 llvm::errs() << warning
.str();
187 L
= SMgr
.getExpansionLoc(I
.getEnd());
188 if (!L
.isFileID() || SMgr
.getFileID(L
) != FID
) {
189 llvm::errs() << warning
.str();
194 if (const auto *call
= dyn_cast
<PathDiagnosticCallPiece
>(piece
))
195 WorkList
.push_back(&call
->path
);
196 else if (const auto *macro
= dyn_cast
<PathDiagnosticMacroPiece
>(piece
))
197 WorkList
.push_back(¯o
->subPieces
);
202 return; // FIXME: Emit a warning?
205 // Profile the node to see if we already have something matching it
206 llvm::FoldingSetNodeID profile
;
208 void *InsertPos
= nullptr;
210 if (PathDiagnostic
*orig
= Diags
.FindNodeOrInsertPos(profile
, InsertPos
)) {
211 // Keep the PathDiagnostic with the shorter path.
212 // Note, the enclosing routine is called in deterministic order, so the
213 // results will be consistent between runs (no reason to break ties if the
214 // size is the same).
215 const unsigned orig_size
= orig
->full_size();
216 const unsigned new_size
= D
->full_size();
217 if (orig_size
<= new_size
)
220 assert(orig
!= D
.get());
221 Diags
.RemoveNode(orig
);
225 Diags
.InsertNode(D
.release());
228 static std::optional
<bool> comparePath(const PathPieces
&X
,
229 const PathPieces
&Y
);
231 static std::optional
<bool>
232 compareControlFlow(const PathDiagnosticControlFlowPiece
&X
,
233 const PathDiagnosticControlFlowPiece
&Y
) {
234 FullSourceLoc XSL
= X
.getStartLocation().asLocation();
235 FullSourceLoc YSL
= Y
.getStartLocation().asLocation();
237 return XSL
.isBeforeInTranslationUnitThan(YSL
);
238 FullSourceLoc XEL
= X
.getEndLocation().asLocation();
239 FullSourceLoc YEL
= Y
.getEndLocation().asLocation();
241 return XEL
.isBeforeInTranslationUnitThan(YEL
);
245 static std::optional
<bool> compareMacro(const PathDiagnosticMacroPiece
&X
,
246 const PathDiagnosticMacroPiece
&Y
) {
247 return comparePath(X
.subPieces
, Y
.subPieces
);
250 static std::optional
<bool> compareCall(const PathDiagnosticCallPiece
&X
,
251 const PathDiagnosticCallPiece
&Y
) {
252 FullSourceLoc X_CEL
= X
.callEnter
.asLocation();
253 FullSourceLoc Y_CEL
= Y
.callEnter
.asLocation();
255 return X_CEL
.isBeforeInTranslationUnitThan(Y_CEL
);
256 FullSourceLoc X_CEWL
= X
.callEnterWithin
.asLocation();
257 FullSourceLoc Y_CEWL
= Y
.callEnterWithin
.asLocation();
258 if (X_CEWL
!= Y_CEWL
)
259 return X_CEWL
.isBeforeInTranslationUnitThan(Y_CEWL
);
260 FullSourceLoc X_CRL
= X
.callReturn
.asLocation();
261 FullSourceLoc Y_CRL
= Y
.callReturn
.asLocation();
263 return X_CRL
.isBeforeInTranslationUnitThan(Y_CRL
);
264 return comparePath(X
.path
, Y
.path
);
267 static std::optional
<bool> comparePiece(const PathDiagnosticPiece
&X
,
268 const PathDiagnosticPiece
&Y
) {
269 if (X
.getKind() != Y
.getKind())
270 return X
.getKind() < Y
.getKind();
272 FullSourceLoc XL
= X
.getLocation().asLocation();
273 FullSourceLoc YL
= Y
.getLocation().asLocation();
275 return XL
.isBeforeInTranslationUnitThan(YL
);
277 if (X
.getString() != Y
.getString())
278 return X
.getString() < Y
.getString();
280 if (X
.getRanges().size() != Y
.getRanges().size())
281 return X
.getRanges().size() < Y
.getRanges().size();
283 const SourceManager
&SM
= XL
.getManager();
285 for (unsigned i
= 0, n
= X
.getRanges().size(); i
< n
; ++i
) {
286 SourceRange XR
= X
.getRanges()[i
];
287 SourceRange YR
= Y
.getRanges()[i
];
289 if (XR
.getBegin() != YR
.getBegin())
290 return SM
.isBeforeInTranslationUnit(XR
.getBegin(), YR
.getBegin());
291 return SM
.isBeforeInTranslationUnit(XR
.getEnd(), YR
.getEnd());
295 switch (X
.getKind()) {
296 case PathDiagnosticPiece::ControlFlow
:
297 return compareControlFlow(cast
<PathDiagnosticControlFlowPiece
>(X
),
298 cast
<PathDiagnosticControlFlowPiece
>(Y
));
299 case PathDiagnosticPiece::Macro
:
300 return compareMacro(cast
<PathDiagnosticMacroPiece
>(X
),
301 cast
<PathDiagnosticMacroPiece
>(Y
));
302 case PathDiagnosticPiece::Call
:
303 return compareCall(cast
<PathDiagnosticCallPiece
>(X
),
304 cast
<PathDiagnosticCallPiece
>(Y
));
305 case PathDiagnosticPiece::Event
:
306 case PathDiagnosticPiece::Note
:
307 case PathDiagnosticPiece::PopUp
:
310 llvm_unreachable("all cases handled");
313 static std::optional
<bool> comparePath(const PathPieces
&X
,
314 const PathPieces
&Y
) {
315 if (X
.size() != Y
.size())
316 return X
.size() < Y
.size();
318 PathPieces::const_iterator X_I
= X
.begin(), X_end
= X
.end();
319 PathPieces::const_iterator Y_I
= Y
.begin(), Y_end
= Y
.end();
321 for (; X_I
!= X_end
&& Y_I
!= Y_end
; ++X_I
, ++Y_I
)
322 if (std::optional
<bool> b
= comparePiece(**X_I
, **Y_I
))
328 static bool compareCrossTUSourceLocs(FullSourceLoc XL
, FullSourceLoc YL
) {
329 if (XL
.isInvalid() && YL
.isValid())
331 if (XL
.isValid() && YL
.isInvalid())
333 std::pair
<FileID
, unsigned> XOffs
= XL
.getDecomposedLoc();
334 std::pair
<FileID
, unsigned> YOffs
= YL
.getDecomposedLoc();
335 const SourceManager
&SM
= XL
.getManager();
336 std::pair
<bool, bool> InSameTU
= SM
.isInTheSameTranslationUnit(XOffs
, YOffs
);
338 return XL
.isBeforeInTranslationUnitThan(YL
);
339 const FileEntry
*XFE
= SM
.getFileEntryForID(XL
.getSpellingLoc().getFileID());
340 const FileEntry
*YFE
= SM
.getFileEntryForID(YL
.getSpellingLoc().getFileID());
343 int NameCmp
= XFE
->getName().compare(YFE
->getName());
346 // Last resort: Compare raw file IDs that are possibly expansions.
347 return XL
.getFileID() < YL
.getFileID();
350 static bool compare(const PathDiagnostic
&X
, const PathDiagnostic
&Y
) {
351 FullSourceLoc XL
= X
.getLocation().asLocation();
352 FullSourceLoc YL
= Y
.getLocation().asLocation();
354 return compareCrossTUSourceLocs(XL
, YL
);
355 FullSourceLoc XUL
= X
.getUniqueingLoc().asLocation();
356 FullSourceLoc YUL
= Y
.getUniqueingLoc().asLocation();
358 return compareCrossTUSourceLocs(XUL
, YUL
);
359 if (X
.getBugType() != Y
.getBugType())
360 return X
.getBugType() < Y
.getBugType();
361 if (X
.getCategory() != Y
.getCategory())
362 return X
.getCategory() < Y
.getCategory();
363 if (X
.getVerboseDescription() != Y
.getVerboseDescription())
364 return X
.getVerboseDescription() < Y
.getVerboseDescription();
365 if (X
.getShortDescription() != Y
.getShortDescription())
366 return X
.getShortDescription() < Y
.getShortDescription();
367 auto CompareDecls
= [&XL
](const Decl
*D1
,
368 const Decl
*D2
) -> std::optional
<bool> {
375 SourceLocation D1L
= D1
->getLocation();
376 SourceLocation D2L
= D2
->getLocation();
378 const SourceManager
&SM
= XL
.getManager();
379 return compareCrossTUSourceLocs(FullSourceLoc(D1L
, SM
),
380 FullSourceLoc(D2L
, SM
));
384 if (auto Result
= CompareDecls(X
.getDeclWithIssue(), Y
.getDeclWithIssue()))
387 if (auto Result
= CompareDecls(X
.getUniqueingDecl(), Y
.getUniqueingDecl()))
390 PathDiagnostic::meta_iterator XI
= X
.meta_begin(), XE
= X
.meta_end();
391 PathDiagnostic::meta_iterator YI
= Y
.meta_begin(), YE
= Y
.meta_end();
392 if (XE
- XI
!= YE
- YI
)
393 return (XE
- XI
) < (YE
- YI
);
394 for ( ; XI
!= XE
; ++XI
, ++YI
) {
396 return (*XI
) < (*YI
);
398 return *comparePath(X
.path
, Y
.path
);
401 void PathDiagnosticConsumer::FlushDiagnostics(
402 PathDiagnosticConsumer::FilesMade
*Files
) {
408 std::vector
<const PathDiagnostic
*> BatchDiags
;
409 for (const auto &D
: Diags
)
410 BatchDiags
.push_back(&D
);
412 // Sort the diagnostics so that they are always emitted in a deterministic
414 int (*Comp
)(const PathDiagnostic
*const *, const PathDiagnostic
*const *) =
415 [](const PathDiagnostic
*const *X
, const PathDiagnostic
*const *Y
) {
416 assert(*X
!= *Y
&& "PathDiagnostics not uniqued!");
417 if (compare(**X
, **Y
))
419 assert(compare(**Y
, **X
) && "Not a total order!");
422 array_pod_sort(BatchDiags
.begin(), BatchDiags
.end(), Comp
);
424 FlushDiagnosticsImpl(BatchDiags
, Files
);
426 // Delete the flushed diagnostics.
427 for (const auto D
: BatchDiags
)
430 // Clear out the FoldingSet.
434 PathDiagnosticConsumer::FilesMade::~FilesMade() {
435 for (auto It
= Set
.begin(); It
!= Set
.end();)
436 (It
++)->~PDFileEntry();
439 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic
&PD
,
440 StringRef ConsumerName
,
441 StringRef FileName
) {
442 llvm::FoldingSetNodeID NodeID
;
445 PDFileEntry
*Entry
= Set
.FindNodeOrInsertPos(NodeID
, InsertPos
);
447 Entry
= Alloc
.Allocate
<PDFileEntry
>();
448 Entry
= new (Entry
) PDFileEntry(NodeID
);
449 Set
.InsertNode(Entry
, InsertPos
);
452 // Allocate persistent storage for the file name.
453 char *FileName_cstr
= (char*) Alloc
.Allocate(FileName
.size(), 1);
454 memcpy(FileName_cstr
, FileName
.data(), FileName
.size());
456 Entry
->files
.push_back(std::make_pair(ConsumerName
,
457 StringRef(FileName_cstr
,
461 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles
*
462 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic
&PD
) {
463 llvm::FoldingSetNodeID NodeID
;
466 PDFileEntry
*Entry
= Set
.FindNodeOrInsertPos(NodeID
, InsertPos
);
469 return &Entry
->files
;
472 //===----------------------------------------------------------------------===//
473 // PathDiagnosticLocation methods.
474 //===----------------------------------------------------------------------===//
476 SourceLocation
PathDiagnosticLocation::getValidSourceLocation(
477 const Stmt
*S
, LocationOrAnalysisDeclContext LAC
, bool UseEndOfStatement
) {
478 SourceLocation L
= UseEndOfStatement
? S
->getEndLoc() : S
->getBeginLoc();
479 assert(!LAC
.isNull() &&
480 "A valid LocationContext or AnalysisDeclContext should be passed to "
481 "PathDiagnosticLocation upon creation.");
483 // S might be a temporary statement that does not have a location in the
484 // source code, so find an enclosing statement and use its location.
486 AnalysisDeclContext
*ADC
;
487 if (LAC
.is
<const LocationContext
*>())
488 ADC
= LAC
.get
<const LocationContext
*>()->getAnalysisDeclContext();
490 ADC
= LAC
.get
<AnalysisDeclContext
*>();
492 ParentMap
&PM
= ADC
->getParentMap();
494 const Stmt
*Parent
= S
;
496 Parent
= PM
.getParent(Parent
);
498 // In rare cases, we have implicit top-level expressions,
499 // such as arguments for implicit member initializers.
500 // In this case, fall back to the start of the body (even if we were
501 // asked for the statement end location).
503 const Stmt
*Body
= ADC
->getBody();
505 L
= Body
->getBeginLoc();
507 L
= ADC
->getDecl()->getEndLoc();
511 L
= UseEndOfStatement
? Parent
->getEndLoc() : Parent
->getBeginLoc();
512 } while (!L
.isValid());
515 // FIXME: Ironically, this assert actually fails in some cases.
516 //assert(L.isValid());
520 static PathDiagnosticLocation
521 getLocationForCaller(const StackFrameContext
*SFC
,
522 const LocationContext
*CallerCtx
,
523 const SourceManager
&SM
) {
524 const CFGBlock
&Block
= *SFC
->getCallSiteBlock();
525 CFGElement Source
= Block
[SFC
->getIndex()];
527 switch (Source
.getKind()) {
528 case CFGElement::Statement
:
529 case CFGElement::Constructor
:
530 case CFGElement::CXXRecordTypedCall
:
531 return PathDiagnosticLocation(Source
.castAs
<CFGStmt
>().getStmt(),
533 case CFGElement::Initializer
: {
534 const CFGInitializer
&Init
= Source
.castAs
<CFGInitializer
>();
535 return PathDiagnosticLocation(Init
.getInitializer()->getInit(),
538 case CFGElement::AutomaticObjectDtor
: {
539 const CFGAutomaticObjDtor
&Dtor
= Source
.castAs
<CFGAutomaticObjDtor
>();
540 return PathDiagnosticLocation::createEnd(Dtor
.getTriggerStmt(),
543 case CFGElement::DeleteDtor
: {
544 const CFGDeleteDtor
&Dtor
= Source
.castAs
<CFGDeleteDtor
>();
545 return PathDiagnosticLocation(Dtor
.getDeleteExpr(), SM
, CallerCtx
);
547 case CFGElement::BaseDtor
:
548 case CFGElement::MemberDtor
: {
549 const AnalysisDeclContext
*CallerInfo
= CallerCtx
->getAnalysisDeclContext();
550 if (const Stmt
*CallerBody
= CallerInfo
->getBody())
551 return PathDiagnosticLocation::createEnd(CallerBody
, SM
, CallerCtx
);
552 return PathDiagnosticLocation::create(CallerInfo
->getDecl(), SM
);
554 case CFGElement::NewAllocator
: {
555 const CFGNewAllocator
&Alloc
= Source
.castAs
<CFGNewAllocator
>();
556 return PathDiagnosticLocation(Alloc
.getAllocatorExpr(), SM
, CallerCtx
);
558 case CFGElement::TemporaryDtor
: {
559 // Temporary destructors are for temporaries. They die immediately at around
560 // the location of CXXBindTemporaryExpr. If they are lifetime-extended,
561 // they'd be dealt with via an AutomaticObjectDtor instead.
562 const auto &Dtor
= Source
.castAs
<CFGTemporaryDtor
>();
563 return PathDiagnosticLocation::createEnd(Dtor
.getBindTemporaryExpr(), SM
,
566 case CFGElement::ScopeBegin
:
567 case CFGElement::ScopeEnd
:
568 llvm_unreachable("not yet implemented!");
569 case CFGElement::LifetimeEnds
:
570 case CFGElement::LoopExit
:
571 llvm_unreachable("CFGElement kind should not be on callsite!");
574 llvm_unreachable("Unknown CFGElement kind");
577 PathDiagnosticLocation
578 PathDiagnosticLocation::createBegin(const Decl
*D
,
579 const SourceManager
&SM
) {
580 return PathDiagnosticLocation(D
->getBeginLoc(), SM
, SingleLocK
);
583 PathDiagnosticLocation
584 PathDiagnosticLocation::createBegin(const Stmt
*S
,
585 const SourceManager
&SM
,
586 LocationOrAnalysisDeclContext LAC
) {
587 return PathDiagnosticLocation(getValidSourceLocation(S
, LAC
),
591 PathDiagnosticLocation
592 PathDiagnosticLocation::createEnd(const Stmt
*S
,
593 const SourceManager
&SM
,
594 LocationOrAnalysisDeclContext LAC
) {
595 if (const auto *CS
= dyn_cast
<CompoundStmt
>(S
))
596 return createEndBrace(CS
, SM
);
597 return PathDiagnosticLocation(getValidSourceLocation(S
, LAC
, /*End=*/true),
601 PathDiagnosticLocation
602 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator
*BO
,
603 const SourceManager
&SM
) {
604 return PathDiagnosticLocation(BO
->getOperatorLoc(), SM
, SingleLocK
);
607 PathDiagnosticLocation
608 PathDiagnosticLocation::createConditionalColonLoc(
609 const ConditionalOperator
*CO
,
610 const SourceManager
&SM
) {
611 return PathDiagnosticLocation(CO
->getColonLoc(), SM
, SingleLocK
);
614 PathDiagnosticLocation
615 PathDiagnosticLocation::createMemberLoc(const MemberExpr
*ME
,
616 const SourceManager
&SM
) {
618 assert(ME
->getMemberLoc().isValid() || ME
->getBeginLoc().isValid());
620 // In some cases, getMemberLoc isn't valid -- in this case we'll return with
621 // some other related valid SourceLocation.
622 if (ME
->getMemberLoc().isValid())
623 return PathDiagnosticLocation(ME
->getMemberLoc(), SM
, SingleLocK
);
625 return PathDiagnosticLocation(ME
->getBeginLoc(), SM
, SingleLocK
);
628 PathDiagnosticLocation
629 PathDiagnosticLocation::createBeginBrace(const CompoundStmt
*CS
,
630 const SourceManager
&SM
) {
631 SourceLocation L
= CS
->getLBracLoc();
632 return PathDiagnosticLocation(L
, SM
, SingleLocK
);
635 PathDiagnosticLocation
636 PathDiagnosticLocation::createEndBrace(const CompoundStmt
*CS
,
637 const SourceManager
&SM
) {
638 SourceLocation L
= CS
->getRBracLoc();
639 return PathDiagnosticLocation(L
, SM
, SingleLocK
);
642 PathDiagnosticLocation
643 PathDiagnosticLocation::createDeclBegin(const LocationContext
*LC
,
644 const SourceManager
&SM
) {
645 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
646 if (const auto *CS
= dyn_cast_or_null
<CompoundStmt
>(LC
->getDecl()->getBody()))
647 if (!CS
->body_empty()) {
648 SourceLocation Loc
= (*CS
->body_begin())->getBeginLoc();
649 return PathDiagnosticLocation(Loc
, SM
, SingleLocK
);
652 return PathDiagnosticLocation();
655 PathDiagnosticLocation
656 PathDiagnosticLocation::createDeclEnd(const LocationContext
*LC
,
657 const SourceManager
&SM
) {
658 SourceLocation L
= LC
->getDecl()->getBodyRBrace();
659 return PathDiagnosticLocation(L
, SM
, SingleLocK
);
662 PathDiagnosticLocation
663 PathDiagnosticLocation::create(const ProgramPoint
& P
,
664 const SourceManager
&SMng
) {
665 const Stmt
* S
= nullptr;
666 if (std::optional
<BlockEdge
> BE
= P
.getAs
<BlockEdge
>()) {
667 const CFGBlock
*BSrc
= BE
->getSrc();
668 if (BSrc
->getTerminator().isVirtualBaseBranch()) {
669 // TODO: VirtualBaseBranches should also appear for destructors.
670 // In this case we should put the diagnostic at the end of decl.
671 return PathDiagnosticLocation::createBegin(
672 P
.getLocationContext()->getDecl(), SMng
);
675 S
= BSrc
->getTerminatorCondition();
677 // If the BlockEdge has no terminator condition statement but its
678 // source is the entry of the CFG (e.g. a checker crated the branch at
679 // the beginning of a function), use the function's declaration instead.
680 assert(BSrc
== &BSrc
->getParent()->getEntry() && "CFGBlock has no "
681 "TerminatorCondition and is not the enrty block of the CFG");
682 return PathDiagnosticLocation::createBegin(
683 P
.getLocationContext()->getDecl(), SMng
);
686 } else if (std::optional
<StmtPoint
> SP
= P
.getAs
<StmtPoint
>()) {
688 if (P
.getAs
<PostStmtPurgeDeadSymbols
>())
689 return PathDiagnosticLocation::createEnd(S
, SMng
, P
.getLocationContext());
690 } else if (std::optional
<PostInitializer
> PIP
= P
.getAs
<PostInitializer
>()) {
691 return PathDiagnosticLocation(PIP
->getInitializer()->getSourceLocation(),
693 } else if (std::optional
<PreImplicitCall
> PIC
= P
.getAs
<PreImplicitCall
>()) {
694 return PathDiagnosticLocation(PIC
->getLocation(), SMng
);
695 } else if (std::optional
<PostImplicitCall
> PIE
=
696 P
.getAs
<PostImplicitCall
>()) {
697 return PathDiagnosticLocation(PIE
->getLocation(), SMng
);
698 } else if (std::optional
<CallEnter
> CE
= P
.getAs
<CallEnter
>()) {
699 return getLocationForCaller(CE
->getCalleeContext(),
700 CE
->getLocationContext(),
702 } else if (std::optional
<CallExitEnd
> CEE
= P
.getAs
<CallExitEnd
>()) {
703 return getLocationForCaller(CEE
->getCalleeContext(),
704 CEE
->getLocationContext(),
706 } else if (auto CEB
= P
.getAs
<CallExitBegin
>()) {
707 if (const ReturnStmt
*RS
= CEB
->getReturnStmt())
708 return PathDiagnosticLocation::createBegin(RS
, SMng
,
709 CEB
->getLocationContext());
710 return PathDiagnosticLocation(
711 CEB
->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng
);
712 } else if (std::optional
<BlockEntrance
> BE
= P
.getAs
<BlockEntrance
>()) {
713 if (std::optional
<CFGElement
> BlockFront
= BE
->getFirstElement()) {
714 if (auto StmtElt
= BlockFront
->getAs
<CFGStmt
>()) {
715 return PathDiagnosticLocation(StmtElt
->getStmt()->getBeginLoc(), SMng
);
716 } else if (auto NewAllocElt
= BlockFront
->getAs
<CFGNewAllocator
>()) {
717 return PathDiagnosticLocation(
718 NewAllocElt
->getAllocatorExpr()->getBeginLoc(), SMng
);
720 llvm_unreachable("Unexpected CFG element at front of block");
723 return PathDiagnosticLocation(
724 BE
->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng
);
725 } else if (std::optional
<FunctionExitPoint
> FE
=
726 P
.getAs
<FunctionExitPoint
>()) {
727 return PathDiagnosticLocation(FE
->getStmt(), SMng
,
728 FE
->getLocationContext());
730 llvm_unreachable("Unexpected ProgramPoint");
733 return PathDiagnosticLocation(S
, SMng
, P
.getLocationContext());
736 PathDiagnosticLocation
PathDiagnosticLocation::createSingleLocation(
737 const PathDiagnosticLocation
&PDL
) {
738 FullSourceLoc L
= PDL
.asLocation();
739 return PathDiagnosticLocation(L
, L
.getManager(), SingleLocK
);
743 PathDiagnosticLocation::genLocation(SourceLocation L
,
744 LocationOrAnalysisDeclContext LAC
) const {
746 // Note that we want a 'switch' here so that the compiler can warn us in
747 // case we add more cases.
753 // Defensive checking.
756 return FullSourceLoc(getValidSourceLocation(S
, LAC
),
757 const_cast<SourceManager
&>(*SM
));
759 // Defensive checking.
762 return FullSourceLoc(D
->getLocation(), const_cast<SourceManager
&>(*SM
));
765 return FullSourceLoc(L
, const_cast<SourceManager
&>(*SM
));
769 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC
) const {
771 // Note that we want a 'switch' here so that the compiler can warn us in
772 // case we add more cases.
775 return PathDiagnosticRange(SourceRange(Loc
,Loc
), true);
779 const Stmt
*S
= asStmt();
780 switch (S
->getStmtClass()) {
783 case Stmt::DeclStmtClass
: {
784 const auto *DS
= cast
<DeclStmt
>(S
);
785 if (DS
->isSingleDecl()) {
786 // Should always be the case, but we'll be defensive.
787 return SourceRange(DS
->getBeginLoc(),
788 DS
->getSingleDecl()->getLocation());
792 // FIXME: Provide better range information for different
794 case Stmt::IfStmtClass
:
795 case Stmt::WhileStmtClass
:
796 case Stmt::DoStmtClass
:
797 case Stmt::ForStmtClass
:
798 case Stmt::ChooseExprClass
:
799 case Stmt::IndirectGotoStmtClass
:
800 case Stmt::SwitchStmtClass
:
801 case Stmt::BinaryConditionalOperatorClass
:
802 case Stmt::ConditionalOperatorClass
:
803 case Stmt::ObjCForCollectionStmtClass
: {
804 SourceLocation L
= getValidSourceLocation(S
, LAC
);
805 return SourceRange(L
, L
);
808 SourceRange R
= S
->getSourceRange();
814 if (const auto *MD
= dyn_cast
<ObjCMethodDecl
>(D
))
815 return MD
->getSourceRange();
816 if (const auto *FD
= dyn_cast
<FunctionDecl
>(D
)) {
817 if (Stmt
*Body
= FD
->getBody())
818 return Body
->getSourceRange();
821 SourceLocation L
= D
->getLocation();
822 return PathDiagnosticRange(SourceRange(L
, L
), true);
826 return SourceRange(Loc
, Loc
);
829 void PathDiagnosticLocation::flatten() {
835 else if (K
== DeclK
) {
842 //===----------------------------------------------------------------------===//
843 // Manipulation of PathDiagnosticCallPieces.
844 //===----------------------------------------------------------------------===//
846 std::shared_ptr
<PathDiagnosticCallPiece
>
847 PathDiagnosticCallPiece::construct(const CallExitEnd
&CE
,
848 const SourceManager
&SM
) {
849 const Decl
*caller
= CE
.getLocationContext()->getDecl();
850 PathDiagnosticLocation pos
= getLocationForCaller(CE
.getCalleeContext(),
851 CE
.getLocationContext(),
853 return std::shared_ptr
<PathDiagnosticCallPiece
>(
854 new PathDiagnosticCallPiece(caller
, pos
));
857 PathDiagnosticCallPiece
*
858 PathDiagnosticCallPiece::construct(PathPieces
&path
,
859 const Decl
*caller
) {
860 std::shared_ptr
<PathDiagnosticCallPiece
> C(
861 new PathDiagnosticCallPiece(path
, caller
));
864 path
.push_front(std::move(C
));
868 void PathDiagnosticCallPiece::setCallee(const CallEnter
&CE
,
869 const SourceManager
&SM
) {
870 const StackFrameContext
*CalleeCtx
= CE
.getCalleeContext();
871 Callee
= CalleeCtx
->getDecl();
873 callEnterWithin
= PathDiagnosticLocation::createBegin(Callee
, SM
);
874 callEnter
= getLocationForCaller(CalleeCtx
, CE
.getLocationContext(), SM
);
876 // Autosynthesized property accessors are special because we'd never
877 // pop back up to non-autosynthesized code until we leave them.
878 // This is not generally true for autosynthesized callees, which may call
879 // non-autosynthesized callbacks.
880 // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag
881 // defaults to false.
882 if (const auto *MD
= dyn_cast
<ObjCMethodDecl
>(Callee
))
883 IsCalleeAnAutosynthesizedPropertyAccessor
= (
884 MD
->isPropertyAccessor() &&
885 CalleeCtx
->getAnalysisDeclContext()->isBodyAutosynthesized());
888 static void describeTemplateParameters(raw_ostream
&Out
,
889 const ArrayRef
<TemplateArgument
> TAList
,
890 const LangOptions
&LO
,
891 StringRef Prefix
= StringRef(),
892 StringRef Postfix
= StringRef());
894 static void describeTemplateParameter(raw_ostream
&Out
,
895 const TemplateArgument
&TArg
,
896 const LangOptions
&LO
) {
898 if (TArg
.getKind() == TemplateArgument::ArgKind::Pack
) {
899 describeTemplateParameters(Out
, TArg
.getPackAsArray(), LO
);
901 TArg
.print(PrintingPolicy(LO
), Out
, /*IncludeType*/ true);
905 static void describeTemplateParameters(raw_ostream
&Out
,
906 const ArrayRef
<TemplateArgument
> TAList
,
907 const LangOptions
&LO
,
908 StringRef Prefix
, StringRef Postfix
) {
913 for (int I
= 0, Last
= TAList
.size() - 1; I
!= Last
; ++I
) {
914 describeTemplateParameter(Out
, TAList
[I
], LO
);
917 describeTemplateParameter(Out
, TAList
[TAList
.size() - 1], LO
);
921 static void describeClass(raw_ostream
&Out
, const CXXRecordDecl
*D
,
922 StringRef Prefix
= StringRef()) {
923 if (!D
->getIdentifier())
925 Out
<< Prefix
<< '\'' << *D
;
926 if (const auto T
= dyn_cast
<ClassTemplateSpecializationDecl
>(D
))
927 describeTemplateParameters(Out
, T
->getTemplateArgs().asArray(),
928 D
->getLangOpts(), "<", ">");
933 static bool describeCodeDecl(raw_ostream
&Out
, const Decl
*D
,
934 bool ExtendedDescription
,
935 StringRef Prefix
= StringRef()) {
939 if (isa
<BlockDecl
>(D
)) {
940 if (ExtendedDescription
)
941 Out
<< Prefix
<< "anonymous block";
942 return ExtendedDescription
;
945 if (const auto *MD
= dyn_cast
<CXXMethodDecl
>(D
)) {
947 if (ExtendedDescription
&& !MD
->isUserProvided()) {
948 if (MD
->isExplicitlyDefaulted())
954 if (const auto *CD
= dyn_cast
<CXXConstructorDecl
>(MD
)) {
955 if (CD
->isDefaultConstructor())
957 else if (CD
->isCopyConstructor())
959 else if (CD
->isMoveConstructor())
962 Out
<< "constructor";
963 describeClass(Out
, MD
->getParent(), " for ");
964 } else if (isa
<CXXDestructorDecl
>(MD
)) {
965 if (!MD
->isUserProvided()) {
967 describeClass(Out
, MD
->getParent(), " for ");
969 // Use ~Foo for explicitly-written destructors.
970 Out
<< "'" << *MD
<< "'";
972 } else if (MD
->isCopyAssignmentOperator()) {
973 Out
<< "copy assignment operator";
974 describeClass(Out
, MD
->getParent(), " for ");
975 } else if (MD
->isMoveAssignmentOperator()) {
976 Out
<< "move assignment operator";
977 describeClass(Out
, MD
->getParent(), " for ");
979 if (MD
->getParent()->getIdentifier())
980 Out
<< "'" << *MD
->getParent() << "::" << *MD
<< "'";
982 Out
<< "'" << *MD
<< "'";
988 Out
<< Prefix
<< '\'' << cast
<NamedDecl
>(*D
);
990 // Adding template parameters.
991 if (const auto FD
= dyn_cast
<FunctionDecl
>(D
))
992 if (const TemplateArgumentList
*TAList
=
993 FD
->getTemplateSpecializationArgs())
994 describeTemplateParameters(Out
, TAList
->asArray(), FD
->getLangOpts(), "<",
1001 std::shared_ptr
<PathDiagnosticEventPiece
>
1002 PathDiagnosticCallPiece::getCallEnterEvent() const {
1003 // We do not produce call enters and call exits for autosynthesized property
1004 // accessors. We do generally produce them for other functions coming from
1005 // the body farm because they may call callbacks that bring us back into
1007 if (!Callee
|| IsCalleeAnAutosynthesizedPropertyAccessor
)
1010 SmallString
<256> buf
;
1011 llvm::raw_svector_ostream
Out(buf
);
1014 describeCodeDecl(Out
, Callee
, /*ExtendedDescription=*/true);
1016 assert(callEnter
.asLocation().isValid());
1017 return std::make_shared
<PathDiagnosticEventPiece
>(callEnter
, Out
.str());
1020 std::shared_ptr
<PathDiagnosticEventPiece
>
1021 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
1022 if (!callEnterWithin
.asLocation().isValid())
1024 if (Callee
->isImplicit() || !Callee
->hasBody())
1026 if (const auto *MD
= dyn_cast
<CXXMethodDecl
>(Callee
))
1027 if (MD
->isDefaulted())
1030 SmallString
<256> buf
;
1031 llvm::raw_svector_ostream
Out(buf
);
1033 Out
<< "Entered call";
1034 describeCodeDecl(Out
, Caller
, /*ExtendedDescription=*/false, " from ");
1036 return std::make_shared
<PathDiagnosticEventPiece
>(callEnterWithin
, Out
.str());
1039 std::shared_ptr
<PathDiagnosticEventPiece
>
1040 PathDiagnosticCallPiece::getCallExitEvent() const {
1041 // We do not produce call enters and call exits for autosynthesized property
1042 // accessors. We do generally produce them for other functions coming from
1043 // the body farm because they may call callbacks that bring us back into
1045 if (NoExit
|| IsCalleeAnAutosynthesizedPropertyAccessor
)
1048 SmallString
<256> buf
;
1049 llvm::raw_svector_ostream
Out(buf
);
1051 if (!CallStackMessage
.empty()) {
1052 Out
<< CallStackMessage
;
1054 bool DidDescribe
= describeCodeDecl(Out
, Callee
,
1055 /*ExtendedDescription=*/false,
1058 Out
<< "Returning to caller";
1061 assert(callReturn
.asLocation().isValid());
1062 return std::make_shared
<PathDiagnosticEventPiece
>(callReturn
, Out
.str());
1065 static void compute_path_size(const PathPieces
&pieces
, unsigned &size
) {
1066 for (const auto &I
: pieces
) {
1067 const PathDiagnosticPiece
*piece
= I
.get();
1068 if (const auto *cp
= dyn_cast
<PathDiagnosticCallPiece
>(piece
))
1069 compute_path_size(cp
->path
, size
);
1075 unsigned PathDiagnostic::full_size() {
1077 compute_path_size(path
, size
);
1081 //===----------------------------------------------------------------------===//
1082 // FoldingSet profiling methods.
1083 //===----------------------------------------------------------------------===//
1085 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID
&ID
) const {
1086 ID
.Add(Range
.getBegin());
1087 ID
.Add(Range
.getEnd());
1088 ID
.Add(static_cast<const SourceLocation
&>(Loc
));
1091 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
1092 ID
.AddInteger((unsigned) getKind());
1094 // FIXME: Add profiling support for code hints.
1095 ID
.AddInteger((unsigned) getDisplayHint());
1096 ArrayRef
<SourceRange
> Ranges
= getRanges();
1097 for (const auto &I
: Ranges
) {
1098 ID
.Add(I
.getBegin());
1103 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
1104 PathDiagnosticPiece::Profile(ID
);
1105 for (const auto &I
: path
)
1109 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
1110 PathDiagnosticPiece::Profile(ID
);
1114 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
1115 PathDiagnosticPiece::Profile(ID
);
1116 for (const auto &I
: *this)
1120 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
1121 PathDiagnosticSpotPiece::Profile(ID
);
1122 for (const auto &I
: subPieces
)
1126 void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
1127 PathDiagnosticSpotPiece::Profile(ID
);
1130 void PathDiagnosticPopUpPiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
1131 PathDiagnosticSpotPiece::Profile(ID
);
1134 void PathDiagnostic::Profile(llvm::FoldingSetNodeID
&ID
) const {
1135 ID
.Add(getLocation());
1136 ID
.Add(getUniqueingLoc());
1137 ID
.AddString(BugType
);
1138 ID
.AddString(VerboseDesc
);
1139 ID
.AddString(Category
);
1142 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID
&ID
) const {
1144 for (const auto &I
: path
)
1146 for (meta_iterator I
= meta_begin(), E
= meta_end(); I
!= E
; ++I
)
1150 LLVM_DUMP_METHOD
void PathPieces::dump() const {
1152 for (PathPieces::const_iterator I
= begin(), E
= end(); I
!= E
; ++I
) {
1153 llvm::errs() << "[" << index
++ << "] ";
1155 llvm::errs() << "\n";
1159 LLVM_DUMP_METHOD
void PathDiagnosticCallPiece::dump() const {
1160 llvm::errs() << "CALL\n--------------\n";
1162 if (const Stmt
*SLoc
= getLocation().getStmtOrNull())
1164 else if (const auto *ND
= dyn_cast_or_null
<NamedDecl
>(getCallee()))
1165 llvm::errs() << *ND
<< "\n";
1167 getLocation().dump();
1170 LLVM_DUMP_METHOD
void PathDiagnosticEventPiece::dump() const {
1171 llvm::errs() << "EVENT\n--------------\n";
1172 llvm::errs() << getString() << "\n";
1173 llvm::errs() << " ---- at ----\n";
1174 getLocation().dump();
1177 LLVM_DUMP_METHOD
void PathDiagnosticControlFlowPiece::dump() const {
1178 llvm::errs() << "CONTROL\n--------------\n";
1179 getStartLocation().dump();
1180 llvm::errs() << " ---- to ----\n";
1181 getEndLocation().dump();
1184 LLVM_DUMP_METHOD
void PathDiagnosticMacroPiece::dump() const {
1185 llvm::errs() << "MACRO\n--------------\n";
1186 // FIXME: Print which macro is being invoked.
1189 LLVM_DUMP_METHOD
void PathDiagnosticNotePiece::dump() const {
1190 llvm::errs() << "NOTE\n--------------\n";
1191 llvm::errs() << getString() << "\n";
1192 llvm::errs() << " ---- at ----\n";
1193 getLocation().dump();
1196 LLVM_DUMP_METHOD
void PathDiagnosticPopUpPiece::dump() const {
1197 llvm::errs() << "POP-UP\n--------------\n";
1198 llvm::errs() << getString() << "\n";
1199 llvm::errs() << " ---- at ----\n";
1200 getLocation().dump();
1203 LLVM_DUMP_METHOD
void PathDiagnosticLocation::dump() const {
1205 llvm::errs() << "<INVALID>\n";
1211 // FIXME: actually print the range.
1212 llvm::errs() << "<range>\n";
1215 asLocation().dump();
1216 llvm::errs() << "\n";
1222 llvm::errs() << "<NULL STMT>\n";
1225 if (const auto *ND
= dyn_cast_or_null
<NamedDecl
>(D
))
1226 llvm::errs() << *ND
<< "\n";
1227 else if (isa
<BlockDecl
>(D
))
1228 // FIXME: Make this nicer.
1229 llvm::errs() << "<block>\n";
1231 llvm::errs() << "<unknown decl>\n";
1233 llvm::errs() << "<NULL DECL>\n";