1 //===- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the PathDiagnostic-related interfaces. 10 // 11 //===----------------------------------------------------------------------===// 12 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" 43 #include <cassert> 44 #include <cstring> 45 #include <memory> 46 #include <optional> 47 #include <utility> 48 #include <vector> 49 50 using namespace clang; 51 using namespace ento; 52 53 static StringRef StripTrailingDots(StringRef s) { return s.rtrim('.'); } 54 55 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 56 Kind k, DisplayHint hint) 57 : str(StripTrailingDots(s)), kind(k), Hint(hint) {} 58 59 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 60 : kind(k), Hint(hint) {} 61 62 PathDiagnosticPiece::~PathDiagnosticPiece() = default; 63 64 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default; 65 66 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default; 67 68 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default; 69 70 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default; 71 72 PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default; 73 74 PathDiagnosticPopUpPiece::~PathDiagnosticPopUpPiece() = default; 75 76 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, 77 bool ShouldFlattenMacros) const { 78 for (auto &Piece : *this) { 79 switch (Piece->getKind()) { 80 case PathDiagnosticPiece::Call: { 81 auto &Call = cast<PathDiagnosticCallPiece>(*Piece); 82 if (auto CallEnter = Call.getCallEnterEvent()) 83 Current.push_back(std::move(CallEnter)); 84 Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros); 85 if (auto callExit = Call.getCallExitEvent()) 86 Current.push_back(std::move(callExit)); 87 break; 88 } 89 case PathDiagnosticPiece::Macro: { 90 auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece); 91 if (ShouldFlattenMacros) { 92 Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 93 } else { 94 Current.push_back(Piece); 95 PathPieces NewPath; 96 Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 97 // FIXME: This probably shouldn't mutate the original path piece. 98 Macro.subPieces = NewPath; 99 } 100 break; 101 } 102 case PathDiagnosticPiece::Event: 103 case PathDiagnosticPiece::ControlFlow: 104 case PathDiagnosticPiece::Note: 105 case PathDiagnosticPiece::PopUp: 106 Current.push_back(Piece); 107 break; 108 } 109 } 110 } 111 112 PathDiagnostic::~PathDiagnostic() = default; 113 114 PathDiagnostic::PathDiagnostic( 115 StringRef CheckerName, const Decl *declWithIssue, StringRef bugtype, 116 StringRef verboseDesc, StringRef shortDesc, StringRef category, 117 PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique, 118 const Decl *AnalysisEntryPoint, 119 std::unique_ptr<FilesToLineNumsMap> ExecutedLines) 120 : CheckerName(CheckerName), DeclWithIssue(declWithIssue), 121 BugType(StripTrailingDots(bugtype)), 122 VerboseDesc(StripTrailingDots(verboseDesc)), 123 ShortDesc(StripTrailingDots(shortDesc)), 124 Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique), 125 UniqueingDecl(DeclToUnique), AnalysisEntryPoint(AnalysisEntryPoint), 126 ExecutedLines(std::move(ExecutedLines)), path(pathImpl) { 127 assert(AnalysisEntryPoint); 128 } 129 130 void PathDiagnosticConsumer::anchor() {} 131 132 PathDiagnosticConsumer::~PathDiagnosticConsumer() { 133 // Delete the contents of the FoldingSet if it isn't empty already. 134 for (auto &Diag : Diags) 135 delete &Diag; 136 } 137 138 void PathDiagnosticConsumer::HandlePathDiagnostic( 139 std::unique_ptr<PathDiagnostic> D) { 140 if (!D || D->path.empty()) 141 return; 142 143 // We need to flatten the locations (convert Stmt* to locations) because 144 // the referenced statements may be freed by the time the diagnostics 145 // are emitted. 146 D->flattenLocations(); 147 148 // If the PathDiagnosticConsumer does not support diagnostics that 149 // cross file boundaries, prune out such diagnostics now. 150 if (!supportsCrossFileDiagnostics()) { 151 // Verify that the entire path is from the same FileID. 152 FileID FID; 153 const SourceManager &SMgr = D->path.front()->getLocation().getManager(); 154 SmallVector<const PathPieces *, 5> WorkList; 155 WorkList.push_back(&D->path); 156 SmallString<128> buf; 157 llvm::raw_svector_ostream warning(buf); 158 warning << "warning: Path diagnostic report is not generated. Current " 159 << "output format does not support diagnostics that cross file " 160 << "boundaries. Refer to --analyzer-output for valid output " 161 << "formats\n"; 162 163 while (!WorkList.empty()) { 164 const PathPieces &path = *WorkList.pop_back_val(); 165 166 for (const auto &I : path) { 167 const PathDiagnosticPiece *piece = I.get(); 168 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 169 170 if (FID.isInvalid()) { 171 FID = SMgr.getFileID(L); 172 } else if (SMgr.getFileID(L) != FID) { 173 llvm::errs() << warning.str(); 174 return; 175 } 176 177 // Check the source ranges. 178 ArrayRef<SourceRange> Ranges = piece->getRanges(); 179 for (const auto &I : Ranges) { 180 SourceLocation L = SMgr.getExpansionLoc(I.getBegin()); 181 if (!L.isFileID() || SMgr.getFileID(L) != FID) { 182 llvm::errs() << warning.str(); 183 return; 184 } 185 L = SMgr.getExpansionLoc(I.getEnd()); 186 if (!L.isFileID() || SMgr.getFileID(L) != FID) { 187 llvm::errs() << warning.str(); 188 return; 189 } 190 } 191 192 if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece)) 193 WorkList.push_back(&call->path); 194 else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece)) 195 WorkList.push_back(¯o->subPieces); 196 } 197 } 198 199 if (FID.isInvalid()) 200 return; // FIXME: Emit a warning? 201 } 202 203 // Profile the node to see if we already have something matching it 204 llvm::FoldingSetNodeID profile; 205 D->Profile(profile); 206 void *InsertPos = nullptr; 207 208 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 209 // Keep the PathDiagnostic with the shorter path. 210 // Note, the enclosing routine is called in deterministic order, so the 211 // results will be consistent between runs (no reason to break ties if the 212 // size is the same). 213 const unsigned orig_size = orig->full_size(); 214 const unsigned new_size = D->full_size(); 215 if (orig_size <= new_size) 216 return; 217 218 assert(orig != D.get()); 219 Diags.RemoveNode(orig); 220 delete orig; 221 } 222 223 Diags.InsertNode(D.release()); 224 } 225 226 static std::optional<bool> comparePath(const PathPieces &X, 227 const PathPieces &Y); 228 229 static std::optional<bool> 230 compareControlFlow(const PathDiagnosticControlFlowPiece &X, 231 const PathDiagnosticControlFlowPiece &Y) { 232 FullSourceLoc XSL = X.getStartLocation().asLocation(); 233 FullSourceLoc YSL = Y.getStartLocation().asLocation(); 234 if (XSL != YSL) 235 return XSL.isBeforeInTranslationUnitThan(YSL); 236 FullSourceLoc XEL = X.getEndLocation().asLocation(); 237 FullSourceLoc YEL = Y.getEndLocation().asLocation(); 238 if (XEL != YEL) 239 return XEL.isBeforeInTranslationUnitThan(YEL); 240 return std::nullopt; 241 } 242 243 static std::optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, 244 const PathDiagnosticMacroPiece &Y) { 245 return comparePath(X.subPieces, Y.subPieces); 246 } 247 248 static std::optional<bool> compareCall(const PathDiagnosticCallPiece &X, 249 const PathDiagnosticCallPiece &Y) { 250 FullSourceLoc X_CEL = X.callEnter.asLocation(); 251 FullSourceLoc Y_CEL = Y.callEnter.asLocation(); 252 if (X_CEL != Y_CEL) 253 return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); 254 FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); 255 FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); 256 if (X_CEWL != Y_CEWL) 257 return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); 258 FullSourceLoc X_CRL = X.callReturn.asLocation(); 259 FullSourceLoc Y_CRL = Y.callReturn.asLocation(); 260 if (X_CRL != Y_CRL) 261 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); 262 return comparePath(X.path, Y.path); 263 } 264 265 static std::optional<bool> comparePiece(const PathDiagnosticPiece &X, 266 const PathDiagnosticPiece &Y) { 267 if (X.getKind() != Y.getKind()) 268 return X.getKind() < Y.getKind(); 269 270 FullSourceLoc XL = X.getLocation().asLocation(); 271 FullSourceLoc YL = Y.getLocation().asLocation(); 272 if (XL != YL) 273 return XL.isBeforeInTranslationUnitThan(YL); 274 275 if (X.getString() != Y.getString()) 276 return X.getString() < Y.getString(); 277 278 if (X.getRanges().size() != Y.getRanges().size()) 279 return X.getRanges().size() < Y.getRanges().size(); 280 281 const SourceManager &SM = XL.getManager(); 282 283 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { 284 SourceRange XR = X.getRanges()[i]; 285 SourceRange YR = Y.getRanges()[i]; 286 if (XR != YR) { 287 if (XR.getBegin() != YR.getBegin()) 288 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); 289 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); 290 } 291 } 292 293 switch (X.getKind()) { 294 case PathDiagnosticPiece::ControlFlow: 295 return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), 296 cast<PathDiagnosticControlFlowPiece>(Y)); 297 case PathDiagnosticPiece::Macro: 298 return compareMacro(cast<PathDiagnosticMacroPiece>(X), 299 cast<PathDiagnosticMacroPiece>(Y)); 300 case PathDiagnosticPiece::Call: 301 return compareCall(cast<PathDiagnosticCallPiece>(X), 302 cast<PathDiagnosticCallPiece>(Y)); 303 case PathDiagnosticPiece::Event: 304 case PathDiagnosticPiece::Note: 305 case PathDiagnosticPiece::PopUp: 306 return std::nullopt; 307 } 308 llvm_unreachable("all cases handled"); 309 } 310 311 static std::optional<bool> comparePath(const PathPieces &X, 312 const PathPieces &Y) { 313 if (X.size() != Y.size()) 314 return X.size() < Y.size(); 315 316 PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); 317 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); 318 319 for (; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) 320 if (std::optional<bool> b = comparePiece(**X_I, **Y_I)) 321 return *b; 322 323 return std::nullopt; 324 } 325 326 static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) { 327 if (XL.isInvalid() && YL.isValid()) 328 return true; 329 if (XL.isValid() && YL.isInvalid()) 330 return false; 331 std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc(); 332 std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc(); 333 const SourceManager &SM = XL.getManager(); 334 std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs); 335 if (InSameTU.first) 336 return XL.isBeforeInTranslationUnitThan(YL); 337 OptionalFileEntryRef XFE = 338 SM.getFileEntryRefForID(XL.getSpellingLoc().getFileID()); 339 OptionalFileEntryRef YFE = 340 SM.getFileEntryRefForID(YL.getSpellingLoc().getFileID()); 341 if (!XFE || !YFE) 342 return XFE && !YFE; 343 int NameCmp = XFE->getName().compare(YFE->getName()); 344 if (NameCmp != 0) 345 return NameCmp < 0; 346 // Last resort: Compare raw file IDs that are possibly expansions. 347 return XL.getFileID() < YL.getFileID(); 348 } 349 350 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { 351 FullSourceLoc XL = X.getLocation().asLocation(); 352 FullSourceLoc YL = Y.getLocation().asLocation(); 353 if (XL != YL) 354 return compareCrossTUSourceLocs(XL, YL); 355 FullSourceLoc XUL = X.getUniqueingLoc().asLocation(); 356 FullSourceLoc YUL = Y.getUniqueingLoc().asLocation(); 357 if (XUL != YUL) 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> { 369 if (D1 == D2) 370 return std::nullopt; 371 if (!D1) 372 return true; 373 if (!D2) 374 return false; 375 SourceLocation D1L = D1->getLocation(); 376 SourceLocation D2L = D2->getLocation(); 377 if (D1L != D2L) { 378 const SourceManager &SM = XL.getManager(); 379 return compareCrossTUSourceLocs(FullSourceLoc(D1L, SM), 380 FullSourceLoc(D2L, SM)); 381 } 382 return std::nullopt; 383 }; 384 if (auto Result = CompareDecls(X.getDeclWithIssue(), Y.getDeclWithIssue())) 385 return *Result; 386 if (XUL.isValid()) { 387 if (auto Result = CompareDecls(X.getUniqueingDecl(), Y.getUniqueingDecl())) 388 return *Result; 389 } 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) { 395 if (*XI != *YI) 396 return (*XI) < (*YI); 397 } 398 return *comparePath(X.path, Y.path); 399 } 400 401 void PathDiagnosticConsumer::FlushDiagnostics( 402 PathDiagnosticConsumer::FilesMade *Files) { 403 if (flushed) 404 return; 405 406 flushed = true; 407 408 std::vector<const PathDiagnostic *> BatchDiags; 409 for (const auto &D : Diags) 410 BatchDiags.push_back(&D); 411 412 // Sort the diagnostics so that they are always emitted in a deterministic 413 // order. 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)) 418 return -1; 419 assert(compare(**Y, **X) && "Not a total order!"); 420 return 1; 421 }; 422 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp); 423 424 FlushDiagnosticsImpl(BatchDiags, Files); 425 426 // Delete the flushed diagnostics. 427 for (const auto D : BatchDiags) 428 delete D; 429 430 // Clear out the FoldingSet. 431 Diags.clear(); 432 } 433 434 PathDiagnosticConsumer::FilesMade::~FilesMade() { 435 for (auto It = Set.begin(); It != Set.end();) 436 (It++)->~PDFileEntry(); 437 } 438 439 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 440 StringRef ConsumerName, 441 StringRef FileName) { 442 llvm::FoldingSetNodeID NodeID; 443 NodeID.Add(PD); 444 void *InsertPos; 445 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 446 if (!Entry) { 447 Entry = Alloc.Allocate<PDFileEntry>(); 448 Entry = new (Entry) PDFileEntry(NodeID); 449 Set.InsertNode(Entry, InsertPos); 450 } 451 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()); 455 456 Entry->files.push_back(std::make_pair(ConsumerName, 457 StringRef(FileName_cstr, 458 FileName.size()))); 459 } 460 461 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 462 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 463 llvm::FoldingSetNodeID NodeID; 464 NodeID.Add(PD); 465 void *InsertPos; 466 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 467 if (!Entry) 468 return nullptr; 469 return &Entry->files; 470 } 471 472 //===----------------------------------------------------------------------===// 473 // PathDiagnosticLocation methods. 474 //===----------------------------------------------------------------------===// 475 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."); 482 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. 485 if (!L.isValid()) { 486 AnalysisDeclContext *ADC; 487 if (LAC.is<const LocationContext*>()) 488 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 489 else 490 ADC = LAC.get<AnalysisDeclContext*>(); 491 492 ParentMap &PM = ADC->getParentMap(); 493 494 const Stmt *Parent = S; 495 do { 496 Parent = PM.getParent(Parent); 497 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). 502 if (!Parent) { 503 const Stmt *Body = ADC->getBody(); 504 if (Body) 505 L = Body->getBeginLoc(); 506 else 507 L = ADC->getDecl()->getEndLoc(); 508 break; 509 } 510 511 L = UseEndOfStatement ? Parent->getEndLoc() : Parent->getBeginLoc(); 512 } while (!L.isValid()); 513 } 514 515 // FIXME: Ironically, this assert actually fails in some cases. 516 //assert(L.isValid()); 517 return L; 518 } 519 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()]; 526 527 switch (Source.getKind()) { 528 case CFGElement::Statement: 529 case CFGElement::Constructor: 530 case CFGElement::CXXRecordTypedCall: 531 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), 532 SM, CallerCtx); 533 case CFGElement::Initializer: { 534 const CFGInitializer &Init = Source.castAs<CFGInitializer>(); 535 return PathDiagnosticLocation(Init.getInitializer()->getInit(), 536 SM, CallerCtx); 537 } 538 case CFGElement::AutomaticObjectDtor: { 539 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); 540 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 541 SM, CallerCtx); 542 } 543 case CFGElement::DeleteDtor: { 544 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); 545 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); 546 } 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); 553 } 554 case CFGElement::NewAllocator: { 555 const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>(); 556 return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx); 557 } 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, 564 CallerCtx); 565 } 566 case CFGElement::ScopeBegin: 567 case CFGElement::ScopeEnd: 568 case CFGElement::CleanupFunction: 569 llvm_unreachable("not yet implemented!"); 570 case CFGElement::LifetimeEnds: 571 case CFGElement::LoopExit: 572 llvm_unreachable("CFGElement kind should not be on callsite!"); 573 } 574 575 llvm_unreachable("Unknown CFGElement kind"); 576 } 577 578 PathDiagnosticLocation 579 PathDiagnosticLocation::createBegin(const Decl *D, 580 const SourceManager &SM) { 581 return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK); 582 } 583 584 PathDiagnosticLocation 585 PathDiagnosticLocation::createBegin(const Stmt *S, 586 const SourceManager &SM, 587 LocationOrAnalysisDeclContext LAC) { 588 assert(S && "Statement cannot be null"); 589 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 590 SM, SingleLocK); 591 } 592 593 PathDiagnosticLocation 594 PathDiagnosticLocation::createEnd(const Stmt *S, 595 const SourceManager &SM, 596 LocationOrAnalysisDeclContext LAC) { 597 if (const auto *CS = dyn_cast<CompoundStmt>(S)) 598 return createEndBrace(CS, SM); 599 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 600 SM, SingleLocK); 601 } 602 603 PathDiagnosticLocation 604 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 605 const SourceManager &SM) { 606 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 607 } 608 609 PathDiagnosticLocation 610 PathDiagnosticLocation::createConditionalColonLoc( 611 const ConditionalOperator *CO, 612 const SourceManager &SM) { 613 return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); 614 } 615 616 PathDiagnosticLocation 617 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 618 const SourceManager &SM) { 619 620 assert(ME->getMemberLoc().isValid() || ME->getBeginLoc().isValid()); 621 622 // In some cases, getMemberLoc isn't valid -- in this case we'll return with 623 // some other related valid SourceLocation. 624 if (ME->getMemberLoc().isValid()) 625 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 626 627 return PathDiagnosticLocation(ME->getBeginLoc(), SM, SingleLocK); 628 } 629 630 PathDiagnosticLocation 631 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 632 const SourceManager &SM) { 633 SourceLocation L = CS->getLBracLoc(); 634 return PathDiagnosticLocation(L, SM, SingleLocK); 635 } 636 637 PathDiagnosticLocation 638 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 639 const SourceManager &SM) { 640 SourceLocation L = CS->getRBracLoc(); 641 return PathDiagnosticLocation(L, SM, SingleLocK); 642 } 643 644 PathDiagnosticLocation 645 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 646 const SourceManager &SM) { 647 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 648 if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 649 if (!CS->body_empty()) { 650 SourceLocation Loc = (*CS->body_begin())->getBeginLoc(); 651 return PathDiagnosticLocation(Loc, SM, SingleLocK); 652 } 653 654 return PathDiagnosticLocation(); 655 } 656 657 PathDiagnosticLocation 658 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 659 const SourceManager &SM) { 660 SourceLocation L = LC->getDecl()->getBodyRBrace(); 661 return PathDiagnosticLocation(L, SM, SingleLocK); 662 } 663 664 PathDiagnosticLocation 665 PathDiagnosticLocation::create(const ProgramPoint& P, 666 const SourceManager &SMng) { 667 const Stmt* S = nullptr; 668 if (std::optional<BlockEdge> BE = P.getAs<BlockEdge>()) { 669 const CFGBlock *BSrc = BE->getSrc(); 670 if (BSrc->getTerminator().isVirtualBaseBranch()) { 671 // TODO: VirtualBaseBranches should also appear for destructors. 672 // In this case we should put the diagnostic at the end of decl. 673 return PathDiagnosticLocation::createBegin( 674 P.getLocationContext()->getDecl(), SMng); 675 676 } else { 677 S = BSrc->getTerminatorCondition(); 678 if (!S) { 679 // If the BlockEdge has no terminator condition statement but its 680 // source is the entry of the CFG (e.g. a checker crated the branch at 681 // the beginning of a function), use the function's declaration instead. 682 assert(BSrc == &BSrc->getParent()->getEntry() && "CFGBlock has no " 683 "TerminatorCondition and is not the enrty block of the CFG"); 684 return PathDiagnosticLocation::createBegin( 685 P.getLocationContext()->getDecl(), SMng); 686 } 687 } 688 } else if (std::optional<StmtPoint> SP = P.getAs<StmtPoint>()) { 689 S = SP->getStmt(); 690 if (P.getAs<PostStmtPurgeDeadSymbols>()) 691 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); 692 } else if (std::optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { 693 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), 694 SMng); 695 } else if (std::optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) { 696 return PathDiagnosticLocation(PIC->getLocation(), SMng); 697 } else if (std::optional<PostImplicitCall> PIE = 698 P.getAs<PostImplicitCall>()) { 699 return PathDiagnosticLocation(PIE->getLocation(), SMng); 700 } else if (std::optional<CallEnter> CE = P.getAs<CallEnter>()) { 701 return getLocationForCaller(CE->getCalleeContext(), 702 CE->getLocationContext(), 703 SMng); 704 } else if (std::optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { 705 return getLocationForCaller(CEE->getCalleeContext(), 706 CEE->getLocationContext(), 707 SMng); 708 } else if (auto CEB = P.getAs<CallExitBegin>()) { 709 if (const ReturnStmt *RS = CEB->getReturnStmt()) 710 return PathDiagnosticLocation::createBegin(RS, SMng, 711 CEB->getLocationContext()); 712 return PathDiagnosticLocation( 713 CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng); 714 } else if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { 715 if (std::optional<CFGElement> BlockFront = BE->getFirstElement()) { 716 if (auto StmtElt = BlockFront->getAs<CFGStmt>()) { 717 return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng); 718 } else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) { 719 return PathDiagnosticLocation( 720 NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng); 721 } 722 llvm_unreachable("Unexpected CFG element at front of block"); 723 } 724 725 return PathDiagnosticLocation( 726 BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng); 727 } else if (std::optional<FunctionExitPoint> FE = 728 P.getAs<FunctionExitPoint>()) { 729 return PathDiagnosticLocation(FE->getStmt(), SMng, 730 FE->getLocationContext()); 731 } else { 732 llvm_unreachable("Unexpected ProgramPoint"); 733 } 734 735 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 736 } 737 738 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 739 const PathDiagnosticLocation &PDL) { 740 FullSourceLoc L = PDL.asLocation(); 741 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 742 } 743 744 FullSourceLoc 745 PathDiagnosticLocation::genLocation(SourceLocation L, 746 LocationOrAnalysisDeclContext LAC) const { 747 assert(isValid()); 748 // Note that we want a 'switch' here so that the compiler can warn us in 749 // case we add more cases. 750 switch (K) { 751 case SingleLocK: 752 case RangeK: 753 break; 754 case StmtK: 755 // Defensive checking. 756 if (!S) 757 break; 758 return FullSourceLoc(getValidSourceLocation(S, LAC), 759 const_cast<SourceManager&>(*SM)); 760 case DeclK: 761 // Defensive checking. 762 if (!D) 763 break; 764 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 765 } 766 767 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 768 } 769 770 PathDiagnosticRange 771 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 772 assert(isValid()); 773 // Note that we want a 'switch' here so that the compiler can warn us in 774 // case we add more cases. 775 switch (K) { 776 case SingleLocK: 777 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 778 case RangeK: 779 break; 780 case StmtK: { 781 const Stmt *S = asStmt(); 782 switch (S->getStmtClass()) { 783 default: 784 break; 785 case Stmt::DeclStmtClass: { 786 const auto *DS = cast<DeclStmt>(S); 787 if (DS->isSingleDecl()) { 788 // Should always be the case, but we'll be defensive. 789 return SourceRange(DS->getBeginLoc(), 790 DS->getSingleDecl()->getLocation()); 791 } 792 break; 793 } 794 // FIXME: Provide better range information for different 795 // terminators. 796 case Stmt::IfStmtClass: 797 case Stmt::WhileStmtClass: 798 case Stmt::DoStmtClass: 799 case Stmt::ForStmtClass: 800 case Stmt::ChooseExprClass: 801 case Stmt::IndirectGotoStmtClass: 802 case Stmt::SwitchStmtClass: 803 case Stmt::BinaryConditionalOperatorClass: 804 case Stmt::ConditionalOperatorClass: 805 case Stmt::ObjCForCollectionStmtClass: { 806 SourceLocation L = getValidSourceLocation(S, LAC); 807 return SourceRange(L, L); 808 } 809 } 810 SourceRange R = S->getSourceRange(); 811 if (R.isValid()) 812 return R; 813 break; 814 } 815 case DeclK: 816 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) 817 return MD->getSourceRange(); 818 if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 819 if (Stmt *Body = FD->getBody()) 820 return Body->getSourceRange(); 821 } 822 else { 823 SourceLocation L = D->getLocation(); 824 return PathDiagnosticRange(SourceRange(L, L), true); 825 } 826 } 827 828 return SourceRange(Loc, Loc); 829 } 830 831 void PathDiagnosticLocation::flatten() { 832 if (K == StmtK) { 833 K = RangeK; 834 S = nullptr; 835 D = nullptr; 836 } 837 else if (K == DeclK) { 838 K = SingleLocK; 839 S = nullptr; 840 D = nullptr; 841 } 842 } 843 844 //===----------------------------------------------------------------------===// 845 // Manipulation of PathDiagnosticCallPieces. 846 //===----------------------------------------------------------------------===// 847 848 std::shared_ptr<PathDiagnosticCallPiece> 849 PathDiagnosticCallPiece::construct(const CallExitEnd &CE, 850 const SourceManager &SM) { 851 const Decl *caller = CE.getLocationContext()->getDecl(); 852 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 853 CE.getLocationContext(), 854 SM); 855 return std::shared_ptr<PathDiagnosticCallPiece>( 856 new PathDiagnosticCallPiece(caller, pos)); 857 } 858 859 PathDiagnosticCallPiece * 860 PathDiagnosticCallPiece::construct(PathPieces &path, 861 const Decl *caller) { 862 std::shared_ptr<PathDiagnosticCallPiece> C( 863 new PathDiagnosticCallPiece(path, caller)); 864 path.clear(); 865 auto *R = C.get(); 866 path.push_front(std::move(C)); 867 return R; 868 } 869 870 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 871 const SourceManager &SM) { 872 const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 873 Callee = CalleeCtx->getDecl(); 874 875 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 876 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 877 878 // Autosynthesized property accessors are special because we'd never 879 // pop back up to non-autosynthesized code until we leave them. 880 // This is not generally true for autosynthesized callees, which may call 881 // non-autosynthesized callbacks. 882 // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag 883 // defaults to false. 884 if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee)) 885 IsCalleeAnAutosynthesizedPropertyAccessor = ( 886 MD->isPropertyAccessor() && 887 CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized()); 888 } 889 890 static void describeTemplateParameters(raw_ostream &Out, 891 const ArrayRef<TemplateArgument> TAList, 892 const LangOptions &LO, 893 StringRef Prefix = StringRef(), 894 StringRef Postfix = StringRef()); 895 896 static void describeTemplateParameter(raw_ostream &Out, 897 const TemplateArgument &TArg, 898 const LangOptions &LO) { 899 900 if (TArg.getKind() == TemplateArgument::ArgKind::Pack) { 901 describeTemplateParameters(Out, TArg.getPackAsArray(), LO); 902 } else { 903 TArg.print(PrintingPolicy(LO), Out, /*IncludeType*/ true); 904 } 905 } 906 907 static void describeTemplateParameters(raw_ostream &Out, 908 const ArrayRef<TemplateArgument> TAList, 909 const LangOptions &LO, 910 StringRef Prefix, StringRef Postfix) { 911 if (TAList.empty()) 912 return; 913 914 Out << Prefix; 915 for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) { 916 describeTemplateParameter(Out, TAList[I], LO); 917 Out << ", "; 918 } 919 describeTemplateParameter(Out, TAList[TAList.size() - 1], LO); 920 Out << Postfix; 921 } 922 923 static void describeClass(raw_ostream &Out, const CXXRecordDecl *D, 924 StringRef Prefix = StringRef()) { 925 if (!D->getIdentifier()) 926 return; 927 Out << Prefix << '\'' << *D; 928 if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D)) 929 describeTemplateParameters(Out, T->getTemplateArgs().asArray(), 930 D->getLangOpts(), "<", ">"); 931 932 Out << '\''; 933 } 934 935 static bool describeCodeDecl(raw_ostream &Out, const Decl *D, 936 bool ExtendedDescription, 937 StringRef Prefix = StringRef()) { 938 if (!D) 939 return false; 940 941 if (isa<BlockDecl>(D)) { 942 if (ExtendedDescription) 943 Out << Prefix << "anonymous block"; 944 return ExtendedDescription; 945 } 946 947 if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { 948 Out << Prefix; 949 if (ExtendedDescription && !MD->isUserProvided()) { 950 if (MD->isExplicitlyDefaulted()) 951 Out << "defaulted "; 952 else 953 Out << "implicit "; 954 } 955 956 if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { 957 if (CD->isDefaultConstructor()) 958 Out << "default "; 959 else if (CD->isCopyConstructor()) 960 Out << "copy "; 961 else if (CD->isMoveConstructor()) 962 Out << "move "; 963 964 Out << "constructor"; 965 describeClass(Out, MD->getParent(), " for "); 966 } else if (isa<CXXDestructorDecl>(MD)) { 967 if (!MD->isUserProvided()) { 968 Out << "destructor"; 969 describeClass(Out, MD->getParent(), " for "); 970 } else { 971 // Use ~Foo for explicitly-written destructors. 972 Out << "'" << *MD << "'"; 973 } 974 } else if (MD->isCopyAssignmentOperator()) { 975 Out << "copy assignment operator"; 976 describeClass(Out, MD->getParent(), " for "); 977 } else if (MD->isMoveAssignmentOperator()) { 978 Out << "move assignment operator"; 979 describeClass(Out, MD->getParent(), " for "); 980 } else { 981 if (MD->getParent()->getIdentifier()) 982 Out << "'" << *MD->getParent() << "::" << *MD << "'"; 983 else 984 Out << "'" << *MD << "'"; 985 } 986 987 return true; 988 } 989 990 Out << Prefix << '\'' << cast<NamedDecl>(*D); 991 992 // Adding template parameters. 993 if (const auto FD = dyn_cast<FunctionDecl>(D)) 994 if (const TemplateArgumentList *TAList = 995 FD->getTemplateSpecializationArgs()) 996 describeTemplateParameters(Out, TAList->asArray(), FD->getLangOpts(), "<", 997 ">"); 998 999 Out << '\''; 1000 return true; 1001 } 1002 1003 std::shared_ptr<PathDiagnosticEventPiece> 1004 PathDiagnosticCallPiece::getCallEnterEvent() const { 1005 // We do not produce call enters and call exits for autosynthesized property 1006 // accessors. We do generally produce them for other functions coming from 1007 // the body farm because they may call callbacks that bring us back into 1008 // visible code. 1009 if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor) 1010 return nullptr; 1011 1012 SmallString<256> buf; 1013 llvm::raw_svector_ostream Out(buf); 1014 1015 Out << "Calling "; 1016 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); 1017 1018 assert(callEnter.asLocation().isValid()); 1019 return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str()); 1020 } 1021 1022 std::shared_ptr<PathDiagnosticEventPiece> 1023 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 1024 if (!callEnterWithin.asLocation().isValid()) 1025 return nullptr; 1026 if (Callee->isImplicit() || !Callee->hasBody()) 1027 return nullptr; 1028 if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee)) 1029 if (MD->isDefaulted()) 1030 return nullptr; 1031 1032 SmallString<256> buf; 1033 llvm::raw_svector_ostream Out(buf); 1034 1035 Out << "Entered call"; 1036 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); 1037 1038 return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str()); 1039 } 1040 1041 std::shared_ptr<PathDiagnosticEventPiece> 1042 PathDiagnosticCallPiece::getCallExitEvent() const { 1043 // We do not produce call enters and call exits for autosynthesized property 1044 // accessors. We do generally produce them for other functions coming from 1045 // the body farm because they may call callbacks that bring us back into 1046 // visible code. 1047 if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor) 1048 return nullptr; 1049 1050 SmallString<256> buf; 1051 llvm::raw_svector_ostream Out(buf); 1052 1053 if (!CallStackMessage.empty()) { 1054 Out << CallStackMessage; 1055 } else { 1056 bool DidDescribe = describeCodeDecl(Out, Callee, 1057 /*ExtendedDescription=*/false, 1058 "Returning from "); 1059 if (!DidDescribe) 1060 Out << "Returning to caller"; 1061 } 1062 1063 assert(callReturn.asLocation().isValid()); 1064 return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str()); 1065 } 1066 1067 static void compute_path_size(const PathPieces &pieces, unsigned &size) { 1068 for (const auto &I : pieces) { 1069 const PathDiagnosticPiece *piece = I.get(); 1070 if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece)) 1071 compute_path_size(cp->path, size); 1072 else 1073 ++size; 1074 } 1075 } 1076 1077 unsigned PathDiagnostic::full_size() { 1078 unsigned size = 0; 1079 compute_path_size(path, size); 1080 return size; 1081 } 1082 1083 //===----------------------------------------------------------------------===// 1084 // FoldingSet profiling methods. 1085 //===----------------------------------------------------------------------===// 1086 1087 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 1088 ID.Add(Range.getBegin()); 1089 ID.Add(Range.getEnd()); 1090 ID.Add(static_cast<const SourceLocation &>(Loc)); 1091 } 1092 1093 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1094 ID.AddInteger((unsigned) getKind()); 1095 ID.AddString(str); 1096 // FIXME: Add profiling support for code hints. 1097 ID.AddInteger((unsigned) getDisplayHint()); 1098 ArrayRef<SourceRange> Ranges = getRanges(); 1099 for (const auto &I : Ranges) { 1100 ID.Add(I.getBegin()); 1101 ID.Add(I.getEnd()); 1102 } 1103 } 1104 1105 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1106 PathDiagnosticPiece::Profile(ID); 1107 for (const auto &I : path) 1108 ID.Add(*I); 1109 } 1110 1111 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1112 PathDiagnosticPiece::Profile(ID); 1113 ID.Add(Pos); 1114 } 1115 1116 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1117 PathDiagnosticPiece::Profile(ID); 1118 for (const auto &I : *this) 1119 ID.Add(I); 1120 } 1121 1122 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1123 PathDiagnosticSpotPiece::Profile(ID); 1124 for (const auto &I : subPieces) 1125 ID.Add(*I); 1126 } 1127 1128 void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const { 1129 PathDiagnosticSpotPiece::Profile(ID); 1130 } 1131 1132 void PathDiagnosticPopUpPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1133 PathDiagnosticSpotPiece::Profile(ID); 1134 } 1135 1136 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 1137 ID.Add(getLocation()); 1138 ID.Add(getUniqueingLoc()); 1139 ID.AddString(BugType); 1140 ID.AddString(VerboseDesc); 1141 ID.AddString(Category); 1142 } 1143 1144 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 1145 Profile(ID); 1146 for (const auto &I : path) 1147 ID.Add(*I); 1148 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 1149 ID.AddString(*I); 1150 } 1151 1152 LLVM_DUMP_METHOD void PathPieces::dump() const { 1153 unsigned index = 0; 1154 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 1155 llvm::errs() << "[" << index++ << "] "; 1156 (*I)->dump(); 1157 llvm::errs() << "\n"; 1158 } 1159 } 1160 1161 LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const { 1162 llvm::errs() << "CALL\n--------------\n"; 1163 1164 if (const Stmt *SLoc = getLocation().getStmtOrNull()) 1165 SLoc->dump(); 1166 else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee())) 1167 llvm::errs() << *ND << "\n"; 1168 else 1169 getLocation().dump(); 1170 } 1171 1172 LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const { 1173 llvm::errs() << "EVENT\n--------------\n"; 1174 llvm::errs() << getString() << "\n"; 1175 llvm::errs() << " ---- at ----\n"; 1176 getLocation().dump(); 1177 } 1178 1179 LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const { 1180 llvm::errs() << "CONTROL\n--------------\n"; 1181 getStartLocation().dump(); 1182 llvm::errs() << " ---- to ----\n"; 1183 getEndLocation().dump(); 1184 } 1185 1186 LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const { 1187 llvm::errs() << "MACRO\n--------------\n"; 1188 // FIXME: Print which macro is being invoked. 1189 } 1190 1191 LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const { 1192 llvm::errs() << "NOTE\n--------------\n"; 1193 llvm::errs() << getString() << "\n"; 1194 llvm::errs() << " ---- at ----\n"; 1195 getLocation().dump(); 1196 } 1197 1198 LLVM_DUMP_METHOD void PathDiagnosticPopUpPiece::dump() const { 1199 llvm::errs() << "POP-UP\n--------------\n"; 1200 llvm::errs() << getString() << "\n"; 1201 llvm::errs() << " ---- at ----\n"; 1202 getLocation().dump(); 1203 } 1204 1205 LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const { 1206 if (!isValid()) { 1207 llvm::errs() << "<INVALID>\n"; 1208 return; 1209 } 1210 1211 switch (K) { 1212 case RangeK: 1213 // FIXME: actually print the range. 1214 llvm::errs() << "<range>\n"; 1215 break; 1216 case SingleLocK: 1217 asLocation().dump(); 1218 llvm::errs() << "\n"; 1219 break; 1220 case StmtK: 1221 if (S) 1222 S->dump(); 1223 else 1224 llvm::errs() << "<NULL STMT>\n"; 1225 break; 1226 case DeclK: 1227 if (const auto *ND = dyn_cast_or_null<NamedDecl>(D)) 1228 llvm::errs() << *ND << "\n"; 1229 else if (isa<BlockDecl>(D)) 1230 // FIXME: Make this nicer. 1231 llvm::errs() << "<block>\n"; 1232 else if (D) 1233 llvm::errs() << "<unknown decl>\n"; 1234 else 1235 llvm::errs() << "<NULL DECL>\n"; 1236 break; 1237 } 1238 } 1239