PathDiagnostic.cpp revision 183ba8e19d49ab1ae25d3cdd0a19591369c5ab9f
103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===// 203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// 303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// The LLVM Compiler Infrastructure 403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// 503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source 603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// License. See LICENSE.TXT for details. 703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// 803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//===----------------------------------------------------------------------===// 903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// 1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// This file defines the PathDiagnostic-related interfaces. 1103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// 1203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//===----------------------------------------------------------------------===// 1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 1403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/Basic/SourceManager.h" 1703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/Expr.h" 1803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/Decl.h" 1903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/DeclCXX.h" 2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/DeclObjC.h" 2103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/ParentMap.h" 2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/StmtCXX.h" 2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "llvm/ADT/SmallString.h" 2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using namespace clang; 2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using namespace ento; 2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool PathDiagnosticMacroPiece::containsEvent() const { 2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) I!=E; ++I) { 3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (isa<PathDiagnosticEventPiece>(*I)) 3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return true; 3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 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 ParentMap *PM = 0; 257 if (LAC.is<const LocationContext*>()) 258 PM = &LAC.get<const LocationContext*>()->getParentMap(); 259 else 260 PM = &LAC.get<AnalysisDeclContext*>()->getParentMap(); 261 262 while (!L.isValid()) { 263 S = PM->getParent(S); 264 L = UseEnd ? S->getLocEnd() : S->getLocStart(); 265 } 266 } 267 268 return L; 269} 270 271PathDiagnosticLocation 272 PathDiagnosticLocation::createBegin(const Decl *D, 273 const SourceManager &SM) { 274 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 275} 276 277PathDiagnosticLocation 278 PathDiagnosticLocation::createBegin(const Stmt *S, 279 const SourceManager &SM, 280 LocationOrAnalysisDeclContext LAC) { 281 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 282 SM, SingleLocK); 283} 284 285 286PathDiagnosticLocation 287PathDiagnosticLocation::createEnd(const Stmt *S, 288 const SourceManager &SM, 289 LocationOrAnalysisDeclContext LAC) { 290 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) 291 return createEndBrace(CS, SM); 292 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 293 SM, SingleLocK); 294} 295 296PathDiagnosticLocation 297 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 298 const SourceManager &SM) { 299 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 300} 301 302PathDiagnosticLocation 303 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 304 const SourceManager &SM) { 305 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 306} 307 308PathDiagnosticLocation 309 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 310 const SourceManager &SM) { 311 SourceLocation L = CS->getLBracLoc(); 312 return PathDiagnosticLocation(L, SM, SingleLocK); 313} 314 315PathDiagnosticLocation 316 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 317 const SourceManager &SM) { 318 SourceLocation L = CS->getRBracLoc(); 319 return PathDiagnosticLocation(L, SM, SingleLocK); 320} 321 322PathDiagnosticLocation 323 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 324 const SourceManager &SM) { 325 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 326 if (const CompoundStmt *CS = 327 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 328 if (!CS->body_empty()) { 329 SourceLocation Loc = (*CS->body_begin())->getLocStart(); 330 return PathDiagnosticLocation(Loc, SM, SingleLocK); 331 } 332 333 return PathDiagnosticLocation(); 334} 335 336PathDiagnosticLocation 337 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 338 const SourceManager &SM) { 339 SourceLocation L = LC->getDecl()->getBodyRBrace(); 340 return PathDiagnosticLocation(L, SM, SingleLocK); 341} 342 343PathDiagnosticLocation 344 PathDiagnosticLocation::create(const ProgramPoint& P, 345 const SourceManager &SMng) { 346 347 const Stmt* S = 0; 348 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 349 const CFGBlock *BSrc = BE->getSrc(); 350 S = BSrc->getTerminatorCondition(); 351 } 352 else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { 353 S = PS->getStmt(); 354 } 355 356 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 357} 358 359PathDiagnosticLocation 360 PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N, 361 const SourceManager &SM) { 362 assert(N && "Cannot create a location with a null node."); 363 364 const ExplodedNode *NI = N; 365 366 while (NI) { 367 ProgramPoint P = NI->getLocation(); 368 const LocationContext *LC = P.getLocationContext(); 369 if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) 370 return PathDiagnosticLocation(PS->getStmt(), SM, LC); 371 else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 372 const Stmt *Term = BE->getSrc()->getTerminator(); 373 if (Term) { 374 return PathDiagnosticLocation(Term, SM, LC); 375 } 376 } 377 NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); 378 } 379 380 return createDeclEnd(N->getLocationContext(), SM); 381} 382 383PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 384 const PathDiagnosticLocation &PDL) { 385 FullSourceLoc L = PDL.asLocation(); 386 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 387} 388 389FullSourceLoc 390 PathDiagnosticLocation::genLocation(SourceLocation L, 391 LocationOrAnalysisDeclContext LAC) const { 392 assert(isValid()); 393 // Note that we want a 'switch' here so that the compiler can warn us in 394 // case we add more cases. 395 switch (K) { 396 case SingleLocK: 397 case RangeK: 398 break; 399 case StmtK: 400 // Defensive checking. 401 if (!S) 402 break; 403 return FullSourceLoc(getValidSourceLocation(S, LAC), 404 const_cast<SourceManager&>(*SM)); 405 case DeclK: 406 // Defensive checking. 407 if (!D) 408 break; 409 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 410 } 411 412 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 413} 414 415PathDiagnosticRange 416 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 417 assert(isValid()); 418 // Note that we want a 'switch' here so that the compiler can warn us in 419 // case we add more cases. 420 switch (K) { 421 case SingleLocK: 422 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 423 case RangeK: 424 break; 425 case StmtK: { 426 const Stmt *S = asStmt(); 427 switch (S->getStmtClass()) { 428 default: 429 break; 430 case Stmt::DeclStmtClass: { 431 const DeclStmt *DS = cast<DeclStmt>(S); 432 if (DS->isSingleDecl()) { 433 // Should always be the case, but we'll be defensive. 434 return SourceRange(DS->getLocStart(), 435 DS->getSingleDecl()->getLocation()); 436 } 437 break; 438 } 439 // FIXME: Provide better range information for different 440 // terminators. 441 case Stmt::IfStmtClass: 442 case Stmt::WhileStmtClass: 443 case Stmt::DoStmtClass: 444 case Stmt::ForStmtClass: 445 case Stmt::ChooseExprClass: 446 case Stmt::IndirectGotoStmtClass: 447 case Stmt::SwitchStmtClass: 448 case Stmt::BinaryConditionalOperatorClass: 449 case Stmt::ConditionalOperatorClass: 450 case Stmt::ObjCForCollectionStmtClass: { 451 SourceLocation L = getValidSourceLocation(S, LAC); 452 return SourceRange(L, L); 453 } 454 } 455 SourceRange R = S->getSourceRange(); 456 if (R.isValid()) 457 return R; 458 break; 459 } 460 case DeclK: 461 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 462 return MD->getSourceRange(); 463 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 464 if (Stmt *Body = FD->getBody()) 465 return Body->getSourceRange(); 466 } 467 else { 468 SourceLocation L = D->getLocation(); 469 return PathDiagnosticRange(SourceRange(L, L), true); 470 } 471 } 472 473 return SourceRange(Loc,Loc); 474} 475 476void PathDiagnosticLocation::flatten() { 477 if (K == StmtK) { 478 K = RangeK; 479 S = 0; 480 D = 0; 481 } 482 else if (K == DeclK) { 483 K = SingleLocK; 484 S = 0; 485 D = 0; 486 } 487} 488 489PathDiagnosticLocation PathDiagnostic::getLocation() const { 490 assert(path.size() > 0 && 491 "getLocation() requires a non-empty PathDiagnostic."); 492 493 PathDiagnosticPiece *p = path.rbegin()->getPtr(); 494 495 while (true) { 496 if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) { 497 assert(!cp->path.empty()); 498 p = cp->path.rbegin()->getPtr(); 499 continue; 500 } 501 break; 502 } 503 504 return p->getLocation(); 505} 506 507//===----------------------------------------------------------------------===// 508// Manipulation of PathDiagnosticCallPieces. 509//===----------------------------------------------------------------------===// 510 511static PathDiagnosticLocation 512getLocationForCaller(const StackFrameContext *SFC, 513 const LocationContext *CallerCtx, 514 const SourceManager &SM) { 515 const CFGBlock &Block = *SFC->getCallSiteBlock(); 516 CFGElement Source = Block[SFC->getIndex()]; 517 518 switch (Source.getKind()) { 519 case CFGElement::Invalid: 520 llvm_unreachable("Invalid CFGElement"); 521 case CFGElement::Statement: 522 return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(), 523 SM, CallerCtx); 524 case CFGElement::Initializer: { 525 const CFGInitializer &Init = cast<CFGInitializer>(Source); 526 return PathDiagnosticLocation(Init.getInitializer()->getInit(), 527 SM, CallerCtx); 528 } 529 case CFGElement::AutomaticObjectDtor: { 530 const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source); 531 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 532 SM, CallerCtx); 533 } 534 case CFGElement::BaseDtor: 535 case CFGElement::MemberDtor: 536 case CFGElement::TemporaryDtor: 537 llvm_unreachable("not yet implemented!"); 538 } 539 540 llvm_unreachable("Unknown CFGElement kind"); 541} 542 543PathDiagnosticCallPiece * 544PathDiagnosticCallPiece::construct(const ExplodedNode *N, 545 const CallExitEnd &CE, 546 const SourceManager &SM) { 547 const Decl *caller = CE.getLocationContext()->getDecl(); 548 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 549 CE.getLocationContext(), 550 SM); 551 return new PathDiagnosticCallPiece(caller, pos); 552} 553 554PathDiagnosticCallPiece * 555PathDiagnosticCallPiece::construct(PathPieces &path, 556 const Decl *caller) { 557 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller); 558 path.clear(); 559 path.push_front(C); 560 return C; 561} 562 563void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 564 const SourceManager &SM) { 565 const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 566 Callee = CalleeCtx->getDecl(); 567 568 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 569 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 570} 571 572IntrusiveRefCntPtr<PathDiagnosticEventPiece> 573PathDiagnosticCallPiece::getCallEnterEvent() const { 574 if (!Callee) 575 return 0; 576 SmallString<256> buf; 577 llvm::raw_svector_ostream Out(buf); 578 if (isa<BlockDecl>(Callee)) 579 Out << "Calling anonymous block"; 580 else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee)) 581 Out << "Calling '" << *ND << "'"; 582 StringRef msg = Out.str(); 583 if (msg.empty()) 584 return 0; 585 return new PathDiagnosticEventPiece(callEnter, msg); 586} 587 588IntrusiveRefCntPtr<PathDiagnosticEventPiece> 589PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 590 SmallString<256> buf; 591 llvm::raw_svector_ostream Out(buf); 592 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller)) 593 Out << "Entered call from '" << *ND << "'"; 594 else 595 Out << "Entered call"; 596 StringRef msg = Out.str(); 597 if (msg.empty()) 598 return 0; 599 return new PathDiagnosticEventPiece(callEnterWithin, msg); 600} 601 602IntrusiveRefCntPtr<PathDiagnosticEventPiece> 603PathDiagnosticCallPiece::getCallExitEvent() const { 604 if (NoExit) 605 return 0; 606 SmallString<256> buf; 607 llvm::raw_svector_ostream Out(buf); 608 if (!CallStackMessage.empty()) 609 Out << CallStackMessage; 610 else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee)) 611 Out << "Returning from '" << *ND << "'"; 612 else 613 Out << "Returning to caller"; 614 return new PathDiagnosticEventPiece(callReturn, Out.str()); 615} 616 617static void compute_path_size(const PathPieces &pieces, unsigned &size) { 618 for (PathPieces::const_iterator it = pieces.begin(), 619 et = pieces.end(); it != et; ++it) { 620 const PathDiagnosticPiece *piece = it->getPtr(); 621 if (const PathDiagnosticCallPiece *cp = 622 dyn_cast<PathDiagnosticCallPiece>(piece)) { 623 compute_path_size(cp->path, size); 624 } 625 else 626 ++size; 627 } 628} 629 630unsigned PathDiagnostic::full_size() { 631 unsigned size = 0; 632 compute_path_size(path, size); 633 return size; 634} 635 636//===----------------------------------------------------------------------===// 637// FoldingSet profiling methods. 638//===----------------------------------------------------------------------===// 639 640void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 641 ID.AddInteger(Range.getBegin().getRawEncoding()); 642 ID.AddInteger(Range.getEnd().getRawEncoding()); 643 ID.AddInteger(Loc.getRawEncoding()); 644 return; 645} 646 647void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 648 ID.AddInteger((unsigned) getKind()); 649 ID.AddString(str); 650 // FIXME: Add profiling support for code hints. 651 ID.AddInteger((unsigned) getDisplayHint()); 652 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) { 653 ID.AddInteger(I->getBegin().getRawEncoding()); 654 ID.AddInteger(I->getEnd().getRawEncoding()); 655 } 656} 657 658void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 659 PathDiagnosticPiece::Profile(ID); 660 for (PathPieces::const_iterator it = path.begin(), 661 et = path.end(); it != et; ++it) { 662 ID.Add(**it); 663 } 664} 665 666void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 667 PathDiagnosticPiece::Profile(ID); 668 ID.Add(Pos); 669} 670 671void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 672 PathDiagnosticPiece::Profile(ID); 673 for (const_iterator I = begin(), E = end(); I != E; ++I) 674 ID.Add(*I); 675} 676 677void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 678 PathDiagnosticSpotPiece::Profile(ID); 679 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 680 I != E; ++I) 681 ID.Add(**I); 682} 683 684void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 685 if (!path.empty()) 686 getLocation().Profile(ID); 687 ID.AddString(BugType); 688 ID.AddString(Desc); 689 ID.AddString(Category); 690} 691 692void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 693 Profile(ID); 694 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) 695 ID.Add(**I); 696 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 697 ID.AddString(*I); 698} 699 700StackHintGenerator::~StackHintGenerator() {} 701 702std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ 703 ProgramPoint P = N->getLocation(); 704 const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P); 705 assert(CExit && "Stack Hints should be constructed at CallExitEnd points."); 706 707 // FIXME: Use CallEvent to abstract this over all calls. 708 const Stmt *CallSite = CExit->getCalleeContext()->getCallSite(); 709 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); 710 if (!CE) 711 return ""; 712 713 if (!N) 714 return getMessageForSymbolNotFound(); 715 716 // Check if one of the parameters are set to the interesting symbol. 717 ProgramStateRef State = N->getState(); 718 const LocationContext *LCtx = N->getLocationContext(); 719 unsigned ArgIndex = 0; 720 for (CallExpr::const_arg_iterator I = CE->arg_begin(), 721 E = CE->arg_end(); I != E; ++I, ++ArgIndex){ 722 SVal SV = State->getSVal(*I, LCtx); 723 724 // Check if the variable corresponding to the symbol is passed by value. 725 SymbolRef AS = SV.getAsLocSymbol(); 726 if (AS == Sym) { 727 return getMessageForArg(*I, ArgIndex); 728 } 729 730 // Check if the parameter is a pointer to the symbol. 731 if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) { 732 SVal PSV = State->getSVal(Reg->getRegion()); 733 SymbolRef AS = PSV.getAsLocSymbol(); 734 if (AS == Sym) { 735 return getMessageForArg(*I, ArgIndex); 736 } 737 } 738 } 739 740 // Check if we are returning the interesting symbol. 741 SVal SV = State->getSVal(CE, LCtx); 742 SymbolRef RetSym = SV.getAsLocSymbol(); 743 if (RetSym == Sym) { 744 return getMessageForReturn(CE); 745 } 746 747 return getMessageForSymbolNotFound(); 748} 749 750/// TODO: This is copied from clang diagnostics. Maybe we could just move it to 751/// some common place. (Same as HandleOrdinalModifier.) 752void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo, 753 llvm::raw_svector_ostream &Out) { 754 assert(ValNo != 0 && "ValNo must be strictly positive!"); 755 756 // We could use text forms for the first N ordinals, but the numeric 757 // forms are actually nicer in diagnostics because they stand out. 758 Out << ValNo; 759 760 // It is critically important that we do this perfectly for 761 // user-written sequences with over 100 elements. 762 switch (ValNo % 100) { 763 case 11: 764 case 12: 765 case 13: 766 Out << "th"; return; 767 default: 768 switch (ValNo % 10) { 769 case 1: Out << "st"; return; 770 case 2: Out << "nd"; return; 771 case 3: Out << "rd"; return; 772 default: Out << "th"; return; 773 } 774 } 775} 776 777std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, 778 unsigned ArgIndex) { 779 SmallString<200> buf; 780 llvm::raw_svector_ostream os(buf); 781 782 os << Msg << " via "; 783 // Printed parameters start at 1, not 0. 784 printOrdinal(++ArgIndex, os); 785 os << " parameter"; 786 787 return os.str(); 788} 789