clang API Documentation
00001 //===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines the PathDiagnostic-related interfaces. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 00015 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 00016 #include "clang/Basic/SourceManager.h" 00017 #include "clang/AST/Expr.h" 00018 #include "clang/AST/Decl.h" 00019 #include "clang/AST/DeclObjC.h" 00020 #include "clang/AST/ParentMap.h" 00021 #include "clang/AST/StmtCXX.h" 00022 #include "llvm/ADT/SmallString.h" 00023 00024 using namespace clang; 00025 using namespace ento; 00026 00027 bool PathDiagnosticMacroPiece::containsEvent() const { 00028 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 00029 I!=E; ++I) { 00030 if (isa<PathDiagnosticEventPiece>(*I)) 00031 return true; 00032 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I)) 00033 if (MP->containsEvent()) 00034 return true; 00035 } 00036 return false; 00037 } 00038 00039 static StringRef StripTrailingDots(StringRef s) { 00040 for (StringRef::size_type i = s.size(); i != 0; --i) 00041 if (s[i - 1] != '.') 00042 return s.substr(0, i); 00043 return ""; 00044 } 00045 00046 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 00047 Kind k, DisplayHint hint) 00048 : str(StripTrailingDots(s)), kind(k), Hint(hint) {} 00049 00050 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 00051 : kind(k), Hint(hint) {} 00052 00053 PathDiagnosticPiece::~PathDiagnosticPiece() {} 00054 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 00055 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} 00056 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 00057 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} 00058 00059 00060 PathPieces::~PathPieces() {} 00061 PathDiagnostic::~PathDiagnostic() {} 00062 00063 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue, 00064 StringRef bugtype, StringRef desc, 00065 StringRef category) 00066 : DeclWithIssue(declWithIssue), 00067 BugType(StripTrailingDots(bugtype)), 00068 Desc(StripTrailingDots(desc)), 00069 Category(StripTrailingDots(category)), 00070 path(pathImpl) {} 00071 00072 void PathDiagnosticConsumer::anchor() { } 00073 00074 PathDiagnosticConsumer::~PathDiagnosticConsumer() { 00075 // Delete the contents of the FoldingSet if it isn't empty already. 00076 for (llvm::FoldingSet<PathDiagnostic>::iterator it = 00077 Diags.begin(), et = Diags.end() ; it != et ; ++it) { 00078 delete &*it; 00079 } 00080 } 00081 00082 void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { 00083 llvm::OwningPtr<PathDiagnostic> OwningD(D); 00084 00085 if (!D || D->path.empty()) 00086 return; 00087 00088 // We need to flatten the locations (convert Stmt* to locations) because 00089 // the referenced statements may be freed by the time the diagnostics 00090 // are emitted. 00091 D->flattenLocations(); 00092 00093 // If the PathDiagnosticConsumer does not support diagnostics that 00094 // cross file boundaries, prune out such diagnostics now. 00095 if (!supportsCrossFileDiagnostics()) { 00096 // Verify that the entire path is from the same FileID. 00097 FileID FID; 00098 const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager(); 00099 llvm::SmallVector<const PathPieces *, 5> WorkList; 00100 WorkList.push_back(&D->path); 00101 00102 while (!WorkList.empty()) { 00103 const PathPieces &path = *WorkList.back(); 00104 WorkList.pop_back(); 00105 00106 for (PathPieces::const_iterator I = path.begin(), E = path.end(); 00107 I != E; ++I) { 00108 const PathDiagnosticPiece *piece = I->getPtr(); 00109 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 00110 00111 if (FID.isInvalid()) { 00112 FID = SMgr.getFileID(L); 00113 } else if (SMgr.getFileID(L) != FID) 00114 return; // FIXME: Emit a warning? 00115 00116 // Check the source ranges. 00117 for (PathDiagnosticPiece::range_iterator RI = piece->ranges_begin(), 00118 RE = piece->ranges_end(); 00119 RI != RE; ++RI) { 00120 SourceLocation L = SMgr.getExpansionLoc(RI->getBegin()); 00121 if (!L.isFileID() || SMgr.getFileID(L) != FID) 00122 return; // FIXME: Emit a warning? 00123 L = SMgr.getExpansionLoc(RI->getEnd()); 00124 if (!L.isFileID() || SMgr.getFileID(L) != FID) 00125 return; // FIXME: Emit a warning? 00126 } 00127 00128 if (const PathDiagnosticCallPiece *call = 00129 dyn_cast<PathDiagnosticCallPiece>(piece)) { 00130 WorkList.push_back(&call->path); 00131 } 00132 else if (const PathDiagnosticMacroPiece *macro = 00133 dyn_cast<PathDiagnosticMacroPiece>(piece)) { 00134 WorkList.push_back(¯o->subPieces); 00135 } 00136 } 00137 } 00138 00139 if (FID.isInvalid()) 00140 return; // FIXME: Emit a warning? 00141 } 00142 00143 // Profile the node to see if we already have something matching it 00144 llvm::FoldingSetNodeID profile; 00145 D->Profile(profile); 00146 void *InsertPos = 0; 00147 00148 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 00149 // Keep the PathDiagnostic with the shorter path. 00150 const unsigned orig_size = orig->full_size(); 00151 const unsigned new_size = D->full_size(); 00152 00153 if (orig_size <= new_size) { 00154 bool shouldKeepOriginal = true; 00155 if (orig_size == new_size) { 00156 // Here we break ties in a fairly arbitrary, but deterministic, way. 00157 llvm::FoldingSetNodeID fullProfile, fullProfileOrig; 00158 D->FullProfile(fullProfile); 00159 orig->FullProfile(fullProfileOrig); 00160 if (fullProfile.ComputeHash() < fullProfileOrig.ComputeHash()) 00161 shouldKeepOriginal = false; 00162 } 00163 00164 if (shouldKeepOriginal) 00165 return; 00166 } 00167 Diags.RemoveNode(orig); 00168 delete orig; 00169 } 00170 00171 Diags.InsertNode(OwningD.take()); 00172 } 00173 00174 00175 namespace { 00176 struct CompareDiagnostics { 00177 // Compare if 'X' is "<" than 'Y'. 00178 bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { 00179 // First compare by location 00180 const FullSourceLoc &XLoc = X->getLocation().asLocation(); 00181 const FullSourceLoc &YLoc = Y->getLocation().asLocation(); 00182 if (XLoc < YLoc) 00183 return true; 00184 if (XLoc != YLoc) 00185 return false; 00186 00187 // Next, compare by bug type. 00188 StringRef XBugType = X->getBugType(); 00189 StringRef YBugType = Y->getBugType(); 00190 if (XBugType < YBugType) 00191 return true; 00192 if (XBugType != YBugType) 00193 return false; 00194 00195 // Next, compare by bug description. 00196 StringRef XDesc = X->getDescription(); 00197 StringRef YDesc = Y->getDescription(); 00198 if (XDesc < YDesc) 00199 return true; 00200 if (XDesc != YDesc) 00201 return false; 00202 00203 // FIXME: Further refine by comparing PathDiagnosticPieces? 00204 return false; 00205 } 00206 }; 00207 } 00208 00209 void 00210 PathDiagnosticConsumer::FlushDiagnostics(SmallVectorImpl<std::string> *Files) { 00211 if (flushed) 00212 return; 00213 00214 flushed = true; 00215 00216 std::vector<const PathDiagnostic *> BatchDiags; 00217 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), 00218 et = Diags.end(); it != et; ++it) { 00219 BatchDiags.push_back(&*it); 00220 } 00221 00222 // Clear out the FoldingSet. 00223 Diags.clear(); 00224 00225 // Sort the diagnostics so that they are always emitted in a deterministic 00226 // order. 00227 if (!BatchDiags.empty()) 00228 std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics()); 00229 00230 FlushDiagnosticsImpl(BatchDiags, Files); 00231 00232 // Delete the flushed diagnostics. 00233 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), 00234 et = BatchDiags.end(); it != et; ++it) { 00235 const PathDiagnostic *D = *it; 00236 delete D; 00237 } 00238 } 00239 00240 //===----------------------------------------------------------------------===// 00241 // PathDiagnosticLocation methods. 00242 //===----------------------------------------------------------------------===// 00243 00244 static SourceLocation getValidSourceLocation(const Stmt* S, 00245 LocationOrAnalysisDeclContext LAC) { 00246 SourceLocation L = S->getLocStart(); 00247 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " 00248 "be passed to PathDiagnosticLocation upon creation."); 00249 00250 // S might be a temporary statement that does not have a location in the 00251 // source code, so find an enclosing statement and use it's location. 00252 if (!L.isValid()) { 00253 00254 ParentMap *PM = 0; 00255 if (LAC.is<const LocationContext*>()) 00256 PM = &LAC.get<const LocationContext*>()->getParentMap(); 00257 else 00258 PM = &LAC.get<AnalysisDeclContext*>()->getParentMap(); 00259 00260 while (!L.isValid()) { 00261 S = PM->getParent(S); 00262 L = S->getLocStart(); 00263 } 00264 } 00265 00266 return L; 00267 } 00268 00269 PathDiagnosticLocation 00270 PathDiagnosticLocation::createBegin(const Decl *D, 00271 const SourceManager &SM) { 00272 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 00273 } 00274 00275 PathDiagnosticLocation 00276 PathDiagnosticLocation::createBegin(const Stmt *S, 00277 const SourceManager &SM, 00278 LocationOrAnalysisDeclContext LAC) { 00279 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 00280 SM, SingleLocK); 00281 } 00282 00283 PathDiagnosticLocation 00284 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 00285 const SourceManager &SM) { 00286 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 00287 } 00288 00289 PathDiagnosticLocation 00290 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 00291 const SourceManager &SM) { 00292 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 00293 } 00294 00295 PathDiagnosticLocation 00296 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 00297 const SourceManager &SM) { 00298 SourceLocation L = CS->getLBracLoc(); 00299 return PathDiagnosticLocation(L, SM, SingleLocK); 00300 } 00301 00302 PathDiagnosticLocation 00303 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 00304 const SourceManager &SM) { 00305 SourceLocation L = CS->getRBracLoc(); 00306 return PathDiagnosticLocation(L, SM, SingleLocK); 00307 } 00308 00309 PathDiagnosticLocation 00310 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 00311 const SourceManager &SM) { 00312 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 00313 if (const CompoundStmt *CS = 00314 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 00315 if (!CS->body_empty()) { 00316 SourceLocation Loc = (*CS->body_begin())->getLocStart(); 00317 return PathDiagnosticLocation(Loc, SM, SingleLocK); 00318 } 00319 00320 return PathDiagnosticLocation(); 00321 } 00322 00323 PathDiagnosticLocation 00324 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 00325 const SourceManager &SM) { 00326 SourceLocation L = LC->getDecl()->getBodyRBrace(); 00327 return PathDiagnosticLocation(L, SM, SingleLocK); 00328 } 00329 00330 PathDiagnosticLocation 00331 PathDiagnosticLocation::create(const ProgramPoint& P, 00332 const SourceManager &SMng) { 00333 00334 const Stmt* S = 0; 00335 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 00336 const CFGBlock *BSrc = BE->getSrc(); 00337 S = BSrc->getTerminatorCondition(); 00338 } 00339 else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { 00340 S = PS->getStmt(); 00341 } 00342 00343 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 00344 } 00345 00346 PathDiagnosticLocation 00347 PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N, 00348 const SourceManager &SM) { 00349 assert(N && "Cannot create a location with a null node."); 00350 00351 const ExplodedNode *NI = N; 00352 00353 while (NI) { 00354 ProgramPoint P = NI->getLocation(); 00355 const LocationContext *LC = P.getLocationContext(); 00356 if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) 00357 return PathDiagnosticLocation(PS->getStmt(), SM, LC); 00358 else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 00359 const Stmt *Term = BE->getSrc()->getTerminator(); 00360 if (Term) { 00361 return PathDiagnosticLocation(Term, SM, LC); 00362 } 00363 } 00364 NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); 00365 } 00366 00367 return createDeclEnd(N->getLocationContext(), SM); 00368 } 00369 00370 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 00371 const PathDiagnosticLocation &PDL) { 00372 FullSourceLoc L = PDL.asLocation(); 00373 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 00374 } 00375 00376 FullSourceLoc 00377 PathDiagnosticLocation::genLocation(SourceLocation L, 00378 LocationOrAnalysisDeclContext LAC) const { 00379 assert(isValid()); 00380 // Note that we want a 'switch' here so that the compiler can warn us in 00381 // case we add more cases. 00382 switch (K) { 00383 case SingleLocK: 00384 case RangeK: 00385 break; 00386 case StmtK: 00387 // Defensive checking. 00388 if (!S) 00389 break; 00390 return FullSourceLoc(getValidSourceLocation(S, LAC), 00391 const_cast<SourceManager&>(*SM)); 00392 case DeclK: 00393 // Defensive checking. 00394 if (!D) 00395 break; 00396 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 00397 } 00398 00399 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 00400 } 00401 00402 PathDiagnosticRange 00403 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 00404 assert(isValid()); 00405 // Note that we want a 'switch' here so that the compiler can warn us in 00406 // case we add more cases. 00407 switch (K) { 00408 case SingleLocK: 00409 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 00410 case RangeK: 00411 break; 00412 case StmtK: { 00413 const Stmt *S = asStmt(); 00414 switch (S->getStmtClass()) { 00415 default: 00416 break; 00417 case Stmt::DeclStmtClass: { 00418 const DeclStmt *DS = cast<DeclStmt>(S); 00419 if (DS->isSingleDecl()) { 00420 // Should always be the case, but we'll be defensive. 00421 return SourceRange(DS->getLocStart(), 00422 DS->getSingleDecl()->getLocation()); 00423 } 00424 break; 00425 } 00426 // FIXME: Provide better range information for different 00427 // terminators. 00428 case Stmt::IfStmtClass: 00429 case Stmt::WhileStmtClass: 00430 case Stmt::DoStmtClass: 00431 case Stmt::ForStmtClass: 00432 case Stmt::ChooseExprClass: 00433 case Stmt::IndirectGotoStmtClass: 00434 case Stmt::SwitchStmtClass: 00435 case Stmt::BinaryConditionalOperatorClass: 00436 case Stmt::ConditionalOperatorClass: 00437 case Stmt::ObjCForCollectionStmtClass: { 00438 SourceLocation L = getValidSourceLocation(S, LAC); 00439 return SourceRange(L, L); 00440 } 00441 } 00442 SourceRange R = S->getSourceRange(); 00443 if (R.isValid()) 00444 return R; 00445 break; 00446 } 00447 case DeclK: 00448 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 00449 return MD->getSourceRange(); 00450 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 00451 if (Stmt *Body = FD->getBody()) 00452 return Body->getSourceRange(); 00453 } 00454 else { 00455 SourceLocation L = D->getLocation(); 00456 return PathDiagnosticRange(SourceRange(L, L), true); 00457 } 00458 } 00459 00460 return SourceRange(Loc,Loc); 00461 } 00462 00463 void PathDiagnosticLocation::flatten() { 00464 if (K == StmtK) { 00465 K = RangeK; 00466 S = 0; 00467 D = 0; 00468 } 00469 else if (K == DeclK) { 00470 K = SingleLocK; 00471 S = 0; 00472 D = 0; 00473 } 00474 } 00475 00476 PathDiagnosticLocation PathDiagnostic::getLocation() const { 00477 assert(path.size() > 0 && 00478 "getLocation() requires a non-empty PathDiagnostic."); 00479 00480 PathDiagnosticPiece *p = path.rbegin()->getPtr(); 00481 00482 while (true) { 00483 if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) { 00484 assert(!cp->path.empty()); 00485 p = cp->path.rbegin()->getPtr(); 00486 continue; 00487 } 00488 break; 00489 } 00490 00491 return p->getLocation(); 00492 } 00493 00494 //===----------------------------------------------------------------------===// 00495 // Manipulation of PathDiagnosticCallPieces. 00496 //===----------------------------------------------------------------------===// 00497 00498 static PathDiagnosticLocation getLastStmtLoc(const ExplodedNode *N, 00499 const SourceManager &SM) { 00500 while (N) { 00501 ProgramPoint PP = N->getLocation(); 00502 if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) 00503 return PathDiagnosticLocation(SP->getStmt(), SM, PP.getLocationContext()); 00504 if (N->pred_empty()) 00505 break; 00506 N = *N->pred_begin(); 00507 } 00508 return PathDiagnosticLocation(); 00509 } 00510 00511 PathDiagnosticCallPiece * 00512 PathDiagnosticCallPiece::construct(const ExplodedNode *N, 00513 const CallExitEnd &CE, 00514 const SourceManager &SM) { 00515 const Decl *caller = CE.getLocationContext()->getDecl(); 00516 PathDiagnosticLocation pos = getLastStmtLoc(N, SM); 00517 return new PathDiagnosticCallPiece(caller, pos); 00518 } 00519 00520 PathDiagnosticCallPiece * 00521 PathDiagnosticCallPiece::construct(PathPieces &path, 00522 const Decl *caller) { 00523 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller); 00524 path.clear(); 00525 path.push_front(C); 00526 return C; 00527 } 00528 00529 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 00530 const SourceManager &SM) { 00531 const Decl *D = CE.getCalleeContext()->getDecl(); 00532 Callee = D; 00533 callEnter = PathDiagnosticLocation(CE.getCallExpr(), SM, 00534 CE.getLocationContext()); 00535 callEnterWithin = PathDiagnosticLocation::createBegin(D, SM); 00536 } 00537 00538 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 00539 PathDiagnosticCallPiece::getCallEnterEvent() const { 00540 if (!Callee) 00541 return 0; 00542 SmallString<256> buf; 00543 llvm::raw_svector_ostream Out(buf); 00544 if (isa<BlockDecl>(Callee)) 00545 Out << "Calling anonymous block"; 00546 else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee)) 00547 Out << "Calling '" << *ND << "'"; 00548 StringRef msg = Out.str(); 00549 if (msg.empty()) 00550 return 0; 00551 return new PathDiagnosticEventPiece(callEnter, msg); 00552 } 00553 00554 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 00555 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 00556 SmallString<256> buf; 00557 llvm::raw_svector_ostream Out(buf); 00558 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller)) 00559 Out << "Entered call from '" << *ND << "'"; 00560 else 00561 Out << "Entered call"; 00562 StringRef msg = Out.str(); 00563 if (msg.empty()) 00564 return 0; 00565 return new PathDiagnosticEventPiece(callEnterWithin, msg); 00566 } 00567 00568 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 00569 PathDiagnosticCallPiece::getCallExitEvent() const { 00570 if (NoExit) 00571 return 0; 00572 SmallString<256> buf; 00573 llvm::raw_svector_ostream Out(buf); 00574 if (!CallStackMessage.empty()) 00575 Out << CallStackMessage; 00576 else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee)) 00577 Out << "Returning from '" << *ND << "'"; 00578 else 00579 Out << "Returning to caller"; 00580 return new PathDiagnosticEventPiece(callReturn, Out.str()); 00581 } 00582 00583 static void compute_path_size(const PathPieces &pieces, unsigned &size) { 00584 for (PathPieces::const_iterator it = pieces.begin(), 00585 et = pieces.end(); it != et; ++it) { 00586 const PathDiagnosticPiece *piece = it->getPtr(); 00587 if (const PathDiagnosticCallPiece *cp = 00588 dyn_cast<PathDiagnosticCallPiece>(piece)) { 00589 compute_path_size(cp->path, size); 00590 } 00591 else 00592 ++size; 00593 } 00594 } 00595 00596 unsigned PathDiagnostic::full_size() { 00597 unsigned size = 0; 00598 compute_path_size(path, size); 00599 return size; 00600 } 00601 00602 //===----------------------------------------------------------------------===// 00603 // FoldingSet profiling methods. 00604 //===----------------------------------------------------------------------===// 00605 00606 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 00607 ID.AddInteger(Range.getBegin().getRawEncoding()); 00608 ID.AddInteger(Range.getEnd().getRawEncoding()); 00609 ID.AddInteger(Loc.getRawEncoding()); 00610 return; 00611 } 00612 00613 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 00614 ID.AddInteger((unsigned) getKind()); 00615 ID.AddString(str); 00616 // FIXME: Add profiling support for code hints. 00617 ID.AddInteger((unsigned) getDisplayHint()); 00618 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) { 00619 ID.AddInteger(I->getBegin().getRawEncoding()); 00620 ID.AddInteger(I->getEnd().getRawEncoding()); 00621 } 00622 } 00623 00624 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 00625 PathDiagnosticPiece::Profile(ID); 00626 for (PathPieces::const_iterator it = path.begin(), 00627 et = path.end(); it != et; ++it) { 00628 ID.Add(**it); 00629 } 00630 } 00631 00632 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 00633 PathDiagnosticPiece::Profile(ID); 00634 ID.Add(Pos); 00635 } 00636 00637 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 00638 PathDiagnosticPiece::Profile(ID); 00639 for (const_iterator I = begin(), E = end(); I != E; ++I) 00640 ID.Add(*I); 00641 } 00642 00643 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 00644 PathDiagnosticSpotPiece::Profile(ID); 00645 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 00646 I != E; ++I) 00647 ID.Add(**I); 00648 } 00649 00650 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 00651 if (!path.empty()) 00652 getLocation().Profile(ID); 00653 ID.AddString(BugType); 00654 ID.AddString(Desc); 00655 ID.AddString(Category); 00656 } 00657 00658 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 00659 Profile(ID); 00660 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) 00661 ID.Add(**I); 00662 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 00663 ID.AddString(*I); 00664 } 00665 00666 StackHintGenerator::~StackHintGenerator() {} 00667 00668 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ 00669 ProgramPoint P = N->getLocation(); 00670 const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P); 00671 assert(CExit && "Stack Hints should be constructed at CallExitEnd points."); 00672 00673 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CExit->getStmt()); 00674 if (!CE) 00675 return ""; 00676 00677 if (!N) 00678 return getMessageForSymbolNotFound(); 00679 00680 // Check if one of the parameters are set to the interesting symbol. 00681 ProgramStateRef State = N->getState(); 00682 const LocationContext *LCtx = N->getLocationContext(); 00683 unsigned ArgIndex = 0; 00684 for (CallExpr::const_arg_iterator I = CE->arg_begin(), 00685 E = CE->arg_end(); I != E; ++I, ++ArgIndex){ 00686 SVal SV = State->getSVal(*I, LCtx); 00687 00688 // Check if the variable corresponding to the symbol is passed by value. 00689 SymbolRef AS = SV.getAsLocSymbol(); 00690 if (AS == Sym) { 00691 return getMessageForArg(*I, ArgIndex); 00692 } 00693 00694 // Check if the parameter is a pointer to the symbol. 00695 if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) { 00696 SVal PSV = State->getSVal(Reg->getRegion()); 00697 SymbolRef AS = PSV.getAsLocSymbol(); 00698 if (AS == Sym) { 00699 return getMessageForArg(*I, ArgIndex); 00700 } 00701 } 00702 } 00703 00704 // Check if we are returning the interesting symbol. 00705 SVal SV = State->getSVal(CE, LCtx); 00706 SymbolRef RetSym = SV.getAsLocSymbol(); 00707 if (RetSym == Sym) { 00708 return getMessageForReturn(CE); 00709 } 00710 00711 return getMessageForSymbolNotFound(); 00712 } 00713 00714 /// TODO: This is copied from clang diagnostics. Maybe we could just move it to 00715 /// some common place. (Same as HandleOrdinalModifier.) 00716 void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo, 00717 llvm::raw_svector_ostream &Out) { 00718 assert(ValNo != 0 && "ValNo must be strictly positive!"); 00719 00720 // We could use text forms for the first N ordinals, but the numeric 00721 // forms are actually nicer in diagnostics because they stand out. 00722 Out << ValNo; 00723 00724 // It is critically important that we do this perfectly for 00725 // user-written sequences with over 100 elements. 00726 switch (ValNo % 100) { 00727 case 11: 00728 case 12: 00729 case 13: 00730 Out << "th"; return; 00731 default: 00732 switch (ValNo % 10) { 00733 case 1: Out << "st"; return; 00734 case 2: Out << "nd"; return; 00735 case 3: Out << "rd"; return; 00736 default: Out << "th"; return; 00737 } 00738 } 00739 } 00740 00741 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, 00742 unsigned ArgIndex) { 00743 SmallString<200> buf; 00744 llvm::raw_svector_ostream os(buf); 00745 00746 os << Msg << " via "; 00747 // Printed parameters start at 1, not 0. 00748 printOrdinal(++ArgIndex, os); 00749 os << " parameter"; 00750 00751 return os.str(); 00752 }