PathDiagnostic.cpp revision 2a648169f9ad854536814515cba1780fd02586d2
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===// 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The LLVM Compiler Infrastructure 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This file is distributed under the University of Illinois Open Source 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// License. See LICENSE.TXT for details. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file defines the PathDiagnostic-related interfaces. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/Decl.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/DeclCXX.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/DeclObjC.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/Expr.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/ParentMap.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/StmtCXX.h" 217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "clang/Basic/SourceManager.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/SmallString.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/StringExtras.h" 257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "llvm/Support/raw_ostream.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace ento; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool PathDiagnosticMacroPiece::containsEvent() const { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) I!=E; ++I) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (isa<PathDiagnosticEventPiece>(*I)) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I)) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (MP->containsEvent()) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static StringRef StripTrailingDots(StringRef s) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (StringRef::size_type i = s.size(); i != 0; --i) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (s[i - 1] != '.') 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return s.substr(0, i); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ""; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Kind k, DisplayHint hint) 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : str(StripTrailingDots(s)), kind(k), Hint(hint), 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LastInMainSourceFile(false) {} 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : kind(k), Hint(hint), LastInMainSourceFile(false) {} 56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PathDiagnosticPiece::~PathDiagnosticPiece() {} 58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 63 64PathPieces::~PathPieces() {} 65 66void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, 67 bool ShouldFlattenMacros) const { 68 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 69 PathDiagnosticPiece *Piece = I->getPtr(); 70 71 switch (Piece->getKind()) { 72 case PathDiagnosticPiece::Call: { 73 PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece); 74 IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter = 75 Call->getCallEnterEvent(); 76 if (CallEnter) 77 Current.push_back(CallEnter); 78 Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros); 79 IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = 80 Call->getCallExitEvent(); 81 if (callExit) 82 Current.push_back(callExit); 83 break; 84 } 85 case PathDiagnosticPiece::Macro: { 86 PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece); 87 if (ShouldFlattenMacros) { 88 Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 89 } else { 90 Current.push_back(Piece); 91 PathPieces NewPath; 92 Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 93 // FIXME: This probably shouldn't mutate the original path piece. 94 Macro->subPieces = NewPath; 95 } 96 break; 97 } 98 case PathDiagnosticPiece::Event: 99 case PathDiagnosticPiece::ControlFlow: 100 Current.push_back(Piece); 101 break; 102 } 103 } 104} 105 106 107PathDiagnostic::~PathDiagnostic() {} 108 109PathDiagnostic::PathDiagnostic(const Decl *declWithIssue, 110 StringRef bugtype, StringRef verboseDesc, 111 StringRef shortDesc, StringRef category, 112 PathDiagnosticLocation LocationToUnique, 113 const Decl *DeclToUnique) 114 : DeclWithIssue(declWithIssue), 115 BugType(StripTrailingDots(bugtype)), 116 VerboseDesc(StripTrailingDots(verboseDesc)), 117 ShortDesc(StripTrailingDots(shortDesc)), 118 Category(StripTrailingDots(category)), 119 UniqueingLoc(LocationToUnique), 120 UniqueingDecl(DeclToUnique), 121 path(pathImpl) {} 122 123static PathDiagnosticCallPiece * 124getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, 125 const SourceManager &SMgr) { 126 SourceLocation CallLoc = CP->callEnter.asLocation(); 127 128 // If the call is within a macro, don't do anything (for now). 129 if (CallLoc.isMacroID()) 130 return 0; 131 132 assert(SMgr.isInMainFile(CallLoc) && 133 "The call piece should be in the main file."); 134 135 // Check if CP represents a path through a function outside of the main file. 136 if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation())) 137 return CP; 138 139 const PathPieces &Path = CP->path; 140 if (Path.empty()) 141 return 0; 142 143 // Check if the last piece in the callee path is a call to a function outside 144 // of the main file. 145 if (PathDiagnosticCallPiece *CPInner = 146 dyn_cast<PathDiagnosticCallPiece>(Path.back())) { 147 return getFirstStackedCallToHeaderFile(CPInner, SMgr); 148 } 149 150 // Otherwise, the last piece is in the main file. 151 return 0; 152} 153 154void PathDiagnostic::resetDiagnosticLocationToMainFile() { 155 if (path.empty()) 156 return; 157 158 PathDiagnosticPiece *LastP = path.back().getPtr(); 159 assert(LastP); 160 const SourceManager &SMgr = LastP->getLocation().getManager(); 161 162 // We only need to check if the report ends inside headers, if the last piece 163 // is a call piece. 164 if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) { 165 CP = getFirstStackedCallToHeaderFile(CP, SMgr); 166 if (CP) { 167 // Mark the piece. 168 CP->setAsLastInMainSourceFile(); 169 170 // Update the path diagnostic message. 171 const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee()); 172 if (ND) { 173 SmallString<200> buf; 174 llvm::raw_svector_ostream os(buf); 175 os << " (within a call to '" << ND->getDeclName() << "')"; 176 appendToDesc(os.str()); 177 } 178 179 // Reset the report containing declaration and location. 180 DeclWithIssue = CP->getCaller(); 181 Loc = CP->getLocation(); 182 183 return; 184 } 185 } 186} 187 188void PathDiagnosticConsumer::anchor() { } 189 190PathDiagnosticConsumer::~PathDiagnosticConsumer() { 191 // Delete the contents of the FoldingSet if it isn't empty already. 192 for (llvm::FoldingSet<PathDiagnostic>::iterator it = 193 Diags.begin(), et = Diags.end() ; it != et ; ++it) { 194 delete &*it; 195 } 196} 197 198void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { 199 OwningPtr<PathDiagnostic> OwningD(D); 200 201 if (!D || D->path.empty()) 202 return; 203 204 // We need to flatten the locations (convert Stmt* to locations) because 205 // the referenced statements may be freed by the time the diagnostics 206 // are emitted. 207 D->flattenLocations(); 208 209 // If the PathDiagnosticConsumer does not support diagnostics that 210 // cross file boundaries, prune out such diagnostics now. 211 if (!supportsCrossFileDiagnostics()) { 212 // Verify that the entire path is from the same FileID. 213 FileID FID; 214 const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager(); 215 SmallVector<const PathPieces *, 5> WorkList; 216 WorkList.push_back(&D->path); 217 218 while (!WorkList.empty()) { 219 const PathPieces &path = *WorkList.pop_back_val(); 220 221 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; 222 ++I) { 223 const PathDiagnosticPiece *piece = I->getPtr(); 224 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 225 226 if (FID.isInvalid()) { 227 FID = SMgr.getFileID(L); 228 } else if (SMgr.getFileID(L) != FID) 229 return; // FIXME: Emit a warning? 230 231 // Check the source ranges. 232 ArrayRef<SourceRange> Ranges = piece->getRanges(); 233 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), 234 E = Ranges.end(); I != E; ++I) { 235 SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); 236 if (!L.isFileID() || SMgr.getFileID(L) != FID) 237 return; // FIXME: Emit a warning? 238 L = SMgr.getExpansionLoc(I->getEnd()); 239 if (!L.isFileID() || SMgr.getFileID(L) != FID) 240 return; // FIXME: Emit a warning? 241 } 242 243 if (const PathDiagnosticCallPiece *call = 244 dyn_cast<PathDiagnosticCallPiece>(piece)) { 245 WorkList.push_back(&call->path); 246 } 247 else if (const PathDiagnosticMacroPiece *macro = 248 dyn_cast<PathDiagnosticMacroPiece>(piece)) { 249 WorkList.push_back(¯o->subPieces); 250 } 251 } 252 } 253 254 if (FID.isInvalid()) 255 return; // FIXME: Emit a warning? 256 } 257 258 // Profile the node to see if we already have something matching it 259 llvm::FoldingSetNodeID profile; 260 D->Profile(profile); 261 void *InsertPos = 0; 262 263 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 264 // Keep the PathDiagnostic with the shorter path. 265 // Note, the enclosing routine is called in deterministic order, so the 266 // results will be consistent between runs (no reason to break ties if the 267 // size is the same). 268 const unsigned orig_size = orig->full_size(); 269 const unsigned new_size = D->full_size(); 270 if (orig_size <= new_size) 271 return; 272 273 assert(orig != D); 274 Diags.RemoveNode(orig); 275 delete orig; 276 } 277 278 Diags.InsertNode(OwningD.take()); 279} 280 281static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); 282static Optional<bool> 283compareControlFlow(const PathDiagnosticControlFlowPiece &X, 284 const PathDiagnosticControlFlowPiece &Y) { 285 FullSourceLoc XSL = X.getStartLocation().asLocation(); 286 FullSourceLoc YSL = Y.getStartLocation().asLocation(); 287 if (XSL != YSL) 288 return XSL.isBeforeInTranslationUnitThan(YSL); 289 FullSourceLoc XEL = X.getEndLocation().asLocation(); 290 FullSourceLoc YEL = Y.getEndLocation().asLocation(); 291 if (XEL != YEL) 292 return XEL.isBeforeInTranslationUnitThan(YEL); 293 return None; 294} 295 296static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, 297 const PathDiagnosticMacroPiece &Y) { 298 return comparePath(X.subPieces, Y.subPieces); 299} 300 301static Optional<bool> compareCall(const PathDiagnosticCallPiece &X, 302 const PathDiagnosticCallPiece &Y) { 303 FullSourceLoc X_CEL = X.callEnter.asLocation(); 304 FullSourceLoc Y_CEL = Y.callEnter.asLocation(); 305 if (X_CEL != Y_CEL) 306 return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); 307 FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); 308 FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); 309 if (X_CEWL != Y_CEWL) 310 return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); 311 FullSourceLoc X_CRL = X.callReturn.asLocation(); 312 FullSourceLoc Y_CRL = Y.callReturn.asLocation(); 313 if (X_CRL != Y_CRL) 314 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); 315 return comparePath(X.path, Y.path); 316} 317 318static Optional<bool> comparePiece(const PathDiagnosticPiece &X, 319 const PathDiagnosticPiece &Y) { 320 if (X.getKind() != Y.getKind()) 321 return X.getKind() < Y.getKind(); 322 323 FullSourceLoc XL = X.getLocation().asLocation(); 324 FullSourceLoc YL = Y.getLocation().asLocation(); 325 if (XL != YL) 326 return XL.isBeforeInTranslationUnitThan(YL); 327 328 if (X.getString() != Y.getString()) 329 return X.getString() < Y.getString(); 330 331 if (X.getRanges().size() != Y.getRanges().size()) 332 return X.getRanges().size() < Y.getRanges().size(); 333 334 const SourceManager &SM = XL.getManager(); 335 336 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { 337 SourceRange XR = X.getRanges()[i]; 338 SourceRange YR = Y.getRanges()[i]; 339 if (XR != YR) { 340 if (XR.getBegin() != YR.getBegin()) 341 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); 342 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); 343 } 344 } 345 346 switch (X.getKind()) { 347 case clang::ento::PathDiagnosticPiece::ControlFlow: 348 return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), 349 cast<PathDiagnosticControlFlowPiece>(Y)); 350 case clang::ento::PathDiagnosticPiece::Event: 351 return None; 352 case clang::ento::PathDiagnosticPiece::Macro: 353 return compareMacro(cast<PathDiagnosticMacroPiece>(X), 354 cast<PathDiagnosticMacroPiece>(Y)); 355 case clang::ento::PathDiagnosticPiece::Call: 356 return compareCall(cast<PathDiagnosticCallPiece>(X), 357 cast<PathDiagnosticCallPiece>(Y)); 358 } 359 llvm_unreachable("all cases handled"); 360} 361 362static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { 363 if (X.size() != Y.size()) 364 return X.size() < Y.size(); 365 366 PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); 367 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); 368 369 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { 370 Optional<bool> b = comparePiece(**X_I, **Y_I); 371 if (b.hasValue()) 372 return b.getValue(); 373 } 374 375 return None; 376} 377 378static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { 379 FullSourceLoc XL = X.getLocation().asLocation(); 380 FullSourceLoc YL = Y.getLocation().asLocation(); 381 if (XL != YL) 382 return XL.isBeforeInTranslationUnitThan(YL); 383 if (X.getBugType() != Y.getBugType()) 384 return X.getBugType() < Y.getBugType(); 385 if (X.getCategory() != Y.getCategory()) 386 return X.getCategory() < Y.getCategory(); 387 if (X.getVerboseDescription() != Y.getVerboseDescription()) 388 return X.getVerboseDescription() < Y.getVerboseDescription(); 389 if (X.getShortDescription() != Y.getShortDescription()) 390 return X.getShortDescription() < Y.getShortDescription(); 391 if (X.getDeclWithIssue() != Y.getDeclWithIssue()) { 392 const Decl *XD = X.getDeclWithIssue(); 393 if (!XD) 394 return true; 395 const Decl *YD = Y.getDeclWithIssue(); 396 if (!YD) 397 return false; 398 SourceLocation XDL = XD->getLocation(); 399 SourceLocation YDL = YD->getLocation(); 400 if (XDL != YDL) { 401 const SourceManager &SM = XL.getManager(); 402 return SM.isBeforeInTranslationUnit(XDL, YDL); 403 } 404 } 405 PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); 406 PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); 407 if (XE - XI != YE - YI) 408 return (XE - XI) < (YE - YI); 409 for ( ; XI != XE ; ++XI, ++YI) { 410 if (*XI != *YI) 411 return (*XI) < (*YI); 412 } 413 Optional<bool> b = comparePath(X.path, Y.path); 414 assert(b.hasValue()); 415 return b.getValue(); 416} 417 418namespace { 419struct CompareDiagnostics { 420 // Compare if 'X' is "<" than 'Y'. 421 bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { 422 if (X == Y) 423 return false; 424 return compare(*X, *Y); 425 } 426}; 427} 428 429void PathDiagnosticConsumer::FlushDiagnostics( 430 PathDiagnosticConsumer::FilesMade *Files) { 431 if (flushed) 432 return; 433 434 flushed = true; 435 436 std::vector<const PathDiagnostic *> BatchDiags; 437 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), 438 et = Diags.end(); it != et; ++it) { 439 const PathDiagnostic *D = &*it; 440 BatchDiags.push_back(D); 441 } 442 443 // Sort the diagnostics so that they are always emitted in a deterministic 444 // order. 445 if (!BatchDiags.empty()) 446 std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics()); 447 448 FlushDiagnosticsImpl(BatchDiags, Files); 449 450 // Delete the flushed diagnostics. 451 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), 452 et = BatchDiags.end(); it != et; ++it) { 453 const PathDiagnostic *D = *it; 454 delete D; 455 } 456 457 // Clear out the FoldingSet. 458 Diags.clear(); 459} 460 461void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 462 StringRef ConsumerName, 463 StringRef FileName) { 464 llvm::FoldingSetNodeID NodeID; 465 NodeID.Add(PD); 466 void *InsertPos; 467 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 468 if (!Entry) { 469 Entry = Alloc.Allocate<PDFileEntry>(); 470 Entry = new (Entry) PDFileEntry(NodeID); 471 InsertNode(Entry, InsertPos); 472 } 473 474 // Allocate persistent storage for the file name. 475 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); 476 memcpy(FileName_cstr, FileName.data(), FileName.size()); 477 478 Entry->files.push_back(std::make_pair(ConsumerName, 479 StringRef(FileName_cstr, 480 FileName.size()))); 481} 482 483PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 484PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 485 llvm::FoldingSetNodeID NodeID; 486 NodeID.Add(PD); 487 void *InsertPos; 488 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 489 if (!Entry) 490 return 0; 491 return &Entry->files; 492} 493 494//===----------------------------------------------------------------------===// 495// PathDiagnosticLocation methods. 496//===----------------------------------------------------------------------===// 497 498static SourceLocation getValidSourceLocation(const Stmt* S, 499 LocationOrAnalysisDeclContext LAC, 500 bool UseEnd = false) { 501 SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart(); 502 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " 503 "be passed to PathDiagnosticLocation upon creation."); 504 505 // S might be a temporary statement that does not have a location in the 506 // source code, so find an enclosing statement and use its location. 507 if (!L.isValid()) { 508 509 AnalysisDeclContext *ADC; 510 if (LAC.is<const LocationContext*>()) 511 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 512 else 513 ADC = LAC.get<AnalysisDeclContext*>(); 514 515 ParentMap &PM = ADC->getParentMap(); 516 517 const Stmt *Parent = S; 518 do { 519 Parent = PM.getParent(Parent); 520 521 // In rare cases, we have implicit top-level expressions, 522 // such as arguments for implicit member initializers. 523 // In this case, fall back to the start of the body (even if we were 524 // asked for the statement end location). 525 if (!Parent) { 526 const Stmt *Body = ADC->getBody(); 527 if (Body) 528 L = Body->getLocStart(); 529 else 530 L = ADC->getDecl()->getLocEnd(); 531 break; 532 } 533 534 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart(); 535 } while (!L.isValid()); 536 } 537 538 return L; 539} 540 541static PathDiagnosticLocation 542getLocationForCaller(const StackFrameContext *SFC, 543 const LocationContext *CallerCtx, 544 const SourceManager &SM) { 545 const CFGBlock &Block = *SFC->getCallSiteBlock(); 546 CFGElement Source = Block[SFC->getIndex()]; 547 548 switch (Source.getKind()) { 549 case CFGElement::Statement: 550 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), 551 SM, CallerCtx); 552 case CFGElement::Initializer: { 553 const CFGInitializer &Init = Source.castAs<CFGInitializer>(); 554 return PathDiagnosticLocation(Init.getInitializer()->getInit(), 555 SM, CallerCtx); 556 } 557 case CFGElement::AutomaticObjectDtor: { 558 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); 559 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 560 SM, CallerCtx); 561 } 562 case CFGElement::DeleteDtor: { 563 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); 564 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); 565 } 566 case CFGElement::BaseDtor: 567 case CFGElement::MemberDtor: { 568 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); 569 if (const Stmt *CallerBody = CallerInfo->getBody()) 570 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); 571 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); 572 } 573 case CFGElement::TemporaryDtor: 574 llvm_unreachable("not yet implemented!"); 575 } 576 577 llvm_unreachable("Unknown CFGElement kind"); 578} 579 580 581PathDiagnosticLocation 582 PathDiagnosticLocation::createBegin(const Decl *D, 583 const SourceManager &SM) { 584 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 585} 586 587PathDiagnosticLocation 588 PathDiagnosticLocation::createBegin(const Stmt *S, 589 const SourceManager &SM, 590 LocationOrAnalysisDeclContext LAC) { 591 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 592 SM, SingleLocK); 593} 594 595 596PathDiagnosticLocation 597PathDiagnosticLocation::createEnd(const Stmt *S, 598 const SourceManager &SM, 599 LocationOrAnalysisDeclContext LAC) { 600 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) 601 return createEndBrace(CS, SM); 602 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 603 SM, SingleLocK); 604} 605 606PathDiagnosticLocation 607 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 608 const SourceManager &SM) { 609 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 610} 611 612PathDiagnosticLocation 613 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 614 const SourceManager &SM) { 615 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 616} 617 618PathDiagnosticLocation 619 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 620 const SourceManager &SM) { 621 SourceLocation L = CS->getLBracLoc(); 622 return PathDiagnosticLocation(L, SM, SingleLocK); 623} 624 625PathDiagnosticLocation 626 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 627 const SourceManager &SM) { 628 SourceLocation L = CS->getRBracLoc(); 629 return PathDiagnosticLocation(L, SM, SingleLocK); 630} 631 632PathDiagnosticLocation 633 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 634 const SourceManager &SM) { 635 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 636 if (const CompoundStmt *CS = 637 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 638 if (!CS->body_empty()) { 639 SourceLocation Loc = (*CS->body_begin())->getLocStart(); 640 return PathDiagnosticLocation(Loc, SM, SingleLocK); 641 } 642 643 return PathDiagnosticLocation(); 644} 645 646PathDiagnosticLocation 647 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 648 const SourceManager &SM) { 649 SourceLocation L = LC->getDecl()->getBodyRBrace(); 650 return PathDiagnosticLocation(L, SM, SingleLocK); 651} 652 653PathDiagnosticLocation 654 PathDiagnosticLocation::create(const ProgramPoint& P, 655 const SourceManager &SMng) { 656 657 const Stmt* S = 0; 658 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { 659 const CFGBlock *BSrc = BE->getSrc(); 660 S = BSrc->getTerminatorCondition(); 661 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { 662 S = SP->getStmt(); 663 if (P.getAs<PostStmtPurgeDeadSymbols>()) 664 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); 665 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { 666 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), 667 SMng); 668 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { 669 return PathDiagnosticLocation(PIE->getLocation(), SMng); 670 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { 671 return getLocationForCaller(CE->getCalleeContext(), 672 CE->getLocationContext(), 673 SMng); 674 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { 675 return getLocationForCaller(CEE->getCalleeContext(), 676 CEE->getLocationContext(), 677 SMng); 678 } else { 679 llvm_unreachable("Unexpected ProgramPoint"); 680 } 681 682 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 683} 684 685const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { 686 ProgramPoint P = N->getLocation(); 687 if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) 688 return SP->getStmt(); 689 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) 690 return BE->getSrc()->getTerminator(); 691 if (Optional<CallEnter> CE = P.getAs<CallEnter>()) 692 return CE->getCallExpr(); 693 if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) 694 return CEE->getCalleeContext()->getCallSite(); 695 if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) 696 return PIPP->getInitializer()->getInit(); 697 698 return 0; 699} 700 701const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { 702 for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) { 703 if (const Stmt *S = getStmt(N)) { 704 // Check if the statement is '?' or '&&'/'||'. These are "merges", 705 // not actual statement points. 706 switch (S->getStmtClass()) { 707 case Stmt::ChooseExprClass: 708 case Stmt::BinaryConditionalOperatorClass: 709 case Stmt::ConditionalOperatorClass: 710 continue; 711 case Stmt::BinaryOperatorClass: { 712 BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); 713 if (Op == BO_LAnd || Op == BO_LOr) 714 continue; 715 break; 716 } 717 default: 718 break; 719 } 720 // We found the statement, so return it. 721 return S; 722 } 723 } 724 725 return 0; 726} 727 728PathDiagnosticLocation 729 PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, 730 const SourceManager &SM) { 731 assert(N && "Cannot create a location with a null node."); 732 const Stmt *S = getStmt(N); 733 734 if (!S) 735 S = getNextStmt(N); 736 737 if (S) { 738 ProgramPoint P = N->getLocation(); 739 const LocationContext *LC = N->getLocationContext(); 740 741 // For member expressions, return the location of the '.' or '->'. 742 if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) 743 return PathDiagnosticLocation::createMemberLoc(ME, SM); 744 745 // For binary operators, return the location of the operator. 746 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) 747 return PathDiagnosticLocation::createOperatorLoc(B, SM); 748 749 if (P.getAs<PostStmtPurgeDeadSymbols>()) 750 return PathDiagnosticLocation::createEnd(S, SM, LC); 751 752 if (S->getLocStart().isValid()) 753 return PathDiagnosticLocation(S, SM, LC); 754 return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); 755 } 756 757 return createDeclEnd(N->getLocationContext(), SM); 758} 759 760PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 761 const PathDiagnosticLocation &PDL) { 762 FullSourceLoc L = PDL.asLocation(); 763 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 764} 765 766FullSourceLoc 767 PathDiagnosticLocation::genLocation(SourceLocation L, 768 LocationOrAnalysisDeclContext LAC) const { 769 assert(isValid()); 770 // Note that we want a 'switch' here so that the compiler can warn us in 771 // case we add more cases. 772 switch (K) { 773 case SingleLocK: 774 case RangeK: 775 break; 776 case StmtK: 777 // Defensive checking. 778 if (!S) 779 break; 780 return FullSourceLoc(getValidSourceLocation(S, LAC), 781 const_cast<SourceManager&>(*SM)); 782 case DeclK: 783 // Defensive checking. 784 if (!D) 785 break; 786 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 787 } 788 789 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 790} 791 792PathDiagnosticRange 793 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 794 assert(isValid()); 795 // Note that we want a 'switch' here so that the compiler can warn us in 796 // case we add more cases. 797 switch (K) { 798 case SingleLocK: 799 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 800 case RangeK: 801 break; 802 case StmtK: { 803 const Stmt *S = asStmt(); 804 switch (S->getStmtClass()) { 805 default: 806 break; 807 case Stmt::DeclStmtClass: { 808 const DeclStmt *DS = cast<DeclStmt>(S); 809 if (DS->isSingleDecl()) { 810 // Should always be the case, but we'll be defensive. 811 return SourceRange(DS->getLocStart(), 812 DS->getSingleDecl()->getLocation()); 813 } 814 break; 815 } 816 // FIXME: Provide better range information for different 817 // terminators. 818 case Stmt::IfStmtClass: 819 case Stmt::WhileStmtClass: 820 case Stmt::DoStmtClass: 821 case Stmt::ForStmtClass: 822 case Stmt::ChooseExprClass: 823 case Stmt::IndirectGotoStmtClass: 824 case Stmt::SwitchStmtClass: 825 case Stmt::BinaryConditionalOperatorClass: 826 case Stmt::ConditionalOperatorClass: 827 case Stmt::ObjCForCollectionStmtClass: { 828 SourceLocation L = getValidSourceLocation(S, LAC); 829 return SourceRange(L, L); 830 } 831 } 832 SourceRange R = S->getSourceRange(); 833 if (R.isValid()) 834 return R; 835 break; 836 } 837 case DeclK: 838 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 839 return MD->getSourceRange(); 840 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 841 if (Stmt *Body = FD->getBody()) 842 return Body->getSourceRange(); 843 } 844 else { 845 SourceLocation L = D->getLocation(); 846 return PathDiagnosticRange(SourceRange(L, L), true); 847 } 848 } 849 850 return SourceRange(Loc,Loc); 851} 852 853void PathDiagnosticLocation::flatten() { 854 if (K == StmtK) { 855 K = RangeK; 856 S = 0; 857 D = 0; 858 } 859 else if (K == DeclK) { 860 K = SingleLocK; 861 S = 0; 862 D = 0; 863 } 864} 865 866//===----------------------------------------------------------------------===// 867// Manipulation of PathDiagnosticCallPieces. 868//===----------------------------------------------------------------------===// 869 870PathDiagnosticCallPiece * 871PathDiagnosticCallPiece::construct(const ExplodedNode *N, 872 const CallExitEnd &CE, 873 const SourceManager &SM) { 874 const Decl *caller = CE.getLocationContext()->getDecl(); 875 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 876 CE.getLocationContext(), 877 SM); 878 return new PathDiagnosticCallPiece(caller, pos); 879} 880 881PathDiagnosticCallPiece * 882PathDiagnosticCallPiece::construct(PathPieces &path, 883 const Decl *caller) { 884 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller); 885 path.clear(); 886 path.push_front(C); 887 return C; 888} 889 890void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 891 const SourceManager &SM) { 892 const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 893 Callee = CalleeCtx->getDecl(); 894 895 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 896 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 897} 898 899static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, 900 StringRef Prefix = StringRef()) { 901 if (!D->getIdentifier()) 902 return; 903 Out << Prefix << '\'' << *D << '\''; 904} 905 906static bool describeCodeDecl(raw_ostream &Out, const Decl *D, 907 bool ExtendedDescription, 908 StringRef Prefix = StringRef()) { 909 if (!D) 910 return false; 911 912 if (isa<BlockDecl>(D)) { 913 if (ExtendedDescription) 914 Out << Prefix << "anonymous block"; 915 return ExtendedDescription; 916 } 917 918 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { 919 Out << Prefix; 920 if (ExtendedDescription && !MD->isUserProvided()) { 921 if (MD->isExplicitlyDefaulted()) 922 Out << "defaulted "; 923 else 924 Out << "implicit "; 925 } 926 927 if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) { 928 if (CD->isDefaultConstructor()) 929 Out << "default "; 930 else if (CD->isCopyConstructor()) 931 Out << "copy "; 932 else if (CD->isMoveConstructor()) 933 Out << "move "; 934 935 Out << "constructor"; 936 describeClass(Out, MD->getParent(), " for "); 937 938 } else if (isa<CXXDestructorDecl>(MD)) { 939 if (!MD->isUserProvided()) { 940 Out << "destructor"; 941 describeClass(Out, MD->getParent(), " for "); 942 } else { 943 // Use ~Foo for explicitly-written destructors. 944 Out << "'" << *MD << "'"; 945 } 946 947 } else if (MD->isCopyAssignmentOperator()) { 948 Out << "copy assignment operator"; 949 describeClass(Out, MD->getParent(), " for "); 950 951 } else if (MD->isMoveAssignmentOperator()) { 952 Out << "move assignment operator"; 953 describeClass(Out, MD->getParent(), " for "); 954 955 } else { 956 if (MD->getParent()->getIdentifier()) 957 Out << "'" << *MD->getParent() << "::" << *MD << "'"; 958 else 959 Out << "'" << *MD << "'"; 960 } 961 962 return true; 963 } 964 965 Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\''; 966 return true; 967} 968 969IntrusiveRefCntPtr<PathDiagnosticEventPiece> 970PathDiagnosticCallPiece::getCallEnterEvent() const { 971 if (!Callee) 972 return 0; 973 974 SmallString<256> buf; 975 llvm::raw_svector_ostream Out(buf); 976 977 Out << "Calling "; 978 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); 979 980 assert(callEnter.asLocation().isValid()); 981 return new PathDiagnosticEventPiece(callEnter, Out.str()); 982} 983 984IntrusiveRefCntPtr<PathDiagnosticEventPiece> 985PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 986 if (!callEnterWithin.asLocation().isValid()) 987 return 0; 988 if (Callee->isImplicit() || !Callee->hasBody()) 989 return 0; 990 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) 991 if (MD->isDefaulted()) 992 return 0; 993 994 SmallString<256> buf; 995 llvm::raw_svector_ostream Out(buf); 996 997 Out << "Entered call"; 998 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); 999 1000 return new PathDiagnosticEventPiece(callEnterWithin, Out.str()); 1001} 1002 1003IntrusiveRefCntPtr<PathDiagnosticEventPiece> 1004PathDiagnosticCallPiece::getCallExitEvent() const { 1005 if (NoExit) 1006 return 0; 1007 1008 SmallString<256> buf; 1009 llvm::raw_svector_ostream Out(buf); 1010 1011 if (!CallStackMessage.empty()) { 1012 Out << CallStackMessage; 1013 } else { 1014 bool DidDescribe = describeCodeDecl(Out, Callee, 1015 /*ExtendedDescription=*/false, 1016 "Returning from "); 1017 if (!DidDescribe) 1018 Out << "Returning to caller"; 1019 } 1020 1021 assert(callReturn.asLocation().isValid()); 1022 return new PathDiagnosticEventPiece(callReturn, Out.str()); 1023} 1024 1025static void compute_path_size(const PathPieces &pieces, unsigned &size) { 1026 for (PathPieces::const_iterator it = pieces.begin(), 1027 et = pieces.end(); it != et; ++it) { 1028 const PathDiagnosticPiece *piece = it->getPtr(); 1029 if (const PathDiagnosticCallPiece *cp = 1030 dyn_cast<PathDiagnosticCallPiece>(piece)) { 1031 compute_path_size(cp->path, size); 1032 } 1033 else 1034 ++size; 1035 } 1036} 1037 1038unsigned PathDiagnostic::full_size() { 1039 unsigned size = 0; 1040 compute_path_size(path, size); 1041 return size; 1042} 1043 1044//===----------------------------------------------------------------------===// 1045// FoldingSet profiling methods. 1046//===----------------------------------------------------------------------===// 1047 1048void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 1049 ID.AddInteger(Range.getBegin().getRawEncoding()); 1050 ID.AddInteger(Range.getEnd().getRawEncoding()); 1051 ID.AddInteger(Loc.getRawEncoding()); 1052 return; 1053} 1054 1055void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1056 ID.AddInteger((unsigned) getKind()); 1057 ID.AddString(str); 1058 // FIXME: Add profiling support for code hints. 1059 ID.AddInteger((unsigned) getDisplayHint()); 1060 ArrayRef<SourceRange> Ranges = getRanges(); 1061 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 1062 I != E; ++I) { 1063 ID.AddInteger(I->getBegin().getRawEncoding()); 1064 ID.AddInteger(I->getEnd().getRawEncoding()); 1065 } 1066} 1067 1068void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1069 PathDiagnosticPiece::Profile(ID); 1070 for (PathPieces::const_iterator it = path.begin(), 1071 et = path.end(); it != et; ++it) { 1072 ID.Add(**it); 1073 } 1074} 1075 1076void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1077 PathDiagnosticPiece::Profile(ID); 1078 ID.Add(Pos); 1079} 1080 1081void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1082 PathDiagnosticPiece::Profile(ID); 1083 for (const_iterator I = begin(), E = end(); I != E; ++I) 1084 ID.Add(*I); 1085} 1086 1087void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1088 PathDiagnosticSpotPiece::Profile(ID); 1089 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 1090 I != E; ++I) 1091 ID.Add(**I); 1092} 1093 1094void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 1095 ID.Add(getLocation()); 1096 ID.AddString(BugType); 1097 ID.AddString(VerboseDesc); 1098 ID.AddString(Category); 1099} 1100 1101void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 1102 Profile(ID); 1103 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) 1104 ID.Add(**I); 1105 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 1106 ID.AddString(*I); 1107} 1108 1109StackHintGenerator::~StackHintGenerator() {} 1110 1111std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ 1112 ProgramPoint P = N->getLocation(); 1113 CallExitEnd CExit = P.castAs<CallExitEnd>(); 1114 1115 // FIXME: Use CallEvent to abstract this over all calls. 1116 const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); 1117 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); 1118 if (!CE) 1119 return ""; 1120 1121 if (!N) 1122 return getMessageForSymbolNotFound(); 1123 1124 // Check if one of the parameters are set to the interesting symbol. 1125 ProgramStateRef State = N->getState(); 1126 const LocationContext *LCtx = N->getLocationContext(); 1127 unsigned ArgIndex = 0; 1128 for (CallExpr::const_arg_iterator I = CE->arg_begin(), 1129 E = CE->arg_end(); I != E; ++I, ++ArgIndex){ 1130 SVal SV = State->getSVal(*I, LCtx); 1131 1132 // Check if the variable corresponding to the symbol is passed by value. 1133 SymbolRef AS = SV.getAsLocSymbol(); 1134 if (AS == Sym) { 1135 return getMessageForArg(*I, ArgIndex); 1136 } 1137 1138 // Check if the parameter is a pointer to the symbol. 1139 if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { 1140 SVal PSV = State->getSVal(Reg->getRegion()); 1141 SymbolRef AS = PSV.getAsLocSymbol(); 1142 if (AS == Sym) { 1143 return getMessageForArg(*I, ArgIndex); 1144 } 1145 } 1146 } 1147 1148 // Check if we are returning the interesting symbol. 1149 SVal SV = State->getSVal(CE, LCtx); 1150 SymbolRef RetSym = SV.getAsLocSymbol(); 1151 if (RetSym == Sym) { 1152 return getMessageForReturn(CE); 1153 } 1154 1155 return getMessageForSymbolNotFound(); 1156} 1157 1158std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, 1159 unsigned ArgIndex) { 1160 // Printed parameters start at 1, not 0. 1161 ++ArgIndex; 1162 1163 SmallString<200> buf; 1164 llvm::raw_svector_ostream os(buf); 1165 1166 os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) 1167 << " parameter"; 1168 1169 return os.str(); 1170} 1171