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