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/AST/Decl.h" 00016 #include "clang/AST/DeclCXX.h" 00017 #include "clang/AST/DeclObjC.h" 00018 #include "clang/AST/Expr.h" 00019 #include "clang/AST/ExprCXX.h" 00020 #include "clang/AST/ParentMap.h" 00021 #include "clang/AST/StmtCXX.h" 00022 #include "clang/Basic/SourceManager.h" 00023 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 00024 #include "llvm/ADT/SmallString.h" 00025 #include "llvm/ADT/StringExtras.h" 00026 #include "llvm/Support/raw_ostream.h" 00027 00028 using namespace clang; 00029 using namespace ento; 00030 00031 bool PathDiagnosticMacroPiece::containsEvent() const { 00032 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 00033 I!=E; ++I) { 00034 if (isa<PathDiagnosticEventPiece>(*I)) 00035 return true; 00036 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I)) 00037 if (MP->containsEvent()) 00038 return true; 00039 } 00040 return false; 00041 } 00042 00043 static StringRef StripTrailingDots(StringRef s) { 00044 for (StringRef::size_type i = s.size(); i != 0; --i) 00045 if (s[i - 1] != '.') 00046 return s.substr(0, i); 00047 return ""; 00048 } 00049 00050 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 00051 Kind k, DisplayHint hint) 00052 : str(StripTrailingDots(s)), kind(k), Hint(hint), 00053 LastInMainSourceFile(false) {} 00054 00055 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 00056 : kind(k), Hint(hint), LastInMainSourceFile(false) {} 00057 00058 PathDiagnosticPiece::~PathDiagnosticPiece() {} 00059 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 00060 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} 00061 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 00062 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} 00063 00064 00065 PathPieces::~PathPieces() {} 00066 00067 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, 00068 bool ShouldFlattenMacros) const { 00069 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 00070 PathDiagnosticPiece *Piece = I->get(); 00071 00072 switch (Piece->getKind()) { 00073 case PathDiagnosticPiece::Call: { 00074 PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece); 00075 IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter = 00076 Call->getCallEnterEvent(); 00077 if (CallEnter) 00078 Current.push_back(CallEnter); 00079 Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros); 00080 IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = 00081 Call->getCallExitEvent(); 00082 if (callExit) 00083 Current.push_back(callExit); 00084 break; 00085 } 00086 case PathDiagnosticPiece::Macro: { 00087 PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece); 00088 if (ShouldFlattenMacros) { 00089 Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 00090 } else { 00091 Current.push_back(Piece); 00092 PathPieces NewPath; 00093 Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 00094 // FIXME: This probably shouldn't mutate the original path piece. 00095 Macro->subPieces = NewPath; 00096 } 00097 break; 00098 } 00099 case PathDiagnosticPiece::Event: 00100 case PathDiagnosticPiece::ControlFlow: 00101 Current.push_back(Piece); 00102 break; 00103 } 00104 } 00105 } 00106 00107 00108 PathDiagnostic::~PathDiagnostic() {} 00109 00110 PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue, 00111 StringRef bugtype, StringRef verboseDesc, 00112 StringRef shortDesc, StringRef category, 00113 PathDiagnosticLocation LocationToUnique, 00114 const Decl *DeclToUnique) 00115 : CheckName(CheckName), 00116 DeclWithIssue(declWithIssue), 00117 BugType(StripTrailingDots(bugtype)), 00118 VerboseDesc(StripTrailingDots(verboseDesc)), 00119 ShortDesc(StripTrailingDots(shortDesc)), 00120 Category(StripTrailingDots(category)), 00121 UniqueingLoc(LocationToUnique), 00122 UniqueingDecl(DeclToUnique), 00123 path(pathImpl) {} 00124 00125 static PathDiagnosticCallPiece * 00126 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, 00127 const SourceManager &SMgr) { 00128 SourceLocation CallLoc = CP->callEnter.asLocation(); 00129 00130 // If the call is within a macro, don't do anything (for now). 00131 if (CallLoc.isMacroID()) 00132 return nullptr; 00133 00134 assert(SMgr.isInMainFile(CallLoc) && 00135 "The call piece should be in the main file."); 00136 00137 // Check if CP represents a path through a function outside of the main file. 00138 if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation())) 00139 return CP; 00140 00141 const PathPieces &Path = CP->path; 00142 if (Path.empty()) 00143 return nullptr; 00144 00145 // Check if the last piece in the callee path is a call to a function outside 00146 // of the main file. 00147 if (PathDiagnosticCallPiece *CPInner = 00148 dyn_cast<PathDiagnosticCallPiece>(Path.back())) { 00149 return getFirstStackedCallToHeaderFile(CPInner, SMgr); 00150 } 00151 00152 // Otherwise, the last piece is in the main file. 00153 return nullptr; 00154 } 00155 00156 void PathDiagnostic::resetDiagnosticLocationToMainFile() { 00157 if (path.empty()) 00158 return; 00159 00160 PathDiagnosticPiece *LastP = path.back().get(); 00161 assert(LastP); 00162 const SourceManager &SMgr = LastP->getLocation().getManager(); 00163 00164 // We only need to check if the report ends inside headers, if the last piece 00165 // is a call piece. 00166 if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) { 00167 CP = getFirstStackedCallToHeaderFile(CP, SMgr); 00168 if (CP) { 00169 // Mark the piece. 00170 CP->setAsLastInMainSourceFile(); 00171 00172 // Update the path diagnostic message. 00173 const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee()); 00174 if (ND) { 00175 SmallString<200> buf; 00176 llvm::raw_svector_ostream os(buf); 00177 os << " (within a call to '" << ND->getDeclName() << "')"; 00178 appendToDesc(os.str()); 00179 } 00180 00181 // Reset the report containing declaration and location. 00182 DeclWithIssue = CP->getCaller(); 00183 Loc = CP->getLocation(); 00184 00185 return; 00186 } 00187 } 00188 } 00189 00190 void PathDiagnosticConsumer::anchor() { } 00191 00192 PathDiagnosticConsumer::~PathDiagnosticConsumer() { 00193 // Delete the contents of the FoldingSet if it isn't empty already. 00194 for (llvm::FoldingSet<PathDiagnostic>::iterator it = 00195 Diags.begin(), et = Diags.end() ; it != et ; ++it) { 00196 delete &*it; 00197 } 00198 } 00199 00200 void PathDiagnosticConsumer::HandlePathDiagnostic( 00201 std::unique_ptr<PathDiagnostic> D) { 00202 if (!D || D->path.empty()) 00203 return; 00204 00205 // We need to flatten the locations (convert Stmt* to locations) because 00206 // the referenced statements may be freed by the time the diagnostics 00207 // are emitted. 00208 D->flattenLocations(); 00209 00210 // If the PathDiagnosticConsumer does not support diagnostics that 00211 // cross file boundaries, prune out such diagnostics now. 00212 if (!supportsCrossFileDiagnostics()) { 00213 // Verify that the entire path is from the same FileID. 00214 FileID FID; 00215 const SourceManager &SMgr = D->path.front()->getLocation().getManager(); 00216 SmallVector<const PathPieces *, 5> WorkList; 00217 WorkList.push_back(&D->path); 00218 00219 while (!WorkList.empty()) { 00220 const PathPieces &path = *WorkList.pop_back_val(); 00221 00222 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; 00223 ++I) { 00224 const PathDiagnosticPiece *piece = I->get(); 00225 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 00226 00227 if (FID.isInvalid()) { 00228 FID = SMgr.getFileID(L); 00229 } else if (SMgr.getFileID(L) != FID) 00230 return; // FIXME: Emit a warning? 00231 00232 // Check the source ranges. 00233 ArrayRef<SourceRange> Ranges = piece->getRanges(); 00234 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), 00235 E = Ranges.end(); I != E; ++I) { 00236 SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); 00237 if (!L.isFileID() || SMgr.getFileID(L) != FID) 00238 return; // FIXME: Emit a warning? 00239 L = SMgr.getExpansionLoc(I->getEnd()); 00240 if (!L.isFileID() || SMgr.getFileID(L) != FID) 00241 return; // FIXME: Emit a warning? 00242 } 00243 00244 if (const PathDiagnosticCallPiece *call = 00245 dyn_cast<PathDiagnosticCallPiece>(piece)) { 00246 WorkList.push_back(&call->path); 00247 } 00248 else if (const PathDiagnosticMacroPiece *macro = 00249 dyn_cast<PathDiagnosticMacroPiece>(piece)) { 00250 WorkList.push_back(¯o->subPieces); 00251 } 00252 } 00253 } 00254 00255 if (FID.isInvalid()) 00256 return; // FIXME: Emit a warning? 00257 } 00258 00259 // Profile the node to see if we already have something matching it 00260 llvm::FoldingSetNodeID profile; 00261 D->Profile(profile); 00262 void *InsertPos = nullptr; 00263 00264 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 00265 // Keep the PathDiagnostic with the shorter path. 00266 // Note, the enclosing routine is called in deterministic order, so the 00267 // results will be consistent between runs (no reason to break ties if the 00268 // size is the same). 00269 const unsigned orig_size = orig->full_size(); 00270 const unsigned new_size = D->full_size(); 00271 if (orig_size <= new_size) 00272 return; 00273 00274 assert(orig != D.get()); 00275 Diags.RemoveNode(orig); 00276 delete orig; 00277 } 00278 00279 Diags.InsertNode(D.release()); 00280 } 00281 00282 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); 00283 static Optional<bool> 00284 compareControlFlow(const PathDiagnosticControlFlowPiece &X, 00285 const PathDiagnosticControlFlowPiece &Y) { 00286 FullSourceLoc XSL = X.getStartLocation().asLocation(); 00287 FullSourceLoc YSL = Y.getStartLocation().asLocation(); 00288 if (XSL != YSL) 00289 return XSL.isBeforeInTranslationUnitThan(YSL); 00290 FullSourceLoc XEL = X.getEndLocation().asLocation(); 00291 FullSourceLoc YEL = Y.getEndLocation().asLocation(); 00292 if (XEL != YEL) 00293 return XEL.isBeforeInTranslationUnitThan(YEL); 00294 return None; 00295 } 00296 00297 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, 00298 const PathDiagnosticMacroPiece &Y) { 00299 return comparePath(X.subPieces, Y.subPieces); 00300 } 00301 00302 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X, 00303 const PathDiagnosticCallPiece &Y) { 00304 FullSourceLoc X_CEL = X.callEnter.asLocation(); 00305 FullSourceLoc Y_CEL = Y.callEnter.asLocation(); 00306 if (X_CEL != Y_CEL) 00307 return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); 00308 FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); 00309 FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); 00310 if (X_CEWL != Y_CEWL) 00311 return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); 00312 FullSourceLoc X_CRL = X.callReturn.asLocation(); 00313 FullSourceLoc Y_CRL = Y.callReturn.asLocation(); 00314 if (X_CRL != Y_CRL) 00315 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); 00316 return comparePath(X.path, Y.path); 00317 } 00318 00319 static Optional<bool> comparePiece(const PathDiagnosticPiece &X, 00320 const PathDiagnosticPiece &Y) { 00321 if (X.getKind() != Y.getKind()) 00322 return X.getKind() < Y.getKind(); 00323 00324 FullSourceLoc XL = X.getLocation().asLocation(); 00325 FullSourceLoc YL = Y.getLocation().asLocation(); 00326 if (XL != YL) 00327 return XL.isBeforeInTranslationUnitThan(YL); 00328 00329 if (X.getString() != Y.getString()) 00330 return X.getString() < Y.getString(); 00331 00332 if (X.getRanges().size() != Y.getRanges().size()) 00333 return X.getRanges().size() < Y.getRanges().size(); 00334 00335 const SourceManager &SM = XL.getManager(); 00336 00337 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { 00338 SourceRange XR = X.getRanges()[i]; 00339 SourceRange YR = Y.getRanges()[i]; 00340 if (XR != YR) { 00341 if (XR.getBegin() != YR.getBegin()) 00342 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); 00343 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); 00344 } 00345 } 00346 00347 switch (X.getKind()) { 00348 case clang::ento::PathDiagnosticPiece::ControlFlow: 00349 return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), 00350 cast<PathDiagnosticControlFlowPiece>(Y)); 00351 case clang::ento::PathDiagnosticPiece::Event: 00352 return None; 00353 case clang::ento::PathDiagnosticPiece::Macro: 00354 return compareMacro(cast<PathDiagnosticMacroPiece>(X), 00355 cast<PathDiagnosticMacroPiece>(Y)); 00356 case clang::ento::PathDiagnosticPiece::Call: 00357 return compareCall(cast<PathDiagnosticCallPiece>(X), 00358 cast<PathDiagnosticCallPiece>(Y)); 00359 } 00360 llvm_unreachable("all cases handled"); 00361 } 00362 00363 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { 00364 if (X.size() != Y.size()) 00365 return X.size() < Y.size(); 00366 00367 PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); 00368 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); 00369 00370 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { 00371 Optional<bool> b = comparePiece(**X_I, **Y_I); 00372 if (b.hasValue()) 00373 return b.getValue(); 00374 } 00375 00376 return None; 00377 } 00378 00379 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { 00380 FullSourceLoc XL = X.getLocation().asLocation(); 00381 FullSourceLoc YL = Y.getLocation().asLocation(); 00382 if (XL != YL) 00383 return XL.isBeforeInTranslationUnitThan(YL); 00384 if (X.getBugType() != Y.getBugType()) 00385 return X.getBugType() < Y.getBugType(); 00386 if (X.getCategory() != Y.getCategory()) 00387 return X.getCategory() < Y.getCategory(); 00388 if (X.getVerboseDescription() != Y.getVerboseDescription()) 00389 return X.getVerboseDescription() < Y.getVerboseDescription(); 00390 if (X.getShortDescription() != Y.getShortDescription()) 00391 return X.getShortDescription() < Y.getShortDescription(); 00392 if (X.getDeclWithIssue() != Y.getDeclWithIssue()) { 00393 const Decl *XD = X.getDeclWithIssue(); 00394 if (!XD) 00395 return true; 00396 const Decl *YD = Y.getDeclWithIssue(); 00397 if (!YD) 00398 return false; 00399 SourceLocation XDL = XD->getLocation(); 00400 SourceLocation YDL = YD->getLocation(); 00401 if (XDL != YDL) { 00402 const SourceManager &SM = XL.getManager(); 00403 return SM.isBeforeInTranslationUnit(XDL, YDL); 00404 } 00405 } 00406 PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); 00407 PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); 00408 if (XE - XI != YE - YI) 00409 return (XE - XI) < (YE - YI); 00410 for ( ; XI != XE ; ++XI, ++YI) { 00411 if (*XI != *YI) 00412 return (*XI) < (*YI); 00413 } 00414 Optional<bool> b = comparePath(X.path, Y.path); 00415 assert(b.hasValue()); 00416 return b.getValue(); 00417 } 00418 00419 void PathDiagnosticConsumer::FlushDiagnostics( 00420 PathDiagnosticConsumer::FilesMade *Files) { 00421 if (flushed) 00422 return; 00423 00424 flushed = true; 00425 00426 std::vector<const PathDiagnostic *> BatchDiags; 00427 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), 00428 et = Diags.end(); it != et; ++it) { 00429 const PathDiagnostic *D = &*it; 00430 BatchDiags.push_back(D); 00431 } 00432 00433 // Sort the diagnostics so that they are always emitted in a deterministic 00434 // order. 00435 if (!BatchDiags.empty()) 00436 std::sort(BatchDiags.begin(), BatchDiags.end(), 00437 [](const PathDiagnostic *X, const PathDiagnostic *Y) { 00438 return X != Y && compare(*X, *Y); 00439 }); 00440 00441 FlushDiagnosticsImpl(BatchDiags, Files); 00442 00443 // Delete the flushed diagnostics. 00444 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), 00445 et = BatchDiags.end(); it != et; ++it) { 00446 const PathDiagnostic *D = *it; 00447 delete D; 00448 } 00449 00450 // Clear out the FoldingSet. 00451 Diags.clear(); 00452 } 00453 00454 PathDiagnosticConsumer::FilesMade::~FilesMade() { 00455 for (PDFileEntry &Entry : *this) 00456 Entry.~PDFileEntry(); 00457 } 00458 00459 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 00460 StringRef ConsumerName, 00461 StringRef FileName) { 00462 llvm::FoldingSetNodeID NodeID; 00463 NodeID.Add(PD); 00464 void *InsertPos; 00465 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 00466 if (!Entry) { 00467 Entry = Alloc.Allocate<PDFileEntry>(); 00468 Entry = new (Entry) PDFileEntry(NodeID); 00469 InsertNode(Entry, InsertPos); 00470 } 00471 00472 // Allocate persistent storage for the file name. 00473 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); 00474 memcpy(FileName_cstr, FileName.data(), FileName.size()); 00475 00476 Entry->files.push_back(std::make_pair(ConsumerName, 00477 StringRef(FileName_cstr, 00478 FileName.size()))); 00479 } 00480 00481 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 00482 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 00483 llvm::FoldingSetNodeID NodeID; 00484 NodeID.Add(PD); 00485 void *InsertPos; 00486 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 00487 if (!Entry) 00488 return nullptr; 00489 return &Entry->files; 00490 } 00491 00492 //===----------------------------------------------------------------------===// 00493 // PathDiagnosticLocation methods. 00494 //===----------------------------------------------------------------------===// 00495 00496 static SourceLocation getValidSourceLocation(const Stmt* S, 00497 LocationOrAnalysisDeclContext LAC, 00498 bool UseEnd = false) { 00499 SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart(); 00500 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " 00501 "be passed to PathDiagnosticLocation upon creation."); 00502 00503 // S might be a temporary statement that does not have a location in the 00504 // source code, so find an enclosing statement and use its location. 00505 if (!L.isValid()) { 00506 00507 AnalysisDeclContext *ADC; 00508 if (LAC.is<const LocationContext*>()) 00509 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 00510 else 00511 ADC = LAC.get<AnalysisDeclContext*>(); 00512 00513 ParentMap &PM = ADC->getParentMap(); 00514 00515 const Stmt *Parent = S; 00516 do { 00517 Parent = PM.getParent(Parent); 00518 00519 // In rare cases, we have implicit top-level expressions, 00520 // such as arguments for implicit member initializers. 00521 // In this case, fall back to the start of the body (even if we were 00522 // asked for the statement end location). 00523 if (!Parent) { 00524 const Stmt *Body = ADC->getBody(); 00525 if (Body) 00526 L = Body->getLocStart(); 00527 else 00528 L = ADC->getDecl()->getLocEnd(); 00529 break; 00530 } 00531 00532 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart(); 00533 } while (!L.isValid()); 00534 } 00535 00536 return L; 00537 } 00538 00539 static PathDiagnosticLocation 00540 getLocationForCaller(const StackFrameContext *SFC, 00541 const LocationContext *CallerCtx, 00542 const SourceManager &SM) { 00543 const CFGBlock &Block = *SFC->getCallSiteBlock(); 00544 CFGElement Source = Block[SFC->getIndex()]; 00545 00546 switch (Source.getKind()) { 00547 case CFGElement::Statement: 00548 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), 00549 SM, CallerCtx); 00550 case CFGElement::Initializer: { 00551 const CFGInitializer &Init = Source.castAs<CFGInitializer>(); 00552 return PathDiagnosticLocation(Init.getInitializer()->getInit(), 00553 SM, CallerCtx); 00554 } 00555 case CFGElement::AutomaticObjectDtor: { 00556 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); 00557 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 00558 SM, CallerCtx); 00559 } 00560 case CFGElement::DeleteDtor: { 00561 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); 00562 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); 00563 } 00564 case CFGElement::BaseDtor: 00565 case CFGElement::MemberDtor: { 00566 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); 00567 if (const Stmt *CallerBody = CallerInfo->getBody()) 00568 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); 00569 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); 00570 } 00571 case CFGElement::TemporaryDtor: 00572 case CFGElement::NewAllocator: 00573 llvm_unreachable("not yet implemented!"); 00574 } 00575 00576 llvm_unreachable("Unknown CFGElement kind"); 00577 } 00578 00579 00580 PathDiagnosticLocation 00581 PathDiagnosticLocation::createBegin(const Decl *D, 00582 const SourceManager &SM) { 00583 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 00584 } 00585 00586 PathDiagnosticLocation 00587 PathDiagnosticLocation::createBegin(const Stmt *S, 00588 const SourceManager &SM, 00589 LocationOrAnalysisDeclContext LAC) { 00590 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 00591 SM, SingleLocK); 00592 } 00593 00594 00595 PathDiagnosticLocation 00596 PathDiagnosticLocation::createEnd(const Stmt *S, 00597 const SourceManager &SM, 00598 LocationOrAnalysisDeclContext LAC) { 00599 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) 00600 return createEndBrace(CS, SM); 00601 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 00602 SM, SingleLocK); 00603 } 00604 00605 PathDiagnosticLocation 00606 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 00607 const SourceManager &SM) { 00608 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 00609 } 00610 00611 PathDiagnosticLocation 00612 PathDiagnosticLocation::createConditionalColonLoc( 00613 const ConditionalOperator *CO, 00614 const SourceManager &SM) { 00615 return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); 00616 } 00617 00618 00619 PathDiagnosticLocation 00620 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 00621 const SourceManager &SM) { 00622 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 00623 } 00624 00625 PathDiagnosticLocation 00626 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 00627 const SourceManager &SM) { 00628 SourceLocation L = CS->getLBracLoc(); 00629 return PathDiagnosticLocation(L, SM, SingleLocK); 00630 } 00631 00632 PathDiagnosticLocation 00633 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 00634 const SourceManager &SM) { 00635 SourceLocation L = CS->getRBracLoc(); 00636 return PathDiagnosticLocation(L, SM, SingleLocK); 00637 } 00638 00639 PathDiagnosticLocation 00640 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 00641 const SourceManager &SM) { 00642 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 00643 if (const CompoundStmt *CS = 00644 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 00645 if (!CS->body_empty()) { 00646 SourceLocation Loc = (*CS->body_begin())->getLocStart(); 00647 return PathDiagnosticLocation(Loc, SM, SingleLocK); 00648 } 00649 00650 return PathDiagnosticLocation(); 00651 } 00652 00653 PathDiagnosticLocation 00654 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 00655 const SourceManager &SM) { 00656 SourceLocation L = LC->getDecl()->getBodyRBrace(); 00657 return PathDiagnosticLocation(L, SM, SingleLocK); 00658 } 00659 00660 PathDiagnosticLocation 00661 PathDiagnosticLocation::create(const ProgramPoint& P, 00662 const SourceManager &SMng) { 00663 00664 const Stmt* S = nullptr; 00665 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { 00666 const CFGBlock *BSrc = BE->getSrc(); 00667 S = BSrc->getTerminatorCondition(); 00668 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { 00669 S = SP->getStmt(); 00670 if (P.getAs<PostStmtPurgeDeadSymbols>()) 00671 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); 00672 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { 00673 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), 00674 SMng); 00675 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { 00676 return PathDiagnosticLocation(PIE->getLocation(), SMng); 00677 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { 00678 return getLocationForCaller(CE->getCalleeContext(), 00679 CE->getLocationContext(), 00680 SMng); 00681 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { 00682 return getLocationForCaller(CEE->getCalleeContext(), 00683 CEE->getLocationContext(), 00684 SMng); 00685 } else { 00686 llvm_unreachable("Unexpected ProgramPoint"); 00687 } 00688 00689 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 00690 } 00691 00692 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { 00693 ProgramPoint P = N->getLocation(); 00694 if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) 00695 return SP->getStmt(); 00696 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) 00697 return BE->getSrc()->getTerminator(); 00698 if (Optional<CallEnter> CE = P.getAs<CallEnter>()) 00699 return CE->getCallExpr(); 00700 if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) 00701 return CEE->getCalleeContext()->getCallSite(); 00702 if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) 00703 return PIPP->getInitializer()->getInit(); 00704 00705 return nullptr; 00706 } 00707 00708 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { 00709 for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) { 00710 if (const Stmt *S = getStmt(N)) { 00711 // Check if the statement is '?' or '&&'/'||'. These are "merges", 00712 // not actual statement points. 00713 switch (S->getStmtClass()) { 00714 case Stmt::ChooseExprClass: 00715 case Stmt::BinaryConditionalOperatorClass: 00716 case Stmt::ConditionalOperatorClass: 00717 continue; 00718 case Stmt::BinaryOperatorClass: { 00719 BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); 00720 if (Op == BO_LAnd || Op == BO_LOr) 00721 continue; 00722 break; 00723 } 00724 default: 00725 break; 00726 } 00727 // We found the statement, so return it. 00728 return S; 00729 } 00730 } 00731 00732 return nullptr; 00733 } 00734 00735 PathDiagnosticLocation 00736 PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, 00737 const SourceManager &SM) { 00738 assert(N && "Cannot create a location with a null node."); 00739 const Stmt *S = getStmt(N); 00740 00741 if (!S) { 00742 // If this is an implicit call, return the implicit call point location. 00743 if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>()) 00744 return PathDiagnosticLocation(PIE->getLocation(), SM); 00745 S = getNextStmt(N); 00746 } 00747 00748 if (S) { 00749 ProgramPoint P = N->getLocation(); 00750 const LocationContext *LC = N->getLocationContext(); 00751 00752 // For member expressions, return the location of the '.' or '->'. 00753 if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) 00754 return PathDiagnosticLocation::createMemberLoc(ME, SM); 00755 00756 // For binary operators, return the location of the operator. 00757 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) 00758 return PathDiagnosticLocation::createOperatorLoc(B, SM); 00759 00760 if (P.getAs<PostStmtPurgeDeadSymbols>()) 00761 return PathDiagnosticLocation::createEnd(S, SM, LC); 00762 00763 if (S->getLocStart().isValid()) 00764 return PathDiagnosticLocation(S, SM, LC); 00765 return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); 00766 } 00767 00768 return createDeclEnd(N->getLocationContext(), SM); 00769 } 00770 00771 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 00772 const PathDiagnosticLocation &PDL) { 00773 FullSourceLoc L = PDL.asLocation(); 00774 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 00775 } 00776 00777 FullSourceLoc 00778 PathDiagnosticLocation::genLocation(SourceLocation L, 00779 LocationOrAnalysisDeclContext LAC) const { 00780 assert(isValid()); 00781 // Note that we want a 'switch' here so that the compiler can warn us in 00782 // case we add more cases. 00783 switch (K) { 00784 case SingleLocK: 00785 case RangeK: 00786 break; 00787 case StmtK: 00788 // Defensive checking. 00789 if (!S) 00790 break; 00791 return FullSourceLoc(getValidSourceLocation(S, LAC), 00792 const_cast<SourceManager&>(*SM)); 00793 case DeclK: 00794 // Defensive checking. 00795 if (!D) 00796 break; 00797 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 00798 } 00799 00800 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 00801 } 00802 00803 PathDiagnosticRange 00804 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 00805 assert(isValid()); 00806 // Note that we want a 'switch' here so that the compiler can warn us in 00807 // case we add more cases. 00808 switch (K) { 00809 case SingleLocK: 00810 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 00811 case RangeK: 00812 break; 00813 case StmtK: { 00814 const Stmt *S = asStmt(); 00815 switch (S->getStmtClass()) { 00816 default: 00817 break; 00818 case Stmt::DeclStmtClass: { 00819 const DeclStmt *DS = cast<DeclStmt>(S); 00820 if (DS->isSingleDecl()) { 00821 // Should always be the case, but we'll be defensive. 00822 return SourceRange(DS->getLocStart(), 00823 DS->getSingleDecl()->getLocation()); 00824 } 00825 break; 00826 } 00827 // FIXME: Provide better range information for different 00828 // terminators. 00829 case Stmt::IfStmtClass: 00830 case Stmt::WhileStmtClass: 00831 case Stmt::DoStmtClass: 00832 case Stmt::ForStmtClass: 00833 case Stmt::ChooseExprClass: 00834 case Stmt::IndirectGotoStmtClass: 00835 case Stmt::SwitchStmtClass: 00836 case Stmt::BinaryConditionalOperatorClass: 00837 case Stmt::ConditionalOperatorClass: 00838 case Stmt::ObjCForCollectionStmtClass: { 00839 SourceLocation L = getValidSourceLocation(S, LAC); 00840 return SourceRange(L, L); 00841 } 00842 } 00843 SourceRange R = S->getSourceRange(); 00844 if (R.isValid()) 00845 return R; 00846 break; 00847 } 00848 case DeclK: 00849 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 00850 return MD->getSourceRange(); 00851 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 00852 if (Stmt *Body = FD->getBody()) 00853 return Body->getSourceRange(); 00854 } 00855 else { 00856 SourceLocation L = D->getLocation(); 00857 return PathDiagnosticRange(SourceRange(L, L), true); 00858 } 00859 } 00860 00861 return SourceRange(Loc,Loc); 00862 } 00863 00864 void PathDiagnosticLocation::flatten() { 00865 if (K == StmtK) { 00866 K = RangeK; 00867 S = nullptr; 00868 D = nullptr; 00869 } 00870 else if (K == DeclK) { 00871 K = SingleLocK; 00872 S = nullptr; 00873 D = nullptr; 00874 } 00875 } 00876 00877 //===----------------------------------------------------------------------===// 00878 // Manipulation of PathDiagnosticCallPieces. 00879 //===----------------------------------------------------------------------===// 00880 00881 PathDiagnosticCallPiece * 00882 PathDiagnosticCallPiece::construct(const ExplodedNode *N, 00883 const CallExitEnd &CE, 00884 const SourceManager &SM) { 00885 const Decl *caller = CE.getLocationContext()->getDecl(); 00886 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 00887 CE.getLocationContext(), 00888 SM); 00889 return new PathDiagnosticCallPiece(caller, pos); 00890 } 00891 00892 PathDiagnosticCallPiece * 00893 PathDiagnosticCallPiece::construct(PathPieces &path, 00894 const Decl *caller) { 00895 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller); 00896 path.clear(); 00897 path.push_front(C); 00898 return C; 00899 } 00900 00901 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 00902 const SourceManager &SM) { 00903 const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 00904 Callee = CalleeCtx->getDecl(); 00905 00906 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 00907 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 00908 } 00909 00910 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, 00911 StringRef Prefix = StringRef()) { 00912 if (!D->getIdentifier()) 00913 return; 00914 Out << Prefix << '\'' << *D << '\''; 00915 } 00916 00917 static bool describeCodeDecl(raw_ostream &Out, const Decl *D, 00918 bool ExtendedDescription, 00919 StringRef Prefix = StringRef()) { 00920 if (!D) 00921 return false; 00922 00923 if (isa<BlockDecl>(D)) { 00924 if (ExtendedDescription) 00925 Out << Prefix << "anonymous block"; 00926 return ExtendedDescription; 00927 } 00928 00929 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { 00930 Out << Prefix; 00931 if (ExtendedDescription && !MD->isUserProvided()) { 00932 if (MD->isExplicitlyDefaulted()) 00933 Out << "defaulted "; 00934 else 00935 Out << "implicit "; 00936 } 00937 00938 if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) { 00939 if (CD->isDefaultConstructor()) 00940 Out << "default "; 00941 else if (CD->isCopyConstructor()) 00942 Out << "copy "; 00943 else if (CD->isMoveConstructor()) 00944 Out << "move "; 00945 00946 Out << "constructor"; 00947 describeClass(Out, MD->getParent(), " for "); 00948 00949 } else if (isa<CXXDestructorDecl>(MD)) { 00950 if (!MD->isUserProvided()) { 00951 Out << "destructor"; 00952 describeClass(Out, MD->getParent(), " for "); 00953 } else { 00954 // Use ~Foo for explicitly-written destructors. 00955 Out << "'" << *MD << "'"; 00956 } 00957 00958 } else if (MD->isCopyAssignmentOperator()) { 00959 Out << "copy assignment operator"; 00960 describeClass(Out, MD->getParent(), " for "); 00961 00962 } else if (MD->isMoveAssignmentOperator()) { 00963 Out << "move assignment operator"; 00964 describeClass(Out, MD->getParent(), " for "); 00965 00966 } else { 00967 if (MD->getParent()->getIdentifier()) 00968 Out << "'" << *MD->getParent() << "::" << *MD << "'"; 00969 else 00970 Out << "'" << *MD << "'"; 00971 } 00972 00973 return true; 00974 } 00975 00976 Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\''; 00977 return true; 00978 } 00979 00980 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 00981 PathDiagnosticCallPiece::getCallEnterEvent() const { 00982 if (!Callee) 00983 return nullptr; 00984 00985 SmallString<256> buf; 00986 llvm::raw_svector_ostream Out(buf); 00987 00988 Out << "Calling "; 00989 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); 00990 00991 assert(callEnter.asLocation().isValid()); 00992 return new PathDiagnosticEventPiece(callEnter, Out.str()); 00993 } 00994 00995 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 00996 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 00997 if (!callEnterWithin.asLocation().isValid()) 00998 return nullptr; 00999 if (Callee->isImplicit() || !Callee->hasBody()) 01000 return nullptr; 01001 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) 01002 if (MD->isDefaulted()) 01003 return nullptr; 01004 01005 SmallString<256> buf; 01006 llvm::raw_svector_ostream Out(buf); 01007 01008 Out << "Entered call"; 01009 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); 01010 01011 return new PathDiagnosticEventPiece(callEnterWithin, Out.str()); 01012 } 01013 01014 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 01015 PathDiagnosticCallPiece::getCallExitEvent() const { 01016 if (NoExit) 01017 return nullptr; 01018 01019 SmallString<256> buf; 01020 llvm::raw_svector_ostream Out(buf); 01021 01022 if (!CallStackMessage.empty()) { 01023 Out << CallStackMessage; 01024 } else { 01025 bool DidDescribe = describeCodeDecl(Out, Callee, 01026 /*ExtendedDescription=*/false, 01027 "Returning from "); 01028 if (!DidDescribe) 01029 Out << "Returning to caller"; 01030 } 01031 01032 assert(callReturn.asLocation().isValid()); 01033 return new PathDiagnosticEventPiece(callReturn, Out.str()); 01034 } 01035 01036 static void compute_path_size(const PathPieces &pieces, unsigned &size) { 01037 for (PathPieces::const_iterator it = pieces.begin(), 01038 et = pieces.end(); it != et; ++it) { 01039 const PathDiagnosticPiece *piece = it->get(); 01040 if (const PathDiagnosticCallPiece *cp = 01041 dyn_cast<PathDiagnosticCallPiece>(piece)) { 01042 compute_path_size(cp->path, size); 01043 } 01044 else 01045 ++size; 01046 } 01047 } 01048 01049 unsigned PathDiagnostic::full_size() { 01050 unsigned size = 0; 01051 compute_path_size(path, size); 01052 return size; 01053 } 01054 01055 //===----------------------------------------------------------------------===// 01056 // FoldingSet profiling methods. 01057 //===----------------------------------------------------------------------===// 01058 01059 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 01060 ID.AddInteger(Range.getBegin().getRawEncoding()); 01061 ID.AddInteger(Range.getEnd().getRawEncoding()); 01062 ID.AddInteger(Loc.getRawEncoding()); 01063 return; 01064 } 01065 01066 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 01067 ID.AddInteger((unsigned) getKind()); 01068 ID.AddString(str); 01069 // FIXME: Add profiling support for code hints. 01070 ID.AddInteger((unsigned) getDisplayHint()); 01071 ArrayRef<SourceRange> Ranges = getRanges(); 01072 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 01073 I != E; ++I) { 01074 ID.AddInteger(I->getBegin().getRawEncoding()); 01075 ID.AddInteger(I->getEnd().getRawEncoding()); 01076 } 01077 } 01078 01079 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 01080 PathDiagnosticPiece::Profile(ID); 01081 for (PathPieces::const_iterator it = path.begin(), 01082 et = path.end(); it != et; ++it) { 01083 ID.Add(**it); 01084 } 01085 } 01086 01087 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 01088 PathDiagnosticPiece::Profile(ID); 01089 ID.Add(Pos); 01090 } 01091 01092 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 01093 PathDiagnosticPiece::Profile(ID); 01094 for (const_iterator I = begin(), E = end(); I != E; ++I) 01095 ID.Add(*I); 01096 } 01097 01098 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 01099 PathDiagnosticSpotPiece::Profile(ID); 01100 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 01101 I != E; ++I) 01102 ID.Add(**I); 01103 } 01104 01105 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 01106 ID.Add(getLocation()); 01107 ID.AddString(BugType); 01108 ID.AddString(VerboseDesc); 01109 ID.AddString(Category); 01110 } 01111 01112 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 01113 Profile(ID); 01114 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) 01115 ID.Add(**I); 01116 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 01117 ID.AddString(*I); 01118 } 01119 01120 StackHintGenerator::~StackHintGenerator() {} 01121 01122 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ 01123 ProgramPoint P = N->getLocation(); 01124 CallExitEnd CExit = P.castAs<CallExitEnd>(); 01125 01126 // FIXME: Use CallEvent to abstract this over all calls. 01127 const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); 01128 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); 01129 if (!CE) 01130 return ""; 01131 01132 if (!N) 01133 return getMessageForSymbolNotFound(); 01134 01135 // Check if one of the parameters are set to the interesting symbol. 01136 ProgramStateRef State = N->getState(); 01137 const LocationContext *LCtx = N->getLocationContext(); 01138 unsigned ArgIndex = 0; 01139 for (CallExpr::const_arg_iterator I = CE->arg_begin(), 01140 E = CE->arg_end(); I != E; ++I, ++ArgIndex){ 01141 SVal SV = State->getSVal(*I, LCtx); 01142 01143 // Check if the variable corresponding to the symbol is passed by value. 01144 SymbolRef AS = SV.getAsLocSymbol(); 01145 if (AS == Sym) { 01146 return getMessageForArg(*I, ArgIndex); 01147 } 01148 01149 // Check if the parameter is a pointer to the symbol. 01150 if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { 01151 SVal PSV = State->getSVal(Reg->getRegion()); 01152 SymbolRef AS = PSV.getAsLocSymbol(); 01153 if (AS == Sym) { 01154 return getMessageForArg(*I, ArgIndex); 01155 } 01156 } 01157 } 01158 01159 // Check if we are returning the interesting symbol. 01160 SVal SV = State->getSVal(CE, LCtx); 01161 SymbolRef RetSym = SV.getAsLocSymbol(); 01162 if (RetSym == Sym) { 01163 return getMessageForReturn(CE); 01164 } 01165 01166 return getMessageForSymbolNotFound(); 01167 } 01168 01169 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, 01170 unsigned ArgIndex) { 01171 // Printed parameters start at 1, not 0. 01172 ++ArgIndex; 01173 01174 SmallString<200> buf; 01175 llvm::raw_svector_ostream os(buf); 01176 01177 os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) 01178 << " parameter"; 01179 01180 return os.str(); 01181 }