1 //===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines the PathDiagnostic-related interfaces. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 15 #include "clang/AST/Decl.h" 16 #include "clang/AST/DeclCXX.h" 17 #include "clang/AST/DeclObjC.h" 18 #include "clang/AST/Expr.h" 19 #include "clang/AST/ExprCXX.h" 20 #include "clang/AST/ParentMap.h" 21 #include "clang/AST/StmtCXX.h" 22 #include "clang/Basic/SourceManager.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/ADT/StringExtras.h" 26 #include "llvm/Support/raw_ostream.h" 27 28 using namespace clang; 29 using namespace ento; 30 31 bool PathDiagnosticMacroPiece::containsEvent() const { 32 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 33 I!=E; ++I) { 34 if (isa<PathDiagnosticEventPiece>(*I)) 35 return true; 36 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I)) 37 if (MP->containsEvent()) 38 return true; 39 } 40 return false; 41 } 42 43 static StringRef StripTrailingDots(StringRef s) { 44 for (StringRef::size_type i = s.size(); i != 0; --i) 45 if (s[i - 1] != '.') 46 return s.substr(0, i); 47 return ""; 48 } 49 50 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 51 Kind k, DisplayHint hint) 52 : str(StripTrailingDots(s)), kind(k), Hint(hint), 53 LastInMainSourceFile(false) {} 54 55 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 56 : kind(k), Hint(hint), LastInMainSourceFile(false) {} 57 58 PathDiagnosticPiece::~PathDiagnosticPiece() {} 59 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 60 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} 61 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 62 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} 63 64 65 PathPieces::~PathPieces() {} 66 67 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, 68 bool ShouldFlattenMacros) const { 69 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 70 PathDiagnosticPiece *Piece = I->get(); 71 72 switch (Piece->getKind()) { 73 case PathDiagnosticPiece::Call: { 74 PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece); 75 IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter = 76 Call->getCallEnterEvent(); 77 if (CallEnter) 78 Current.push_back(CallEnter); 79 Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros); 80 IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = 81 Call->getCallExitEvent(); 82 if (callExit) 83 Current.push_back(callExit); 84 break; 85 } 86 case PathDiagnosticPiece::Macro: { 87 PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece); 88 if (ShouldFlattenMacros) { 89 Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 90 } else { 91 Current.push_back(Piece); 92 PathPieces NewPath; 93 Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 94 // FIXME: This probably shouldn't mutate the original path piece. 95 Macro->subPieces = NewPath; 96 } 97 break; 98 } 99 case PathDiagnosticPiece::Event: 100 case PathDiagnosticPiece::ControlFlow: 101 Current.push_back(Piece); 102 break; 103 } 104 } 105 } 106 107 108 PathDiagnostic::~PathDiagnostic() {} 109 110 PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue, 111 StringRef bugtype, StringRef verboseDesc, 112 StringRef shortDesc, StringRef category, 113 PathDiagnosticLocation LocationToUnique, 114 const Decl *DeclToUnique) 115 : CheckName(CheckName), 116 DeclWithIssue(declWithIssue), 117 BugType(StripTrailingDots(bugtype)), 118 VerboseDesc(StripTrailingDots(verboseDesc)), 119 ShortDesc(StripTrailingDots(shortDesc)), 120 Category(StripTrailingDots(category)), 121 UniqueingLoc(LocationToUnique), 122 UniqueingDecl(DeclToUnique), 123 path(pathImpl) {} 124 125 static PathDiagnosticCallPiece * 126 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, 127 const SourceManager &SMgr) { 128 SourceLocation CallLoc = CP->callEnter.asLocation(); 129 130 // If the call is within a macro, don't do anything (for now). 131 if (CallLoc.isMacroID()) 132 return nullptr; 133 134 assert(SMgr.isInMainFile(CallLoc) && 135 "The call piece should be in the main file."); 136 137 // Check if CP represents a path through a function outside of the main file. 138 if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation())) 139 return CP; 140 141 const PathPieces &Path = CP->path; 142 if (Path.empty()) 143 return nullptr; 144 145 // Check if the last piece in the callee path is a call to a function outside 146 // of the main file. 147 if (PathDiagnosticCallPiece *CPInner = 148 dyn_cast<PathDiagnosticCallPiece>(Path.back())) { 149 return getFirstStackedCallToHeaderFile(CPInner, SMgr); 150 } 151 152 // Otherwise, the last piece is in the main file. 153 return nullptr; 154 } 155 156 void PathDiagnostic::resetDiagnosticLocationToMainFile() { 157 if (path.empty()) 158 return; 159 160 PathDiagnosticPiece *LastP = path.back().get(); 161 assert(LastP); 162 const SourceManager &SMgr = LastP->getLocation().getManager(); 163 164 // We only need to check if the report ends inside headers, if the last piece 165 // is a call piece. 166 if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) { 167 CP = getFirstStackedCallToHeaderFile(CP, SMgr); 168 if (CP) { 169 // Mark the piece. 170 CP->setAsLastInMainSourceFile(); 171 172 // Update the path diagnostic message. 173 const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee()); 174 if (ND) { 175 SmallString<200> buf; 176 llvm::raw_svector_ostream os(buf); 177 os << " (within a call to '" << ND->getDeclName() << "')"; 178 appendToDesc(os.str()); 179 } 180 181 // Reset the report containing declaration and location. 182 DeclWithIssue = CP->getCaller(); 183 Loc = CP->getLocation(); 184 185 return; 186 } 187 } 188 } 189 190 void PathDiagnosticConsumer::anchor() { } 191 192 PathDiagnosticConsumer::~PathDiagnosticConsumer() { 193 // Delete the contents of the FoldingSet if it isn't empty already. 194 for (llvm::FoldingSet<PathDiagnostic>::iterator it = 195 Diags.begin(), et = Diags.end() ; it != et ; ++it) { 196 delete &*it; 197 } 198 } 199 200 void PathDiagnosticConsumer::HandlePathDiagnostic( 201 std::unique_ptr<PathDiagnostic> D) { 202 if (!D || D->path.empty()) 203 return; 204 205 // We need to flatten the locations (convert Stmt* to locations) because 206 // the referenced statements may be freed by the time the diagnostics 207 // are emitted. 208 D->flattenLocations(); 209 210 // If the PathDiagnosticConsumer does not support diagnostics that 211 // cross file boundaries, prune out such diagnostics now. 212 if (!supportsCrossFileDiagnostics()) { 213 // Verify that the entire path is from the same FileID. 214 FileID FID; 215 const SourceManager &SMgr = D->path.front()->getLocation().getManager(); 216 SmallVector<const PathPieces *, 5> WorkList; 217 WorkList.push_back(&D->path); 218 219 while (!WorkList.empty()) { 220 const PathPieces &path = *WorkList.pop_back_val(); 221 222 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; 223 ++I) { 224 const PathDiagnosticPiece *piece = I->get(); 225 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 226 227 if (FID.isInvalid()) { 228 FID = SMgr.getFileID(L); 229 } else if (SMgr.getFileID(L) != FID) 230 return; // FIXME: Emit a warning? 231 232 // Check the source ranges. 233 ArrayRef<SourceRange> Ranges = piece->getRanges(); 234 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), 235 E = Ranges.end(); I != E; ++I) { 236 SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); 237 if (!L.isFileID() || SMgr.getFileID(L) != FID) 238 return; // FIXME: Emit a warning? 239 L = SMgr.getExpansionLoc(I->getEnd()); 240 if (!L.isFileID() || SMgr.getFileID(L) != FID) 241 return; // FIXME: Emit a warning? 242 } 243 244 if (const PathDiagnosticCallPiece *call = 245 dyn_cast<PathDiagnosticCallPiece>(piece)) { 246 WorkList.push_back(&call->path); 247 } 248 else if (const PathDiagnosticMacroPiece *macro = 249 dyn_cast<PathDiagnosticMacroPiece>(piece)) { 250 WorkList.push_back(¯o->subPieces); 251 } 252 } 253 } 254 255 if (FID.isInvalid()) 256 return; // FIXME: Emit a warning? 257 } 258 259 // Profile the node to see if we already have something matching it 260 llvm::FoldingSetNodeID profile; 261 D->Profile(profile); 262 void *InsertPos = nullptr; 263 264 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 265 // Keep the PathDiagnostic with the shorter path. 266 // Note, the enclosing routine is called in deterministic order, so the 267 // results will be consistent between runs (no reason to break ties if the 268 // size is the same). 269 const unsigned orig_size = orig->full_size(); 270 const unsigned new_size = D->full_size(); 271 if (orig_size <= new_size) 272 return; 273 274 assert(orig != D.get()); 275 Diags.RemoveNode(orig); 276 delete orig; 277 } 278 279 Diags.InsertNode(D.release()); 280 } 281 282 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); 283 static Optional<bool> 284 compareControlFlow(const PathDiagnosticControlFlowPiece &X, 285 const PathDiagnosticControlFlowPiece &Y) { 286 FullSourceLoc XSL = X.getStartLocation().asLocation(); 287 FullSourceLoc YSL = Y.getStartLocation().asLocation(); 288 if (XSL != YSL) 289 return XSL.isBeforeInTranslationUnitThan(YSL); 290 FullSourceLoc XEL = X.getEndLocation().asLocation(); 291 FullSourceLoc YEL = Y.getEndLocation().asLocation(); 292 if (XEL != YEL) 293 return XEL.isBeforeInTranslationUnitThan(YEL); 294 return None; 295 } 296 297 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, 298 const PathDiagnosticMacroPiece &Y) { 299 return comparePath(X.subPieces, Y.subPieces); 300 } 301 302 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X, 303 const PathDiagnosticCallPiece &Y) { 304 FullSourceLoc X_CEL = X.callEnter.asLocation(); 305 FullSourceLoc Y_CEL = Y.callEnter.asLocation(); 306 if (X_CEL != Y_CEL) 307 return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); 308 FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); 309 FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); 310 if (X_CEWL != Y_CEWL) 311 return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); 312 FullSourceLoc X_CRL = X.callReturn.asLocation(); 313 FullSourceLoc Y_CRL = Y.callReturn.asLocation(); 314 if (X_CRL != Y_CRL) 315 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); 316 return comparePath(X.path, Y.path); 317 } 318 319 static Optional<bool> comparePiece(const PathDiagnosticPiece &X, 320 const PathDiagnosticPiece &Y) { 321 if (X.getKind() != Y.getKind()) 322 return X.getKind() < Y.getKind(); 323 324 FullSourceLoc XL = X.getLocation().asLocation(); 325 FullSourceLoc YL = Y.getLocation().asLocation(); 326 if (XL != YL) 327 return XL.isBeforeInTranslationUnitThan(YL); 328 329 if (X.getString() != Y.getString()) 330 return X.getString() < Y.getString(); 331 332 if (X.getRanges().size() != Y.getRanges().size()) 333 return X.getRanges().size() < Y.getRanges().size(); 334 335 const SourceManager &SM = XL.getManager(); 336 337 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { 338 SourceRange XR = X.getRanges()[i]; 339 SourceRange YR = Y.getRanges()[i]; 340 if (XR != YR) { 341 if (XR.getBegin() != YR.getBegin()) 342 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); 343 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); 344 } 345 } 346 347 switch (X.getKind()) { 348 case clang::ento::PathDiagnosticPiece::ControlFlow: 349 return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), 350 cast<PathDiagnosticControlFlowPiece>(Y)); 351 case clang::ento::PathDiagnosticPiece::Event: 352 return None; 353 case clang::ento::PathDiagnosticPiece::Macro: 354 return compareMacro(cast<PathDiagnosticMacroPiece>(X), 355 cast<PathDiagnosticMacroPiece>(Y)); 356 case clang::ento::PathDiagnosticPiece::Call: 357 return compareCall(cast<PathDiagnosticCallPiece>(X), 358 cast<PathDiagnosticCallPiece>(Y)); 359 } 360 llvm_unreachable("all cases handled"); 361 } 362 363 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { 364 if (X.size() != Y.size()) 365 return X.size() < Y.size(); 366 367 PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); 368 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); 369 370 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { 371 Optional<bool> b = comparePiece(**X_I, **Y_I); 372 if (b.hasValue()) 373 return b.getValue(); 374 } 375 376 return None; 377 } 378 379 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { 380 FullSourceLoc XL = X.getLocation().asLocation(); 381 FullSourceLoc YL = Y.getLocation().asLocation(); 382 if (XL != YL) 383 return XL.isBeforeInTranslationUnitThan(YL); 384 if (X.getBugType() != Y.getBugType()) 385 return X.getBugType() < Y.getBugType(); 386 if (X.getCategory() != Y.getCategory()) 387 return X.getCategory() < Y.getCategory(); 388 if (X.getVerboseDescription() != Y.getVerboseDescription()) 389 return X.getVerboseDescription() < Y.getVerboseDescription(); 390 if (X.getShortDescription() != Y.getShortDescription()) 391 return X.getShortDescription() < Y.getShortDescription(); 392 if (X.getDeclWithIssue() != Y.getDeclWithIssue()) { 393 const Decl *XD = X.getDeclWithIssue(); 394 if (!XD) 395 return true; 396 const Decl *YD = Y.getDeclWithIssue(); 397 if (!YD) 398 return false; 399 SourceLocation XDL = XD->getLocation(); 400 SourceLocation YDL = YD->getLocation(); 401 if (XDL != YDL) { 402 const SourceManager &SM = XL.getManager(); 403 return SM.isBeforeInTranslationUnit(XDL, YDL); 404 } 405 } 406 PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); 407 PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); 408 if (XE - XI != YE - YI) 409 return (XE - XI) < (YE - YI); 410 for ( ; XI != XE ; ++XI, ++YI) { 411 if (*XI != *YI) 412 return (*XI) < (*YI); 413 } 414 Optional<bool> b = comparePath(X.path, Y.path); 415 assert(b.hasValue()); 416 return b.getValue(); 417 } 418 419 void PathDiagnosticConsumer::FlushDiagnostics( 420 PathDiagnosticConsumer::FilesMade *Files) { 421 if (flushed) 422 return; 423 424 flushed = true; 425 426 std::vector<const PathDiagnostic *> BatchDiags; 427 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), 428 et = Diags.end(); it != et; ++it) { 429 const PathDiagnostic *D = &*it; 430 BatchDiags.push_back(D); 431 } 432 433 // Sort the diagnostics so that they are always emitted in a deterministic 434 // order. 435 int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) = 436 [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) { 437 assert(*X != *Y && "PathDiagnostics not uniqued!"); 438 if (compare(**X, **Y)) 439 return -1; 440 assert(compare(**Y, **X) && "Not a total order!"); 441 return 1; 442 }; 443 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp); 444 445 FlushDiagnosticsImpl(BatchDiags, Files); 446 447 // Delete the flushed diagnostics. 448 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), 449 et = BatchDiags.end(); it != et; ++it) { 450 const PathDiagnostic *D = *it; 451 delete D; 452 } 453 454 // Clear out the FoldingSet. 455 Diags.clear(); 456 } 457 458 PathDiagnosticConsumer::FilesMade::~FilesMade() { 459 for (PDFileEntry &Entry : Set) 460 Entry.~PDFileEntry(); 461 } 462 463 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 464 StringRef ConsumerName, 465 StringRef FileName) { 466 llvm::FoldingSetNodeID NodeID; 467 NodeID.Add(PD); 468 void *InsertPos; 469 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 470 if (!Entry) { 471 Entry = Alloc.Allocate<PDFileEntry>(); 472 Entry = new (Entry) PDFileEntry(NodeID); 473 Set.InsertNode(Entry, InsertPos); 474 } 475 476 // Allocate persistent storage for the file name. 477 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); 478 memcpy(FileName_cstr, FileName.data(), FileName.size()); 479 480 Entry->files.push_back(std::make_pair(ConsumerName, 481 StringRef(FileName_cstr, 482 FileName.size()))); 483 } 484 485 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 486 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 487 llvm::FoldingSetNodeID NodeID; 488 NodeID.Add(PD); 489 void *InsertPos; 490 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 491 if (!Entry) 492 return nullptr; 493 return &Entry->files; 494 } 495 496 //===----------------------------------------------------------------------===// 497 // PathDiagnosticLocation methods. 498 //===----------------------------------------------------------------------===// 499 500 static SourceLocation getValidSourceLocation(const Stmt* S, 501 LocationOrAnalysisDeclContext LAC, 502 bool UseEnd = false) { 503 SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart(); 504 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " 505 "be passed to PathDiagnosticLocation upon creation."); 506 507 // S might be a temporary statement that does not have a location in the 508 // source code, so find an enclosing statement and use its location. 509 if (!L.isValid()) { 510 511 AnalysisDeclContext *ADC; 512 if (LAC.is<const LocationContext*>()) 513 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 514 else 515 ADC = LAC.get<AnalysisDeclContext*>(); 516 517 ParentMap &PM = ADC->getParentMap(); 518 519 const Stmt *Parent = S; 520 do { 521 Parent = PM.getParent(Parent); 522 523 // In rare cases, we have implicit top-level expressions, 524 // such as arguments for implicit member initializers. 525 // In this case, fall back to the start of the body (even if we were 526 // asked for the statement end location). 527 if (!Parent) { 528 const Stmt *Body = ADC->getBody(); 529 if (Body) 530 L = Body->getLocStart(); 531 else 532 L = ADC->getDecl()->getLocEnd(); 533 break; 534 } 535 536 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart(); 537 } while (!L.isValid()); 538 } 539 540 return L; 541 } 542 543 static PathDiagnosticLocation 544 getLocationForCaller(const StackFrameContext *SFC, 545 const LocationContext *CallerCtx, 546 const SourceManager &SM) { 547 const CFGBlock &Block = *SFC->getCallSiteBlock(); 548 CFGElement Source = Block[SFC->getIndex()]; 549 550 switch (Source.getKind()) { 551 case CFGElement::Statement: 552 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), 553 SM, CallerCtx); 554 case CFGElement::Initializer: { 555 const CFGInitializer &Init = Source.castAs<CFGInitializer>(); 556 return PathDiagnosticLocation(Init.getInitializer()->getInit(), 557 SM, CallerCtx); 558 } 559 case CFGElement::AutomaticObjectDtor: { 560 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); 561 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 562 SM, CallerCtx); 563 } 564 case CFGElement::DeleteDtor: { 565 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); 566 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); 567 } 568 case CFGElement::BaseDtor: 569 case CFGElement::MemberDtor: { 570 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); 571 if (const Stmt *CallerBody = CallerInfo->getBody()) 572 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); 573 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); 574 } 575 case CFGElement::TemporaryDtor: 576 case CFGElement::NewAllocator: 577 llvm_unreachable("not yet implemented!"); 578 } 579 580 llvm_unreachable("Unknown CFGElement kind"); 581 } 582 583 584 PathDiagnosticLocation 585 PathDiagnosticLocation::createBegin(const Decl *D, 586 const SourceManager &SM) { 587 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 588 } 589 590 PathDiagnosticLocation 591 PathDiagnosticLocation::createBegin(const Stmt *S, 592 const SourceManager &SM, 593 LocationOrAnalysisDeclContext LAC) { 594 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 595 SM, SingleLocK); 596 } 597 598 599 PathDiagnosticLocation 600 PathDiagnosticLocation::createEnd(const Stmt *S, 601 const SourceManager &SM, 602 LocationOrAnalysisDeclContext LAC) { 603 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) 604 return createEndBrace(CS, SM); 605 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 606 SM, SingleLocK); 607 } 608 609 PathDiagnosticLocation 610 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 611 const SourceManager &SM) { 612 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 613 } 614 615 PathDiagnosticLocation 616 PathDiagnosticLocation::createConditionalColonLoc( 617 const ConditionalOperator *CO, 618 const SourceManager &SM) { 619 return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); 620 } 621 622 623 PathDiagnosticLocation 624 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 625 const SourceManager &SM) { 626 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 627 } 628 629 PathDiagnosticLocation 630 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 631 const SourceManager &SM) { 632 SourceLocation L = CS->getLBracLoc(); 633 return PathDiagnosticLocation(L, SM, SingleLocK); 634 } 635 636 PathDiagnosticLocation 637 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 638 const SourceManager &SM) { 639 SourceLocation L = CS->getRBracLoc(); 640 return PathDiagnosticLocation(L, SM, SingleLocK); 641 } 642 643 PathDiagnosticLocation 644 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 645 const SourceManager &SM) { 646 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 647 if (const CompoundStmt *CS = 648 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 649 if (!CS->body_empty()) { 650 SourceLocation Loc = (*CS->body_begin())->getLocStart(); 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 668 const Stmt* S = nullptr; 669 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { 670 const CFGBlock *BSrc = BE->getSrc(); 671 S = BSrc->getTerminatorCondition(); 672 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { 673 S = SP->getStmt(); 674 if (P.getAs<PostStmtPurgeDeadSymbols>()) 675 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); 676 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { 677 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), 678 SMng); 679 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { 680 return PathDiagnosticLocation(PIE->getLocation(), SMng); 681 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { 682 return getLocationForCaller(CE->getCalleeContext(), 683 CE->getLocationContext(), 684 SMng); 685 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { 686 return getLocationForCaller(CEE->getCalleeContext(), 687 CEE->getLocationContext(), 688 SMng); 689 } else { 690 llvm_unreachable("Unexpected ProgramPoint"); 691 } 692 693 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 694 } 695 696 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { 697 ProgramPoint P = N->getLocation(); 698 if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) 699 return SP->getStmt(); 700 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) 701 return BE->getSrc()->getTerminator(); 702 if (Optional<CallEnter> CE = P.getAs<CallEnter>()) 703 return CE->getCallExpr(); 704 if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) 705 return CEE->getCalleeContext()->getCallSite(); 706 if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) 707 return PIPP->getInitializer()->getInit(); 708 709 return nullptr; 710 } 711 712 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { 713 for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) { 714 if (const Stmt *S = getStmt(N)) { 715 // Check if the statement is '?' or '&&'/'||'. These are "merges", 716 // not actual statement points. 717 switch (S->getStmtClass()) { 718 case Stmt::ChooseExprClass: 719 case Stmt::BinaryConditionalOperatorClass: 720 case Stmt::ConditionalOperatorClass: 721 continue; 722 case Stmt::BinaryOperatorClass: { 723 BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); 724 if (Op == BO_LAnd || Op == BO_LOr) 725 continue; 726 break; 727 } 728 default: 729 break; 730 } 731 // We found the statement, so return it. 732 return S; 733 } 734 } 735 736 return nullptr; 737 } 738 739 PathDiagnosticLocation 740 PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, 741 const SourceManager &SM) { 742 assert(N && "Cannot create a location with a null node."); 743 const Stmt *S = getStmt(N); 744 745 if (!S) { 746 // If this is an implicit call, return the implicit call point location. 747 if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>()) 748 return PathDiagnosticLocation(PIE->getLocation(), SM); 749 S = getNextStmt(N); 750 } 751 752 if (S) { 753 ProgramPoint P = N->getLocation(); 754 const LocationContext *LC = N->getLocationContext(); 755 756 // For member expressions, return the location of the '.' or '->'. 757 if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) 758 return PathDiagnosticLocation::createMemberLoc(ME, SM); 759 760 // For binary operators, return the location of the operator. 761 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) 762 return PathDiagnosticLocation::createOperatorLoc(B, SM); 763 764 if (P.getAs<PostStmtPurgeDeadSymbols>()) 765 return PathDiagnosticLocation::createEnd(S, SM, LC); 766 767 if (S->getLocStart().isValid()) 768 return PathDiagnosticLocation(S, SM, LC); 769 return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); 770 } 771 772 return createDeclEnd(N->getLocationContext(), SM); 773 } 774 775 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 776 const PathDiagnosticLocation &PDL) { 777 FullSourceLoc L = PDL.asLocation(); 778 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 779 } 780 781 FullSourceLoc 782 PathDiagnosticLocation::genLocation(SourceLocation L, 783 LocationOrAnalysisDeclContext LAC) const { 784 assert(isValid()); 785 // Note that we want a 'switch' here so that the compiler can warn us in 786 // case we add more cases. 787 switch (K) { 788 case SingleLocK: 789 case RangeK: 790 break; 791 case StmtK: 792 // Defensive checking. 793 if (!S) 794 break; 795 return FullSourceLoc(getValidSourceLocation(S, LAC), 796 const_cast<SourceManager&>(*SM)); 797 case DeclK: 798 // Defensive checking. 799 if (!D) 800 break; 801 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 802 } 803 804 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 805 } 806 807 PathDiagnosticRange 808 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 809 assert(isValid()); 810 // Note that we want a 'switch' here so that the compiler can warn us in 811 // case we add more cases. 812 switch (K) { 813 case SingleLocK: 814 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 815 case RangeK: 816 break; 817 case StmtK: { 818 const Stmt *S = asStmt(); 819 switch (S->getStmtClass()) { 820 default: 821 break; 822 case Stmt::DeclStmtClass: { 823 const DeclStmt *DS = cast<DeclStmt>(S); 824 if (DS->isSingleDecl()) { 825 // Should always be the case, but we'll be defensive. 826 return SourceRange(DS->getLocStart(), 827 DS->getSingleDecl()->getLocation()); 828 } 829 break; 830 } 831 // FIXME: Provide better range information for different 832 // terminators. 833 case Stmt::IfStmtClass: 834 case Stmt::WhileStmtClass: 835 case Stmt::DoStmtClass: 836 case Stmt::ForStmtClass: 837 case Stmt::ChooseExprClass: 838 case Stmt::IndirectGotoStmtClass: 839 case Stmt::SwitchStmtClass: 840 case Stmt::BinaryConditionalOperatorClass: 841 case Stmt::ConditionalOperatorClass: 842 case Stmt::ObjCForCollectionStmtClass: { 843 SourceLocation L = getValidSourceLocation(S, LAC); 844 return SourceRange(L, L); 845 } 846 } 847 SourceRange R = S->getSourceRange(); 848 if (R.isValid()) 849 return R; 850 break; 851 } 852 case DeclK: 853 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 854 return MD->getSourceRange(); 855 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 856 if (Stmt *Body = FD->getBody()) 857 return Body->getSourceRange(); 858 } 859 else { 860 SourceLocation L = D->getLocation(); 861 return PathDiagnosticRange(SourceRange(L, L), true); 862 } 863 } 864 865 return SourceRange(Loc,Loc); 866 } 867 868 void PathDiagnosticLocation::flatten() { 869 if (K == StmtK) { 870 K = RangeK; 871 S = nullptr; 872 D = nullptr; 873 } 874 else if (K == DeclK) { 875 K = SingleLocK; 876 S = nullptr; 877 D = nullptr; 878 } 879 } 880 881 //===----------------------------------------------------------------------===// 882 // Manipulation of PathDiagnosticCallPieces. 883 //===----------------------------------------------------------------------===// 884 885 PathDiagnosticCallPiece * 886 PathDiagnosticCallPiece::construct(const ExplodedNode *N, 887 const CallExitEnd &CE, 888 const SourceManager &SM) { 889 const Decl *caller = CE.getLocationContext()->getDecl(); 890 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 891 CE.getLocationContext(), 892 SM); 893 return new PathDiagnosticCallPiece(caller, pos); 894 } 895 896 PathDiagnosticCallPiece * 897 PathDiagnosticCallPiece::construct(PathPieces &path, 898 const Decl *caller) { 899 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller); 900 path.clear(); 901 path.push_front(C); 902 return C; 903 } 904 905 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 906 const SourceManager &SM) { 907 const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 908 Callee = CalleeCtx->getDecl(); 909 910 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 911 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 912 } 913 914 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, 915 StringRef Prefix = StringRef()) { 916 if (!D->getIdentifier()) 917 return; 918 Out << Prefix << '\'' << *D << '\''; 919 } 920 921 static bool describeCodeDecl(raw_ostream &Out, const Decl *D, 922 bool ExtendedDescription, 923 StringRef Prefix = StringRef()) { 924 if (!D) 925 return false; 926 927 if (isa<BlockDecl>(D)) { 928 if (ExtendedDescription) 929 Out << Prefix << "anonymous block"; 930 return ExtendedDescription; 931 } 932 933 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { 934 Out << Prefix; 935 if (ExtendedDescription && !MD->isUserProvided()) { 936 if (MD->isExplicitlyDefaulted()) 937 Out << "defaulted "; 938 else 939 Out << "implicit "; 940 } 941 942 if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) { 943 if (CD->isDefaultConstructor()) 944 Out << "default "; 945 else if (CD->isCopyConstructor()) 946 Out << "copy "; 947 else if (CD->isMoveConstructor()) 948 Out << "move "; 949 950 Out << "constructor"; 951 describeClass(Out, MD->getParent(), " for "); 952 953 } else if (isa<CXXDestructorDecl>(MD)) { 954 if (!MD->isUserProvided()) { 955 Out << "destructor"; 956 describeClass(Out, MD->getParent(), " for "); 957 } else { 958 // Use ~Foo for explicitly-written destructors. 959 Out << "'" << *MD << "'"; 960 } 961 962 } else if (MD->isCopyAssignmentOperator()) { 963 Out << "copy assignment operator"; 964 describeClass(Out, MD->getParent(), " for "); 965 966 } else if (MD->isMoveAssignmentOperator()) { 967 Out << "move assignment operator"; 968 describeClass(Out, MD->getParent(), " for "); 969 970 } else { 971 if (MD->getParent()->getIdentifier()) 972 Out << "'" << *MD->getParent() << "::" << *MD << "'"; 973 else 974 Out << "'" << *MD << "'"; 975 } 976 977 return true; 978 } 979 980 Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\''; 981 return true; 982 } 983 984 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 985 PathDiagnosticCallPiece::getCallEnterEvent() const { 986 if (!Callee) 987 return nullptr; 988 989 SmallString<256> buf; 990 llvm::raw_svector_ostream Out(buf); 991 992 Out << "Calling "; 993 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); 994 995 assert(callEnter.asLocation().isValid()); 996 return new PathDiagnosticEventPiece(callEnter, Out.str()); 997 } 998 999 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 1000 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 1001 if (!callEnterWithin.asLocation().isValid()) 1002 return nullptr; 1003 if (Callee->isImplicit() || !Callee->hasBody()) 1004 return nullptr; 1005 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) 1006 if (MD->isDefaulted()) 1007 return nullptr; 1008 1009 SmallString<256> buf; 1010 llvm::raw_svector_ostream Out(buf); 1011 1012 Out << "Entered call"; 1013 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); 1014 1015 return new PathDiagnosticEventPiece(callEnterWithin, Out.str()); 1016 } 1017 1018 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 1019 PathDiagnosticCallPiece::getCallExitEvent() const { 1020 if (NoExit) 1021 return nullptr; 1022 1023 SmallString<256> buf; 1024 llvm::raw_svector_ostream Out(buf); 1025 1026 if (!CallStackMessage.empty()) { 1027 Out << CallStackMessage; 1028 } else { 1029 bool DidDescribe = describeCodeDecl(Out, Callee, 1030 /*ExtendedDescription=*/false, 1031 "Returning from "); 1032 if (!DidDescribe) 1033 Out << "Returning to caller"; 1034 } 1035 1036 assert(callReturn.asLocation().isValid()); 1037 return new PathDiagnosticEventPiece(callReturn, Out.str()); 1038 } 1039 1040 static void compute_path_size(const PathPieces &pieces, unsigned &size) { 1041 for (PathPieces::const_iterator it = pieces.begin(), 1042 et = pieces.end(); it != et; ++it) { 1043 const PathDiagnosticPiece *piece = it->get(); 1044 if (const PathDiagnosticCallPiece *cp = 1045 dyn_cast<PathDiagnosticCallPiece>(piece)) { 1046 compute_path_size(cp->path, size); 1047 } 1048 else 1049 ++size; 1050 } 1051 } 1052 1053 unsigned PathDiagnostic::full_size() { 1054 unsigned size = 0; 1055 compute_path_size(path, size); 1056 return size; 1057 } 1058 1059 //===----------------------------------------------------------------------===// 1060 // FoldingSet profiling methods. 1061 //===----------------------------------------------------------------------===// 1062 1063 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 1064 ID.AddInteger(Range.getBegin().getRawEncoding()); 1065 ID.AddInteger(Range.getEnd().getRawEncoding()); 1066 ID.AddInteger(Loc.getRawEncoding()); 1067 return; 1068 } 1069 1070 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1071 ID.AddInteger((unsigned) getKind()); 1072 ID.AddString(str); 1073 // FIXME: Add profiling support for code hints. 1074 ID.AddInteger((unsigned) getDisplayHint()); 1075 ArrayRef<SourceRange> Ranges = getRanges(); 1076 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 1077 I != E; ++I) { 1078 ID.AddInteger(I->getBegin().getRawEncoding()); 1079 ID.AddInteger(I->getEnd().getRawEncoding()); 1080 } 1081 } 1082 1083 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1084 PathDiagnosticPiece::Profile(ID); 1085 for (PathPieces::const_iterator it = path.begin(), 1086 et = path.end(); it != et; ++it) { 1087 ID.Add(**it); 1088 } 1089 } 1090 1091 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1092 PathDiagnosticPiece::Profile(ID); 1093 ID.Add(Pos); 1094 } 1095 1096 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1097 PathDiagnosticPiece::Profile(ID); 1098 for (const_iterator I = begin(), E = end(); I != E; ++I) 1099 ID.Add(*I); 1100 } 1101 1102 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1103 PathDiagnosticSpotPiece::Profile(ID); 1104 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 1105 I != E; ++I) 1106 ID.Add(**I); 1107 } 1108 1109 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 1110 ID.Add(getLocation()); 1111 ID.AddString(BugType); 1112 ID.AddString(VerboseDesc); 1113 ID.AddString(Category); 1114 } 1115 1116 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 1117 Profile(ID); 1118 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) 1119 ID.Add(**I); 1120 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 1121 ID.AddString(*I); 1122 } 1123 1124 StackHintGenerator::~StackHintGenerator() {} 1125 1126 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ 1127 ProgramPoint P = N->getLocation(); 1128 CallExitEnd CExit = P.castAs<CallExitEnd>(); 1129 1130 // FIXME: Use CallEvent to abstract this over all calls. 1131 const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); 1132 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); 1133 if (!CE) 1134 return ""; 1135 1136 if (!N) 1137 return getMessageForSymbolNotFound(); 1138 1139 // Check if one of the parameters are set to the interesting symbol. 1140 ProgramStateRef State = N->getState(); 1141 const LocationContext *LCtx = N->getLocationContext(); 1142 unsigned ArgIndex = 0; 1143 for (CallExpr::const_arg_iterator I = CE->arg_begin(), 1144 E = CE->arg_end(); I != E; ++I, ++ArgIndex){ 1145 SVal SV = State->getSVal(*I, LCtx); 1146 1147 // Check if the variable corresponding to the symbol is passed by value. 1148 SymbolRef AS = SV.getAsLocSymbol(); 1149 if (AS == Sym) { 1150 return getMessageForArg(*I, ArgIndex); 1151 } 1152 1153 // Check if the parameter is a pointer to the symbol. 1154 if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { 1155 SVal PSV = State->getSVal(Reg->getRegion()); 1156 SymbolRef AS = PSV.getAsLocSymbol(); 1157 if (AS == Sym) { 1158 return getMessageForArg(*I, ArgIndex); 1159 } 1160 } 1161 } 1162 1163 // Check if we are returning the interesting symbol. 1164 SVal SV = State->getSVal(CE, LCtx); 1165 SymbolRef RetSym = SV.getAsLocSymbol(); 1166 if (RetSym == Sym) { 1167 return getMessageForReturn(CE); 1168 } 1169 1170 return getMessageForSymbolNotFound(); 1171 } 1172 1173 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, 1174 unsigned ArgIndex) { 1175 // Printed parameters start at 1, not 0. 1176 ++ArgIndex; 1177 1178 SmallString<200> buf; 1179 llvm::raw_svector_ostream os(buf); 1180 1181 os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) 1182 << " parameter"; 1183 1184 return os.str(); 1185 } 1186