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