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