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