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/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" 45#include <cassert> 46#include <cstring> 47#include <memory> 48#include <utility> 49#include <vector> 50 51using namespace clang; 52using namespace ento; 53 54static StringRef StripTrailingDots(StringRef s) { 55 for (StringRef::size_type i = s.size(); i != 0; --i) 56 if (s[i - 1] != '.') 57 return s.substr(0, i); 58 return {}; 59} 60 61PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 62 Kind k, DisplayHint hint) 63 : str(StripTrailingDots(s)), kind(k), Hint(hint) {} 64 65PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 66 : kind(k), Hint(hint) {} 67 68PathDiagnosticPiece::~PathDiagnosticPiece() = default; 69 70PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default; 71 72PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default; 73 74PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default; 75 76PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default; 77 78PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default; 79 80PathDiagnosticPopUpPiece::~PathDiagnosticPopUpPiece() = default; 81 82void 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)); 93 break; 94 } 95 case PathDiagnosticPiece::Macro: { 96 auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece); 97 if (ShouldFlattenMacros) { 98 Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 99 } else { 100 Current.push_back(Piece); 101 PathPieces NewPath; 102 Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 103 // FIXME: This probably shouldn't mutate the original path piece. 104 Macro.subPieces = NewPath; 105 } 106 break; 107 } 108 case PathDiagnosticPiece::Event: 109 case PathDiagnosticPiece::ControlFlow: 110 case PathDiagnosticPiece::Note: 111 case PathDiagnosticPiece::PopUp: 112 Current.push_back(Piece); 113 break; 114 } 115 } 116} 117 118PathDiagnostic::~PathDiagnostic() = default; 119 120PathDiagnostic::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)), 131 path(pathImpl) {} 132 133void PathDiagnosticConsumer::anchor() {} 134 135PathDiagnosticConsumer::~PathDiagnosticConsumer() { 136 // Delete the contents of the FoldingSet if it isn't empty already. 137 for (auto &Diag : Diags) 138 delete &Diag; 139} 140 141void PathDiagnosticConsumer::HandlePathDiagnostic( 142 std::unique_ptr<PathDiagnostic> D) { 143 if (!D || D->path.empty()) 144 return; 145 146 // We need to flatten the locations (convert Stmt* to locations) because 147 // the referenced statements may be freed by the time the diagnostics 148 // are emitted. 149 D->flattenLocations(); 150 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. 155 FileID FID; 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 " 164 << "formats\n"; 165 166 while (!WorkList.empty()) { 167 const PathPieces &path = *WorkList.pop_back_val(); 168 169 for (const auto &I : path) { 170 const PathDiagnosticPiece *piece = I.get(); 171 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 172 173 if (FID.isInvalid()) { 174 FID = SMgr.getFileID(L); 175 } else if (SMgr.getFileID(L) != FID) { 176 llvm::errs() << warning.str(); 177 return; 178 } 179 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(); 186 return; 187 } 188 L = SMgr.getExpansionLoc(I.getEnd()); 189 if (!L.isFileID() || SMgr.getFileID(L) != FID) { 190 llvm::errs() << warning.str(); 191 return; 192 } 193 } 194 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); 199 } 200 } 201 202 if (FID.isInvalid()) 203 return; // FIXME: Emit a warning? 204 } 205 206 // Profile the node to see if we already have something matching it 207 llvm::FoldingSetNodeID profile; 208 D->Profile(profile); 209 void *InsertPos = nullptr; 210 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) 219 return; 220 221 assert(orig != D.get()); 222 Diags.RemoveNode(orig); 223 delete orig; 224 } 225 226 Diags.InsertNode(D.release()); 227} 228 229static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); 230 231static Optional<bool> 232compareControlFlow(const PathDiagnosticControlFlowPiece &X, 233 const PathDiagnosticControlFlowPiece &Y) { 234 FullSourceLoc XSL = X.getStartLocation().asLocation(); 235 FullSourceLoc YSL = Y.getStartLocation().asLocation(); 236 if (XSL != YSL) 237 return XSL.isBeforeInTranslationUnitThan(YSL); 238 FullSourceLoc XEL = X.getEndLocation().asLocation(); 239 FullSourceLoc YEL = Y.getEndLocation().asLocation(); 240 if (XEL != YEL) 241 return XEL.isBeforeInTranslationUnitThan(YEL); 242 return None; 243} 244 245static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, 246 const PathDiagnosticMacroPiece &Y) { 247 return comparePath(X.subPieces, Y.subPieces); 248} 249 250static Optional<bool> compareCall(const PathDiagnosticCallPiece &X, 251 const PathDiagnosticCallPiece &Y) { 252 FullSourceLoc X_CEL = X.callEnter.asLocation(); 253 FullSourceLoc Y_CEL = Y.callEnter.asLocation(); 254 if (X_CEL != Y_CEL) 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(); 262 if (X_CRL != Y_CRL) 263 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); 264 return comparePath(X.path, Y.path); 265} 266 267static Optional<bool> comparePiece(const PathDiagnosticPiece &X, 268 const PathDiagnosticPiece &Y) { 269 if (X.getKind() != Y.getKind()) 270 return X.getKind() < Y.getKind(); 271 272 FullSourceLoc XL = X.getLocation().asLocation(); 273 FullSourceLoc YL = Y.getLocation().asLocation(); 274 if (XL != YL) 275 return XL.isBeforeInTranslationUnitThan(YL); 276 277 if (X.getString() != Y.getString()) 278 return X.getString() < Y.getString(); 279 280 if (X.getRanges().size() != Y.getRanges().size()) 281 return X.getRanges().size() < Y.getRanges().size(); 282 283 const SourceManager &SM = XL.getManager(); 284 285 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { 286 SourceRange XR = X.getRanges()[i]; 287 SourceRange YR = Y.getRanges()[i]; 288 if (XR != YR) { 289 if (XR.getBegin() != YR.getBegin()) 290 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); 291 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); 292 } 293 } 294 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: 308 return None; 309 } 310 llvm_unreachable("all cases handled"); 311} 312 313static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { 314 if (X.size() != Y.size()) 315 return X.size() < Y.size(); 316 317 PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); 318 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); 319 320 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { 321 Optional<bool> b = comparePiece(**X_I, **Y_I); 322 if (b.hasValue()) 323 return b.getValue(); 324 } 325 326 return None; 327} 328 329static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) { 330 if (XL.isInvalid() && YL.isValid()) 331 return true; 332 if (XL.isValid() && YL.isInvalid()) 333 return false; 334 std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc(); 335 std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc(); 336 const SourceManager &SM = XL.getManager(); 337 std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs); 338 if (InSameTU.first) 339 return XL.isBeforeInTranslationUnitThan(YL); 340 const FileEntry *XFE = SM.getFileEntryForID(XL.getSpellingLoc().getFileID()); 341 const FileEntry *YFE = SM.getFileEntryForID(YL.getSpellingLoc().getFileID()); 342 if (!XFE || !YFE) 343 return XFE && !YFE; 344 int NameCmp = XFE->getName().compare(YFE->getName()); 345 if (NameCmp != 0) 346 return NameCmp == -1; 347 // Last resort: Compare raw file IDs that are possibly expansions. 348 return XL.getFileID() < YL.getFileID(); 349} 350 351static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { 352 FullSourceLoc XL = X.getLocation().asLocation(); 353 FullSourceLoc YL = Y.getLocation().asLocation(); 354 if (XL != YL) 355 return compareCrossTUSourceLocs(XL, YL); 356 FullSourceLoc XUL = X.getUniqueingLoc().asLocation(); 357 FullSourceLoc YUL = Y.getUniqueingLoc().asLocation(); 358 if (XUL != YUL) 359 return compareCrossTUSourceLocs(XUL, YUL); 360 if (X.getBugType() != Y.getBugType()) 361 return X.getBugType() < Y.getBugType(); 362 if (X.getCategory() != Y.getCategory()) 363 return X.getCategory() < Y.getCategory(); 364 if (X.getVerboseDescription() != Y.getVerboseDescription()) 365 return X.getVerboseDescription() < Y.getVerboseDescription(); 366 if (X.getShortDescription() != Y.getShortDescription()) 367 return X.getShortDescription() < Y.getShortDescription(); 368 auto CompareDecls = [&XL](const Decl *D1, const Decl *D2) -> Optional<bool> { 369 if (D1 == D2) 370 return None; 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 None; 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 Optional<bool> b = comparePath(X.path, Y.path); 399 assert(b.hasValue()); 400 return b.getValue(); 401} 402 403void PathDiagnosticConsumer::FlushDiagnostics( 404 PathDiagnosticConsumer::FilesMade *Files) { 405 if (flushed) 406 return; 407 408 flushed = true; 409 410 std::vector<const PathDiagnostic *> BatchDiags; 411 for (const auto &D : Diags) 412 BatchDiags.push_back(&D); 413 414 // Sort the diagnostics so that they are always emitted in a deterministic 415 // order. 416 int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) = 417 [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) { 418 assert(*X != *Y && "PathDiagnostics not uniqued!"); 419 if (compare(**X, **Y)) 420 return -1; 421 assert(compare(**Y, **X) && "Not a total order!"); 422 return 1; 423 }; 424 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp); 425 426 FlushDiagnosticsImpl(BatchDiags, Files); 427 428 // Delete the flushed diagnostics. 429 for (const auto D : BatchDiags) 430 delete D; 431 432 // Clear out the FoldingSet. 433 Diags.clear(); 434} 435 436PathDiagnosticConsumer::FilesMade::~FilesMade() { 437 for (PDFileEntry &Entry : Set) 438 Entry.~PDFileEntry(); 439} 440 441void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 442 StringRef ConsumerName, 443 StringRef FileName) { 444 llvm::FoldingSetNodeID NodeID; 445 NodeID.Add(PD); 446 void *InsertPos; 447 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 448 if (!Entry) { 449 Entry = Alloc.Allocate<PDFileEntry>(); 450 Entry = new (Entry) PDFileEntry(NodeID); 451 Set.InsertNode(Entry, InsertPos); 452 } 453 454 // Allocate persistent storage for the file name. 455 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); 456 memcpy(FileName_cstr, FileName.data(), FileName.size()); 457 458 Entry->files.push_back(std::make_pair(ConsumerName, 459 StringRef(FileName_cstr, 460 FileName.size()))); 461} 462 463PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 464PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 465 llvm::FoldingSetNodeID NodeID; 466 NodeID.Add(PD); 467 void *InsertPos; 468 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 469 if (!Entry) 470 return nullptr; 471 return &Entry->files; 472} 473 474//===----------------------------------------------------------------------===// 475// PathDiagnosticLocation methods. 476//===----------------------------------------------------------------------===// 477 478SourceLocation PathDiagnosticLocation::getValidSourceLocation( 479 const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement) { 480 SourceLocation L = UseEndOfStatement ? S->getEndLoc() : S->getBeginLoc(); 481 assert(!LAC.isNull() && 482 "A valid LocationContext or AnalysisDeclContext should be passed to " 483 "PathDiagnosticLocation upon creation."); 484 485 // S might be a temporary statement that does not have a location in the 486 // source code, so find an enclosing statement and use its location. 487 if (!L.isValid()) { 488 AnalysisDeclContext *ADC; 489 if (LAC.is<const LocationContext*>()) 490 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 491 else 492 ADC = LAC.get<AnalysisDeclContext*>(); 493 494 ParentMap &PM = ADC->getParentMap(); 495 496 const Stmt *Parent = S; 497 do { 498 Parent = PM.getParent(Parent); 499 500 // In rare cases, we have implicit top-level expressions, 501 // such as arguments for implicit member initializers. 502 // In this case, fall back to the start of the body (even if we were 503 // asked for the statement end location). 504 if (!Parent) { 505 const Stmt *Body = ADC->getBody(); 506 if (Body) 507 L = Body->getBeginLoc(); 508 else 509 L = ADC->getDecl()->getEndLoc(); 510 break; 511 } 512 513 L = UseEndOfStatement ? Parent->getEndLoc() : Parent->getBeginLoc(); 514 } while (!L.isValid()); 515 } 516 517 // FIXME: Ironically, this assert actually fails in some cases. 518 //assert(L.isValid()); 519 return L; 520} 521 522static PathDiagnosticLocation 523getLocationForCaller(const StackFrameContext *SFC, 524 const LocationContext *CallerCtx, 525 const SourceManager &SM) { 526 const CFGBlock &Block = *SFC->getCallSiteBlock(); 527 CFGElement Source = Block[SFC->getIndex()]; 528 529 switch (Source.getKind()) { 530 case CFGElement::Statement: 531 case CFGElement::Constructor: 532 case CFGElement::CXXRecordTypedCall: 533 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), 534 SM, CallerCtx); 535 case CFGElement::Initializer: { 536 const CFGInitializer &Init = Source.castAs<CFGInitializer>(); 537 return PathDiagnosticLocation(Init.getInitializer()->getInit(), 538 SM, CallerCtx); 539 } 540 case CFGElement::AutomaticObjectDtor: { 541 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); 542 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 543 SM, CallerCtx); 544 } 545 case CFGElement::DeleteDtor: { 546 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); 547 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); 548 } 549 case CFGElement::BaseDtor: 550 case CFGElement::MemberDtor: { 551 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); 552 if (const Stmt *CallerBody = CallerInfo->getBody()) 553 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); 554 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); 555 } 556 case CFGElement::NewAllocator: { 557 const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>(); 558 return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx); 559 } 560 case CFGElement::TemporaryDtor: { 561 // Temporary destructors are for temporaries. They die immediately at around 562 // the location of CXXBindTemporaryExpr. If they are lifetime-extended, 563 // they'd be dealt with via an AutomaticObjectDtor instead. 564 const auto &Dtor = Source.castAs<CFGTemporaryDtor>(); 565 return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM, 566 CallerCtx); 567 } 568 case CFGElement::ScopeBegin: 569 case CFGElement::ScopeEnd: 570 llvm_unreachable("not yet implemented!"); 571 case CFGElement::LifetimeEnds: 572 case CFGElement::LoopExit: 573 llvm_unreachable("CFGElement kind should not be on callsite!"); 574 } 575 576 llvm_unreachable("Unknown CFGElement kind"); 577} 578 579PathDiagnosticLocation 580PathDiagnosticLocation::createBegin(const Decl *D, 581 const SourceManager &SM) { 582 return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK); 583} 584 585PathDiagnosticLocation 586PathDiagnosticLocation::createBegin(const Stmt *S, 587 const SourceManager &SM, 588 LocationOrAnalysisDeclContext LAC) { 589 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 590 SM, SingleLocK); 591} 592 593PathDiagnosticLocation 594PathDiagnosticLocation::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 603PathDiagnosticLocation 604PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 605 const SourceManager &SM) { 606 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 607} 608 609PathDiagnosticLocation 610PathDiagnosticLocation::createConditionalColonLoc( 611 const ConditionalOperator *CO, 612 const SourceManager &SM) { 613 return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); 614} 615 616PathDiagnosticLocation 617PathDiagnosticLocation::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 630PathDiagnosticLocation 631PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 632 const SourceManager &SM) { 633 SourceLocation L = CS->getLBracLoc(); 634 return PathDiagnosticLocation(L, SM, SingleLocK); 635} 636 637PathDiagnosticLocation 638PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 639 const SourceManager &SM) { 640 SourceLocation L = CS->getRBracLoc(); 641 return PathDiagnosticLocation(L, SM, SingleLocK); 642} 643 644PathDiagnosticLocation 645PathDiagnosticLocation::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 657PathDiagnosticLocation 658PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 659 const SourceManager &SM) { 660 SourceLocation L = LC->getDecl()->getBodyRBrace(); 661 return PathDiagnosticLocation(L, SM, SingleLocK); 662} 663 664PathDiagnosticLocation 665PathDiagnosticLocation::create(const ProgramPoint& P, 666 const SourceManager &SMng) { 667 const Stmt* S = nullptr; 668 if (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 (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 (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { 693 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), 694 SMng); 695 } else if (Optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) { 696 return PathDiagnosticLocation(PIC->getLocation(), SMng); 697 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { 698 return PathDiagnosticLocation(PIE->getLocation(), SMng); 699 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { 700 return getLocationForCaller(CE->getCalleeContext(), 701 CE->getLocationContext(), 702 SMng); 703 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { 704 return getLocationForCaller(CEE->getCalleeContext(), 705 CEE->getLocationContext(), 706 SMng); 707 } else if (auto CEB = P.getAs<CallExitBegin>()) { 708 if (const ReturnStmt *RS = CEB->getReturnStmt()) 709 return PathDiagnosticLocation::createBegin(RS, SMng, 710 CEB->getLocationContext()); 711 return PathDiagnosticLocation( 712 CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng); 713 } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { 714 if (Optional<CFGElement> BlockFront = BE->getFirstElement()) { 715 if (auto StmtElt = BlockFront->getAs<CFGStmt>()) { 716 return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng); 717 } else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) { 718 return PathDiagnosticLocation( 719 NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng); 720 } 721 llvm_unreachable("Unexpected CFG element at front of block"); 722 } 723 724 return PathDiagnosticLocation( 725 BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng); 726 } else if (Optional<FunctionExitPoint> FE = P.getAs<FunctionExitPoint>()) { 727 return PathDiagnosticLocation(FE->getStmt(), SMng, 728 FE->getLocationContext()); 729 } else { 730 llvm_unreachable("Unexpected ProgramPoint"); 731 } 732 733 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 734} 735 736PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 737 const PathDiagnosticLocation &PDL) { 738 FullSourceLoc L = PDL.asLocation(); 739 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 740} 741 742FullSourceLoc 743 PathDiagnosticLocation::genLocation(SourceLocation L, 744 LocationOrAnalysisDeclContext LAC) const { 745 assert(isValid()); 746 // Note that we want a 'switch' here so that the compiler can warn us in 747 // case we add more cases. 748 switch (K) { 749 case SingleLocK: 750 case RangeK: 751 break; 752 case StmtK: 753 // Defensive checking. 754 if (!S) 755 break; 756 return FullSourceLoc(getValidSourceLocation(S, LAC), 757 const_cast<SourceManager&>(*SM)); 758 case DeclK: 759 // Defensive checking. 760 if (!D) 761 break; 762 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 763 } 764 765 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 766} 767 768PathDiagnosticRange 769 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 770 assert(isValid()); 771 // Note that we want a 'switch' here so that the compiler can warn us in 772 // case we add more cases. 773 switch (K) { 774 case SingleLocK: 775 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 776 case RangeK: 777 break; 778 case StmtK: { 779 const Stmt *S = asStmt(); 780 switch (S->getStmtClass()) { 781 default: 782 break; 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()); 789 } 790 break; 791 } 792 // FIXME: Provide better range information for different 793 // terminators. 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); 806 } 807 } 808 SourceRange R = S->getSourceRange(); 809 if (R.isValid()) 810 return R; 811 break; 812 } 813 case DeclK: 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(); 819 } 820 else { 821 SourceLocation L = D->getLocation(); 822 return PathDiagnosticRange(SourceRange(L, L), true); 823 } 824 } 825 826 return SourceRange(Loc, Loc); 827} 828 829void PathDiagnosticLocation::flatten() { 830 if (K == StmtK) { 831 K = RangeK; 832 S = nullptr; 833 D = nullptr; 834 } 835 else if (K == DeclK) { 836 K = SingleLocK; 837 S = nullptr; 838 D = nullptr; 839 } 840} 841 842//===----------------------------------------------------------------------===// 843// Manipulation of PathDiagnosticCallPieces. 844//===----------------------------------------------------------------------===// 845 846std::shared_ptr<PathDiagnosticCallPiece> 847PathDiagnosticCallPiece::construct(const CallExitEnd &CE, 848 const SourceManager &SM) { 849 const Decl *caller = CE.getLocationContext()->getDecl(); 850 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 851 CE.getLocationContext(), 852 SM); 853 return std::shared_ptr<PathDiagnosticCallPiece>( 854 new PathDiagnosticCallPiece(caller, pos)); 855} 856 857PathDiagnosticCallPiece * 858PathDiagnosticCallPiece::construct(PathPieces &path, 859 const Decl *caller) { 860 std::shared_ptr<PathDiagnosticCallPiece> C( 861 new PathDiagnosticCallPiece(path, caller)); 862 path.clear(); 863 auto *R = C.get(); 864 path.push_front(std::move(C)); 865 return R; 866} 867 868void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 869 const SourceManager &SM) { 870 const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 871 Callee = CalleeCtx->getDecl(); 872 873 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 874 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 875 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()); 886} 887 888static void describeTemplateParameters(raw_ostream &Out, 889 const ArrayRef<TemplateArgument> TAList, 890 const LangOptions &LO, 891 StringRef Prefix = StringRef(), 892 StringRef Postfix = StringRef()); 893 894static void describeTemplateParameter(raw_ostream &Out, 895 const TemplateArgument &TArg, 896 const LangOptions &LO) { 897 898 if (TArg.getKind() == TemplateArgument::ArgKind::Pack) { 899 describeTemplateParameters(Out, TArg.getPackAsArray(), LO); 900 } else { 901 TArg.print(PrintingPolicy(LO), Out, /*IncludeType*/ true); 902 } 903} 904 905static void describeTemplateParameters(raw_ostream &Out, 906 const ArrayRef<TemplateArgument> TAList, 907 const LangOptions &LO, 908 StringRef Prefix, StringRef Postfix) { 909 if (TAList.empty()) 910 return; 911 912 Out << Prefix; 913 for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) { 914 describeTemplateParameter(Out, TAList[I], LO); 915 Out << ", "; 916 } 917 describeTemplateParameter(Out, TAList[TAList.size() - 1], LO); 918 Out << Postfix; 919} 920 921static void describeClass(raw_ostream &Out, const CXXRecordDecl *D, 922 StringRef Prefix = StringRef()) { 923 if (!D->getIdentifier()) 924 return; 925 Out << Prefix << '\'' << *D; 926 if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D)) 927 describeTemplateParameters(Out, T->getTemplateArgs().asArray(), 928 D->getLangOpts(), "<", ">"); 929 930 Out << '\''; 931} 932 933static bool describeCodeDecl(raw_ostream &Out, const Decl *D, 934 bool ExtendedDescription, 935 StringRef Prefix = StringRef()) { 936 if (!D) 937 return false; 938 939 if (isa<BlockDecl>(D)) { 940 if (ExtendedDescription) 941 Out << Prefix << "anonymous block"; 942 return ExtendedDescription; 943 } 944 945 if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { 946 Out << Prefix; 947 if (ExtendedDescription && !MD->isUserProvided()) { 948 if (MD->isExplicitlyDefaulted()) 949 Out << "defaulted "; 950 else 951 Out << "implicit "; 952 } 953 954 if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { 955 if (CD->isDefaultConstructor()) 956 Out << "default "; 957 else if (CD->isCopyConstructor()) 958 Out << "copy "; 959 else if (CD->isMoveConstructor()) 960 Out << "move "; 961 962 Out << "constructor"; 963 describeClass(Out, MD->getParent(), " for "); 964 } else if (isa<CXXDestructorDecl>(MD)) { 965 if (!MD->isUserProvided()) { 966 Out << "destructor"; 967 describeClass(Out, MD->getParent(), " for "); 968 } else { 969 // Use ~Foo for explicitly-written destructors. 970 Out << "'" << *MD << "'"; 971 } 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 "); 978 } else { 979 if (MD->getParent()->getIdentifier()) 980 Out << "'" << *MD->getParent() << "::" << *MD << "'"; 981 else 982 Out << "'" << *MD << "'"; 983 } 984 985 return true; 986 } 987 988 Out << Prefix << '\'' << cast<NamedDecl>(*D); 989 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(), "<", 995 ">"); 996 997 Out << '\''; 998 return true; 999} 1000 1001std::shared_ptr<PathDiagnosticEventPiece> 1002PathDiagnosticCallPiece::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 1006 // visible code. 1007 if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor) 1008 return nullptr; 1009 1010 SmallString<256> buf; 1011 llvm::raw_svector_ostream Out(buf); 1012 1013 Out << "Calling "; 1014 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); 1015 1016 assert(callEnter.asLocation().isValid()); 1017 return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str()); 1018} 1019 1020std::shared_ptr<PathDiagnosticEventPiece> 1021PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 1022 if (!callEnterWithin.asLocation().isValid()) 1023 return nullptr; 1024 if (Callee->isImplicit() || !Callee->hasBody()) 1025 return nullptr; 1026 if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee)) 1027 if (MD->isDefaulted()) 1028 return nullptr; 1029 1030 SmallString<256> buf; 1031 llvm::raw_svector_ostream Out(buf); 1032 1033 Out << "Entered call"; 1034 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); 1035 1036 return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str()); 1037} 1038 1039std::shared_ptr<PathDiagnosticEventPiece> 1040PathDiagnosticCallPiece::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 1044 // visible code. 1045 if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor) 1046 return nullptr; 1047 1048 SmallString<256> buf; 1049 llvm::raw_svector_ostream Out(buf); 1050 1051 if (!CallStackMessage.empty()) { 1052 Out << CallStackMessage; 1053 } else { 1054 bool DidDescribe = describeCodeDecl(Out, Callee, 1055 /*ExtendedDescription=*/false, 1056 "Returning from "); 1057 if (!DidDescribe) 1058 Out << "Returning to caller"; 1059 } 1060 1061 assert(callReturn.asLocation().isValid()); 1062 return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str()); 1063} 1064 1065static 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); 1070 else 1071 ++size; 1072 } 1073} 1074 1075unsigned PathDiagnostic::full_size() { 1076 unsigned size = 0; 1077 compute_path_size(path, size); 1078 return size; 1079} 1080 1081//===----------------------------------------------------------------------===// 1082// FoldingSet profiling methods. 1083//===----------------------------------------------------------------------===// 1084 1085void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 1086 ID.Add(Range.getBegin()); 1087 ID.Add(Range.getEnd()); 1088 ID.Add(static_cast<const SourceLocation &>(Loc)); 1089} 1090 1091void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1092 ID.AddInteger((unsigned) getKind()); 1093 ID.AddString(str); 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()); 1099 ID.Add(I.getEnd()); 1100 } 1101} 1102 1103void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1104 PathDiagnosticPiece::Profile(ID); 1105 for (const auto &I : path) 1106 ID.Add(*I); 1107} 1108 1109void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1110 PathDiagnosticPiece::Profile(ID); 1111 ID.Add(Pos); 1112} 1113 1114void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1115 PathDiagnosticPiece::Profile(ID); 1116 for (const auto &I : *this) 1117 ID.Add(I); 1118} 1119 1120void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1121 PathDiagnosticSpotPiece::Profile(ID); 1122 for (const auto &I : subPieces) 1123 ID.Add(*I); 1124} 1125 1126void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const { 1127 PathDiagnosticSpotPiece::Profile(ID); 1128} 1129 1130void PathDiagnosticPopUpPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1131 PathDiagnosticSpotPiece::Profile(ID); 1132} 1133 1134void 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); 1140} 1141 1142void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 1143 Profile(ID); 1144 for (const auto &I : path) 1145 ID.Add(*I); 1146 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 1147 ID.AddString(*I); 1148} 1149 1150LLVM_DUMP_METHOD void PathPieces::dump() const { 1151 unsigned index = 0; 1152 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 1153 llvm::errs() << "[" << index++ << "] "; 1154 (*I)->dump(); 1155 llvm::errs() << "\n"; 1156 } 1157} 1158 1159LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const { 1160 llvm::errs() << "CALL\n--------------\n"; 1161 1162 if (const Stmt *SLoc = getLocation().getStmtOrNull()) 1163 SLoc->dump(); 1164 else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee())) 1165 llvm::errs() << *ND << "\n"; 1166 else 1167 getLocation().dump(); 1168} 1169 1170LLVM_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(); 1175} 1176 1177LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const { 1178 llvm::errs() << "CONTROL\n--------------\n"; 1179 getStartLocation().dump(); 1180 llvm::errs() << " ---- to ----\n"; 1181 getEndLocation().dump(); 1182} 1183 1184LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const { 1185 llvm::errs() << "MACRO\n--------------\n"; 1186 // FIXME: Print which macro is being invoked. 1187} 1188 1189LLVM_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(); 1194} 1195 1196LLVM_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(); 1201} 1202 1203LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const { 1204 if (!isValid()) { 1205 llvm::errs() << "<INVALID>\n"; 1206 return; 1207 } 1208 1209 switch (K) { 1210 case RangeK: 1211 // FIXME: actually print the range. 1212 llvm::errs() << "<range>\n"; 1213 break; 1214 case SingleLocK: 1215 asLocation().dump(); 1216 llvm::errs() << "\n"; 1217 break; 1218 case StmtK: 1219 if (S) 1220 S->dump(); 1221 else 1222 llvm::errs() << "<NULL STMT>\n"; 1223 break; 1224 case DeclK: 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"; 1230 else if (D) 1231 llvm::errs() << "<unknown decl>\n"; 1232 else 1233 llvm::errs() << "<NULL DECL>\n"; 1234 break; 1235 } 1236} 1237