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/None.h"
36 #include "llvm/ADT/Optional.h"
37 #include "llvm/ADT/STLExtras.h"
38 #include "llvm/ADT/SmallString.h"
39 #include "llvm/ADT/SmallVector.h"
40 #include "llvm/ADT/StringExtras.h"
41 #include "llvm/ADT/StringRef.h"
42 #include "llvm/Support/Casting.h"
43 #include "llvm/Support/ErrorHandling.h"
44 #include "llvm/Support/raw_ostream.h"
51 using namespace clang;
54 static StringRef StripTrailingDots(StringRef s) {
55 for (StringRef::size_type i = s.size(); i != 0; --i)
57 return s.substr(0, i);
61 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
62 Kind k, DisplayHint hint)
63 : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
65 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
66 : kind(k), Hint(hint) {}
68 PathDiagnosticPiece::~PathDiagnosticPiece() = default;
70 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default;
72 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default;
74 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default;
76 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default;
78 PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default;
80 PathDiagnosticPopUpPiece::~PathDiagnosticPopUpPiece() = default;
82 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
83 bool ShouldFlattenMacros) const {
84 for (auto &Piece : *this) {
85 switch (Piece->getKind()) {
86 case PathDiagnosticPiece::Call: {
87 auto &Call = cast<PathDiagnosticCallPiece>(*Piece);
88 if (auto CallEnter = Call.getCallEnterEvent())
89 Current.push_back(std::move(CallEnter));
90 Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros);
91 if (auto callExit = Call.getCallExitEvent())
92 Current.push_back(std::move(callExit));
95 case PathDiagnosticPiece::Macro: {
96 auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece);
97 if (ShouldFlattenMacros) {
98 Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
100 Current.push_back(Piece);
102 Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
103 // FIXME: This probably shouldn't mutate the original path piece.
104 Macro.subPieces = NewPath;
108 case PathDiagnosticPiece::Event:
109 case PathDiagnosticPiece::ControlFlow:
110 case PathDiagnosticPiece::Note:
111 case PathDiagnosticPiece::PopUp:
112 Current.push_back(Piece);
118 PathDiagnostic::~PathDiagnostic() = default;
120 PathDiagnostic::PathDiagnostic(
121 StringRef CheckerName, const Decl *declWithIssue, StringRef bugtype,
122 StringRef verboseDesc, StringRef shortDesc, StringRef category,
123 PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique,
124 std::unique_ptr<FilesToLineNumsMap> ExecutedLines)
125 : CheckerName(CheckerName), DeclWithIssue(declWithIssue),
126 BugType(StripTrailingDots(bugtype)),
127 VerboseDesc(StripTrailingDots(verboseDesc)),
128 ShortDesc(StripTrailingDots(shortDesc)),
129 Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique),
130 UniqueingDecl(DeclToUnique), ExecutedLines(std::move(ExecutedLines)),
133 void PathDiagnosticConsumer::anchor() {}
135 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
136 // Delete the contents of the FoldingSet if it isn't empty already.
137 for (auto &Diag : Diags)
141 void PathDiagnosticConsumer::HandlePathDiagnostic(
142 std::unique_ptr<PathDiagnostic> D) {
143 if (!D || D->path.empty())
146 // We need to flatten the locations (convert Stmt* to locations) because
147 // the referenced statements may be freed by the time the diagnostics
149 D->flattenLocations();
151 // If the PathDiagnosticConsumer does not support diagnostics that
152 // cross file boundaries, prune out such diagnostics now.
153 if (!supportsCrossFileDiagnostics()) {
154 // Verify that the entire path is from the same FileID.
156 const SourceManager &SMgr = D->path.front()->getLocation().getManager();
157 SmallVector<const PathPieces *, 5> WorkList;
158 WorkList.push_back(&D->path);
159 SmallString<128> buf;
160 llvm::raw_svector_ostream warning(buf);
161 warning << "warning: Path diagnostic report is not generated. Current "
162 << "output format does not support diagnostics that cross file "
163 << "boundaries. Refer to --analyzer-output for valid output "
166 while (!WorkList.empty()) {
167 const PathPieces &path = *WorkList.pop_back_val();
169 for (const auto &I : path) {
170 const PathDiagnosticPiece *piece = I.get();
171 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
173 if (FID.isInvalid()) {
174 FID = SMgr.getFileID(L);
175 } else if (SMgr.getFileID(L) != FID) {
176 llvm::errs() << warning.str();
180 // Check the source ranges.
181 ArrayRef<SourceRange> Ranges = piece->getRanges();
182 for (const auto &I : Ranges) {
183 SourceLocation L = SMgr.getExpansionLoc(I.getBegin());
184 if (!L.isFileID() || SMgr.getFileID(L) != FID) {
185 llvm::errs() << warning.str();
188 L = SMgr.getExpansionLoc(I.getEnd());
189 if (!L.isFileID() || SMgr.getFileID(L) != FID) {
190 llvm::errs() << warning.str();
195 if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece))
196 WorkList.push_back(&call->path);
197 else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece))
198 WorkList.push_back(¯o->subPieces);
203 return; // FIXME: Emit a warning?
206 // Profile the node to see if we already have something matching it
207 llvm::FoldingSetNodeID profile;
209 void *InsertPos = nullptr;
211 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
212 // Keep the PathDiagnostic with the shorter path.
213 // Note, the enclosing routine is called in deterministic order, so the
214 // results will be consistent between runs (no reason to break ties if the
215 // size is the same).
216 const unsigned orig_size = orig->full_size();
217 const unsigned new_size = D->full_size();
218 if (orig_size <= new_size)
221 assert(orig != D.get());
222 Diags.RemoveNode(orig);
226 Diags.InsertNode(D.release());
229 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
231 static 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 Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
246 const PathDiagnosticMacroPiece &Y) {
247 return comparePath(X.subPieces, Y.subPieces);
250 static 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 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 Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
314 if (X.size() != Y.size())
315 return X.size() < Y.size();
317 PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
318 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
320 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
321 Optional<bool> b = comparePiece(**X_I, **Y_I);
329 static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) {
330 std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc();
331 std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc();
332 const SourceManager &SM = XL.getManager();
333 std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs);
335 return XL.isBeforeInTranslationUnitThan(YL);
336 const FileEntry *XFE = SM.getFileEntryForID(XL.getSpellingLoc().getFileID());
337 const FileEntry *YFE = SM.getFileEntryForID(YL.getSpellingLoc().getFileID());
340 int NameCmp = XFE->getName().compare(YFE->getName());
342 return NameCmp == -1;
343 // Last resort: Compare raw file IDs that are possibly expansions.
344 return XL.getFileID() < YL.getFileID();
347 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
348 FullSourceLoc XL = X.getLocation().asLocation();
349 FullSourceLoc YL = Y.getLocation().asLocation();
351 return compareCrossTUSourceLocs(XL, YL);
352 if (X.getBugType() != Y.getBugType())
353 return X.getBugType() < Y.getBugType();
354 if (X.getCategory() != Y.getCategory())
355 return X.getCategory() < Y.getCategory();
356 if (X.getVerboseDescription() != Y.getVerboseDescription())
357 return X.getVerboseDescription() < Y.getVerboseDescription();
358 if (X.getShortDescription() != Y.getShortDescription())
359 return X.getShortDescription() < Y.getShortDescription();
360 if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
361 const Decl *XD = X.getDeclWithIssue();
364 const Decl *YD = Y.getDeclWithIssue();
367 SourceLocation XDL = XD->getLocation();
368 SourceLocation YDL = YD->getLocation();
370 const SourceManager &SM = XL.getManager();
371 return compareCrossTUSourceLocs(FullSourceLoc(XDL, SM),
372 FullSourceLoc(YDL, SM));
375 PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
376 PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
377 if (XE - XI != YE - YI)
378 return (XE - XI) < (YE - YI);
379 for ( ; XI != XE ; ++XI, ++YI) {
381 return (*XI) < (*YI);
383 Optional<bool> b = comparePath(X.path, Y.path);
384 assert(b.hasValue());
388 void PathDiagnosticConsumer::FlushDiagnostics(
389 PathDiagnosticConsumer::FilesMade *Files) {
395 std::vector<const PathDiagnostic *> BatchDiags;
396 for (const auto &D : Diags)
397 BatchDiags.push_back(&D);
399 // Sort the diagnostics so that they are always emitted in a deterministic
401 int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) =
402 [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) {
403 assert(*X != *Y && "PathDiagnostics not uniqued!");
404 if (compare(**X, **Y))
406 assert(compare(**Y, **X) && "Not a total order!");
409 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);
411 FlushDiagnosticsImpl(BatchDiags, Files);
413 // Delete the flushed diagnostics.
414 for (const auto D : BatchDiags)
417 // Clear out the FoldingSet.
421 PathDiagnosticConsumer::FilesMade::~FilesMade() {
422 for (PDFileEntry &Entry : Set)
423 Entry.~PDFileEntry();
426 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
427 StringRef ConsumerName,
428 StringRef FileName) {
429 llvm::FoldingSetNodeID NodeID;
432 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
434 Entry = Alloc.Allocate<PDFileEntry>();
435 Entry = new (Entry) PDFileEntry(NodeID);
436 Set.InsertNode(Entry, InsertPos);
439 // Allocate persistent storage for the file name.
440 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
441 memcpy(FileName_cstr, FileName.data(), FileName.size());
443 Entry->files.push_back(std::make_pair(ConsumerName,
444 StringRef(FileName_cstr,
448 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
449 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
450 llvm::FoldingSetNodeID NodeID;
453 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
456 return &Entry->files;
459 //===----------------------------------------------------------------------===//
460 // PathDiagnosticLocation methods.
461 //===----------------------------------------------------------------------===//
463 SourceLocation PathDiagnosticLocation::getValidSourceLocation(
464 const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement) {
465 SourceLocation L = UseEndOfStatement ? S->getEndLoc() : S->getBeginLoc();
466 assert(!LAC.isNull() &&
467 "A valid LocationContext or AnalysisDeclContext should be passed to "
468 "PathDiagnosticLocation upon creation.");
470 // S might be a temporary statement that does not have a location in the
471 // source code, so find an enclosing statement and use its location.
473 AnalysisDeclContext *ADC;
474 if (LAC.is<const LocationContext*>())
475 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
477 ADC = LAC.get<AnalysisDeclContext*>();
479 ParentMap &PM = ADC->getParentMap();
481 const Stmt *Parent = S;
483 Parent = PM.getParent(Parent);
485 // In rare cases, we have implicit top-level expressions,
486 // such as arguments for implicit member initializers.
487 // In this case, fall back to the start of the body (even if we were
488 // asked for the statement end location).
490 const Stmt *Body = ADC->getBody();
492 L = Body->getBeginLoc();
494 L = ADC->getDecl()->getEndLoc();
498 L = UseEndOfStatement ? Parent->getEndLoc() : Parent->getBeginLoc();
499 } while (!L.isValid());
502 // FIXME: Ironically, this assert actually fails in some cases.
503 //assert(L.isValid());
507 static PathDiagnosticLocation
508 getLocationForCaller(const StackFrameContext *SFC,
509 const LocationContext *CallerCtx,
510 const SourceManager &SM) {
511 const CFGBlock &Block = *SFC->getCallSiteBlock();
512 CFGElement Source = Block[SFC->getIndex()];
514 switch (Source.getKind()) {
515 case CFGElement::Statement:
516 case CFGElement::Constructor:
517 case CFGElement::CXXRecordTypedCall:
518 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
520 case CFGElement::Initializer: {
521 const CFGInitializer &Init = Source.castAs<CFGInitializer>();
522 return PathDiagnosticLocation(Init.getInitializer()->getInit(),
525 case CFGElement::AutomaticObjectDtor: {
526 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
527 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
530 case CFGElement::DeleteDtor: {
531 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
532 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
534 case CFGElement::BaseDtor:
535 case CFGElement::MemberDtor: {
536 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
537 if (const Stmt *CallerBody = CallerInfo->getBody())
538 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
539 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
541 case CFGElement::NewAllocator: {
542 const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>();
543 return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx);
545 case CFGElement::TemporaryDtor: {
546 // Temporary destructors are for temporaries. They die immediately at around
547 // the location of CXXBindTemporaryExpr. If they are lifetime-extended,
548 // they'd be dealt with via an AutomaticObjectDtor instead.
549 const auto &Dtor = Source.castAs<CFGTemporaryDtor>();
550 return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM,
553 case CFGElement::ScopeBegin:
554 case CFGElement::ScopeEnd:
555 llvm_unreachable("not yet implemented!");
556 case CFGElement::LifetimeEnds:
557 case CFGElement::LoopExit:
558 llvm_unreachable("CFGElement kind should not be on callsite!");
561 llvm_unreachable("Unknown CFGElement kind");
564 PathDiagnosticLocation
565 PathDiagnosticLocation::createBegin(const Decl *D,
566 const SourceManager &SM) {
567 return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK);
570 PathDiagnosticLocation
571 PathDiagnosticLocation::createBegin(const Stmt *S,
572 const SourceManager &SM,
573 LocationOrAnalysisDeclContext LAC) {
574 return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
578 PathDiagnosticLocation
579 PathDiagnosticLocation::createEnd(const Stmt *S,
580 const SourceManager &SM,
581 LocationOrAnalysisDeclContext LAC) {
582 if (const auto *CS = dyn_cast<CompoundStmt>(S))
583 return createEndBrace(CS, SM);
584 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
588 PathDiagnosticLocation
589 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
590 const SourceManager &SM) {
591 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
594 PathDiagnosticLocation
595 PathDiagnosticLocation::createConditionalColonLoc(
596 const ConditionalOperator *CO,
597 const SourceManager &SM) {
598 return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK);
601 PathDiagnosticLocation
602 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
603 const SourceManager &SM) {
605 assert(ME->getMemberLoc().isValid() || ME->getBeginLoc().isValid());
607 // In some cases, getMemberLoc isn't valid -- in this case we'll return with
608 // some other related valid SourceLocation.
609 if (ME->getMemberLoc().isValid())
610 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
612 return PathDiagnosticLocation(ME->getBeginLoc(), SM, SingleLocK);
615 PathDiagnosticLocation
616 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
617 const SourceManager &SM) {
618 SourceLocation L = CS->getLBracLoc();
619 return PathDiagnosticLocation(L, SM, SingleLocK);
622 PathDiagnosticLocation
623 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
624 const SourceManager &SM) {
625 SourceLocation L = CS->getRBracLoc();
626 return PathDiagnosticLocation(L, SM, SingleLocK);
629 PathDiagnosticLocation
630 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
631 const SourceManager &SM) {
632 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
633 if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
634 if (!CS->body_empty()) {
635 SourceLocation Loc = (*CS->body_begin())->getBeginLoc();
636 return PathDiagnosticLocation(Loc, SM, SingleLocK);
639 return PathDiagnosticLocation();
642 PathDiagnosticLocation
643 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
644 const SourceManager &SM) {
645 SourceLocation L = LC->getDecl()->getBodyRBrace();
646 return PathDiagnosticLocation(L, SM, SingleLocK);
649 PathDiagnosticLocation
650 PathDiagnosticLocation::create(const ProgramPoint& P,
651 const SourceManager &SMng) {
652 const Stmt* S = nullptr;
653 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
654 const CFGBlock *BSrc = BE->getSrc();
655 if (BSrc->getTerminator().isVirtualBaseBranch()) {
656 // TODO: VirtualBaseBranches should also appear for destructors.
657 // In this case we should put the diagnostic at the end of decl.
658 return PathDiagnosticLocation::createBegin(
659 P.getLocationContext()->getDecl(), SMng);
662 S = BSrc->getTerminatorCondition();
664 // If the BlockEdge has no terminator condition statement but its
665 // source is the entry of the CFG (e.g. a checker crated the branch at
666 // the beginning of a function), use the function's declaration instead.
667 assert(BSrc == &BSrc->getParent()->getEntry() && "CFGBlock has no "
668 "TerminatorCondition and is not the enrty block of the CFG");
669 return PathDiagnosticLocation::createBegin(
670 P.getLocationContext()->getDecl(), SMng);
673 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
675 if (P.getAs<PostStmtPurgeDeadSymbols>())
676 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
677 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
678 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
680 } else if (Optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) {
681 return PathDiagnosticLocation(PIC->getLocation(), SMng);
682 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
683 return PathDiagnosticLocation(PIE->getLocation(), SMng);
684 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
685 return getLocationForCaller(CE->getCalleeContext(),
686 CE->getLocationContext(),
688 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
689 return getLocationForCaller(CEE->getCalleeContext(),
690 CEE->getLocationContext(),
692 } else if (auto CEB = P.getAs<CallExitBegin>()) {
693 if (const ReturnStmt *RS = CEB->getReturnStmt())
694 return PathDiagnosticLocation::createBegin(RS, SMng,
695 CEB->getLocationContext());
696 return PathDiagnosticLocation(
697 CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng);
698 } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
699 if (Optional<CFGElement> BlockFront = BE->getFirstElement()) {
700 if (auto StmtElt = BlockFront->getAs<CFGStmt>()) {
701 return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);
702 } else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) {
703 return PathDiagnosticLocation(
704 NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng);
706 llvm_unreachable("Unexpected CFG element at front of block");
709 return PathDiagnosticLocation(
710 BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng);
711 } else if (Optional<FunctionExitPoint> FE = P.getAs<FunctionExitPoint>()) {
712 return PathDiagnosticLocation(FE->getStmt(), SMng,
713 FE->getLocationContext());
715 llvm_unreachable("Unexpected ProgramPoint");
718 return PathDiagnosticLocation(S, SMng, P.getLocationContext());
721 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
722 const PathDiagnosticLocation &PDL) {
723 FullSourceLoc L = PDL.asLocation();
724 return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
728 PathDiagnosticLocation::genLocation(SourceLocation L,
729 LocationOrAnalysisDeclContext LAC) const {
731 // Note that we want a 'switch' here so that the compiler can warn us in
732 // case we add more cases.
738 // Defensive checking.
741 return FullSourceLoc(getValidSourceLocation(S, LAC),
742 const_cast<SourceManager&>(*SM));
744 // Defensive checking.
747 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
750 return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
754 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
756 // Note that we want a 'switch' here so that the compiler can warn us in
757 // case we add more cases.
760 return PathDiagnosticRange(SourceRange(Loc,Loc), true);
764 const Stmt *S = asStmt();
765 switch (S->getStmtClass()) {
768 case Stmt::DeclStmtClass: {
769 const auto *DS = cast<DeclStmt>(S);
770 if (DS->isSingleDecl()) {
771 // Should always be the case, but we'll be defensive.
772 return SourceRange(DS->getBeginLoc(),
773 DS->getSingleDecl()->getLocation());
777 // FIXME: Provide better range information for different
779 case Stmt::IfStmtClass:
780 case Stmt::WhileStmtClass:
781 case Stmt::DoStmtClass:
782 case Stmt::ForStmtClass:
783 case Stmt::ChooseExprClass:
784 case Stmt::IndirectGotoStmtClass:
785 case Stmt::SwitchStmtClass:
786 case Stmt::BinaryConditionalOperatorClass:
787 case Stmt::ConditionalOperatorClass:
788 case Stmt::ObjCForCollectionStmtClass: {
789 SourceLocation L = getValidSourceLocation(S, LAC);
790 return SourceRange(L, L);
793 SourceRange R = S->getSourceRange();
799 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
800 return MD->getSourceRange();
801 if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
802 if (Stmt *Body = FD->getBody())
803 return Body->getSourceRange();
806 SourceLocation L = D->getLocation();
807 return PathDiagnosticRange(SourceRange(L, L), true);
811 return SourceRange(Loc, Loc);
814 void PathDiagnosticLocation::flatten() {
820 else if (K == DeclK) {
827 //===----------------------------------------------------------------------===//
828 // Manipulation of PathDiagnosticCallPieces.
829 //===----------------------------------------------------------------------===//
831 std::shared_ptr<PathDiagnosticCallPiece>
832 PathDiagnosticCallPiece::construct(const CallExitEnd &CE,
833 const SourceManager &SM) {
834 const Decl *caller = CE.getLocationContext()->getDecl();
835 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
836 CE.getLocationContext(),
838 return std::shared_ptr<PathDiagnosticCallPiece>(
839 new PathDiagnosticCallPiece(caller, pos));
842 PathDiagnosticCallPiece *
843 PathDiagnosticCallPiece::construct(PathPieces &path,
844 const Decl *caller) {
845 std::shared_ptr<PathDiagnosticCallPiece> C(
846 new PathDiagnosticCallPiece(path, caller));
849 path.push_front(std::move(C));
853 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
854 const SourceManager &SM) {
855 const StackFrameContext *CalleeCtx = CE.getCalleeContext();
856 Callee = CalleeCtx->getDecl();
858 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
859 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
861 // Autosynthesized property accessors are special because we'd never
862 // pop back up to non-autosynthesized code until we leave them.
863 // This is not generally true for autosynthesized callees, which may call
864 // non-autosynthesized callbacks.
865 // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag
866 // defaults to false.
867 if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee))
868 IsCalleeAnAutosynthesizedPropertyAccessor = (
869 MD->isPropertyAccessor() &&
870 CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());
873 static void describeTemplateParameters(raw_ostream &Out,
874 const ArrayRef<TemplateArgument> TAList,
875 const LangOptions &LO,
876 StringRef Prefix = StringRef(),
877 StringRef Postfix = StringRef());
879 static void describeTemplateParameter(raw_ostream &Out,
880 const TemplateArgument &TArg,
881 const LangOptions &LO) {
883 if (TArg.getKind() == TemplateArgument::ArgKind::Pack) {
884 describeTemplateParameters(Out, TArg.getPackAsArray(), LO);
886 TArg.print(PrintingPolicy(LO), Out);
890 static void describeTemplateParameters(raw_ostream &Out,
891 const ArrayRef<TemplateArgument> TAList,
892 const LangOptions &LO,
893 StringRef Prefix, StringRef Postfix) {
898 for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) {
899 describeTemplateParameter(Out, TAList[I], LO);
902 describeTemplateParameter(Out, TAList[TAList.size() - 1], LO);
906 static void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
907 StringRef Prefix = StringRef()) {
908 if (!D->getIdentifier())
910 Out << Prefix << '\'' << *D;
911 if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D))
912 describeTemplateParameters(Out, T->getTemplateArgs().asArray(),
913 D->getLangOpts(), "<", ">");
918 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
919 bool ExtendedDescription,
920 StringRef Prefix = StringRef()) {
924 if (isa<BlockDecl>(D)) {
925 if (ExtendedDescription)
926 Out << Prefix << "anonymous block";
927 return ExtendedDescription;
930 if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
932 if (ExtendedDescription && !MD->isUserProvided()) {
933 if (MD->isExplicitlyDefaulted())
939 if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
940 if (CD->isDefaultConstructor())
942 else if (CD->isCopyConstructor())
944 else if (CD->isMoveConstructor())
947 Out << "constructor";
948 describeClass(Out, MD->getParent(), " for ");
949 } else if (isa<CXXDestructorDecl>(MD)) {
950 if (!MD->isUserProvided()) {
952 describeClass(Out, MD->getParent(), " for ");
954 // Use ~Foo for explicitly-written destructors.
955 Out << "'" << *MD << "'";
957 } else if (MD->isCopyAssignmentOperator()) {
958 Out << "copy assignment operator";
959 describeClass(Out, MD->getParent(), " for ");
960 } else if (MD->isMoveAssignmentOperator()) {
961 Out << "move assignment operator";
962 describeClass(Out, MD->getParent(), " for ");
964 if (MD->getParent()->getIdentifier())
965 Out << "'" << *MD->getParent() << "::" << *MD << "'";
967 Out << "'" << *MD << "'";
973 Out << Prefix << '\'' << cast<NamedDecl>(*D);
975 // Adding template parameters.
976 if (const auto FD = dyn_cast<FunctionDecl>(D))
977 if (const TemplateArgumentList *TAList =
978 FD->getTemplateSpecializationArgs())
979 describeTemplateParameters(Out, TAList->asArray(), FD->getLangOpts(), "<",
986 std::shared_ptr<PathDiagnosticEventPiece>
987 PathDiagnosticCallPiece::getCallEnterEvent() const {
988 // We do not produce call enters and call exits for autosynthesized property
989 // accessors. We do generally produce them for other functions coming from
990 // the body farm because they may call callbacks that bring us back into
992 if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor)
995 SmallString<256> buf;
996 llvm::raw_svector_ostream Out(buf);
999 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
1001 assert(callEnter.asLocation().isValid());
1002 return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str());
1005 std::shared_ptr<PathDiagnosticEventPiece>
1006 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
1007 if (!callEnterWithin.asLocation().isValid())
1009 if (Callee->isImplicit() || !Callee->hasBody())
1011 if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee))
1012 if (MD->isDefaulted())
1015 SmallString<256> buf;
1016 llvm::raw_svector_ostream Out(buf);
1018 Out << "Entered call";
1019 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
1021 return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str());
1024 std::shared_ptr<PathDiagnosticEventPiece>
1025 PathDiagnosticCallPiece::getCallExitEvent() const {
1026 // We do not produce call enters and call exits for autosynthesized property
1027 // accessors. We do generally produce them for other functions coming from
1028 // the body farm because they may call callbacks that bring us back into
1030 if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor)
1033 SmallString<256> buf;
1034 llvm::raw_svector_ostream Out(buf);
1036 if (!CallStackMessage.empty()) {
1037 Out << CallStackMessage;
1039 bool DidDescribe = describeCodeDecl(Out, Callee,
1040 /*ExtendedDescription=*/false,
1043 Out << "Returning to caller";
1046 assert(callReturn.asLocation().isValid());
1047 return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str());
1050 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
1051 for (const auto &I : pieces) {
1052 const PathDiagnosticPiece *piece = I.get();
1053 if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece))
1054 compute_path_size(cp->path, size);
1060 unsigned PathDiagnostic::full_size() {
1062 compute_path_size(path, size);
1066 //===----------------------------------------------------------------------===//
1067 // FoldingSet profiling methods.
1068 //===----------------------------------------------------------------------===//
1070 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
1071 ID.AddInteger(Range.getBegin().getRawEncoding());
1072 ID.AddInteger(Range.getEnd().getRawEncoding());
1073 ID.AddInteger(Loc.getRawEncoding());
1076 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1077 ID.AddInteger((unsigned) getKind());
1079 // FIXME: Add profiling support for code hints.
1080 ID.AddInteger((unsigned) getDisplayHint());
1081 ArrayRef<SourceRange> Ranges = getRanges();
1082 for (const auto &I : Ranges) {
1083 ID.AddInteger(I.getBegin().getRawEncoding());
1084 ID.AddInteger(I.getEnd().getRawEncoding());
1088 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1089 PathDiagnosticPiece::Profile(ID);
1090 for (const auto &I : path)
1094 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1095 PathDiagnosticPiece::Profile(ID);
1099 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1100 PathDiagnosticPiece::Profile(ID);
1101 for (const auto &I : *this)
1105 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1106 PathDiagnosticSpotPiece::Profile(ID);
1107 for (const auto &I : subPieces)
1111 void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const {
1112 PathDiagnosticSpotPiece::Profile(ID);
1115 void PathDiagnosticPopUpPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1116 PathDiagnosticSpotPiece::Profile(ID);
1119 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
1120 ID.Add(getLocation());
1121 ID.AddString(BugType);
1122 ID.AddString(VerboseDesc);
1123 ID.AddString(Category);
1126 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
1128 for (const auto &I : path)
1130 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1134 LLVM_DUMP_METHOD void PathPieces::dump() const {
1136 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
1137 llvm::errs() << "[" << index++ << "] ";
1139 llvm::errs() << "\n";
1143 LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const {
1144 llvm::errs() << "CALL\n--------------\n";
1146 if (const Stmt *SLoc = getLocation().getStmtOrNull())
1148 else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee()))
1149 llvm::errs() << *ND << "\n";
1151 getLocation().dump();
1154 LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const {
1155 llvm::errs() << "EVENT\n--------------\n";
1156 llvm::errs() << getString() << "\n";
1157 llvm::errs() << " ---- at ----\n";
1158 getLocation().dump();
1161 LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const {
1162 llvm::errs() << "CONTROL\n--------------\n";
1163 getStartLocation().dump();
1164 llvm::errs() << " ---- to ----\n";
1165 getEndLocation().dump();
1168 LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const {
1169 llvm::errs() << "MACRO\n--------------\n";
1170 // FIXME: Print which macro is being invoked.
1173 LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const {
1174 llvm::errs() << "NOTE\n--------------\n";
1175 llvm::errs() << getString() << "\n";
1176 llvm::errs() << " ---- at ----\n";
1177 getLocation().dump();
1180 LLVM_DUMP_METHOD void PathDiagnosticPopUpPiece::dump() const {
1181 llvm::errs() << "POP-UP\n--------------\n";
1182 llvm::errs() << getString() << "\n";
1183 llvm::errs() << " ---- at ----\n";
1184 getLocation().dump();
1187 LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const {
1189 llvm::errs() << "<INVALID>\n";
1195 // FIXME: actually print the range.
1196 llvm::errs() << "<range>\n";
1199 asLocation().dump();
1200 llvm::errs() << "\n";
1206 llvm::errs() << "<NULL STMT>\n";
1209 if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
1210 llvm::errs() << *ND << "\n";
1211 else if (isa<BlockDecl>(D))
1212 // FIXME: Make this nicer.
1213 llvm::errs() << "<block>\n";
1215 llvm::errs() << "<unknown decl>\n";
1217 llvm::errs() << "<NULL DECL>\n";