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