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