1218887Sdim//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===// 2218887Sdim// 3218887Sdim// The LLVM Compiler Infrastructure 4218887Sdim// 5218887Sdim// This file is distributed under the University of Illinois Open Source 6218887Sdim// License. See LICENSE.TXT for details. 7218887Sdim// 8218887Sdim//===----------------------------------------------------------------------===// 9218887Sdim// 10218887Sdim// This file defines the PathDiagnostic-related interfaces. 11218887Sdim// 12218887Sdim//===----------------------------------------------------------------------===// 13218887Sdim 14218887Sdim#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 15218887Sdim#include "clang/AST/Decl.h" 16239462Sdim#include "clang/AST/DeclCXX.h" 17218887Sdim#include "clang/AST/DeclObjC.h" 18249423Sdim#include "clang/AST/Expr.h" 19226633Sdim#include "clang/AST/ParentMap.h" 20218887Sdim#include "clang/AST/StmtCXX.h" 21249423Sdim#include "clang/Basic/SourceManager.h" 22249423Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 23218887Sdim#include "llvm/ADT/SmallString.h" 24243830Sdim#include "llvm/ADT/StringExtras.h" 25249423Sdim#include "llvm/Support/raw_ostream.h" 26218887Sdim 27218887Sdimusing namespace clang; 28218887Sdimusing namespace ento; 29218887Sdim 30218887Sdimbool PathDiagnosticMacroPiece::containsEvent() const { 31234353Sdim for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 32234353Sdim I!=E; ++I) { 33218887Sdim if (isa<PathDiagnosticEventPiece>(*I)) 34218887Sdim return true; 35218887Sdim if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I)) 36218887Sdim if (MP->containsEvent()) 37218887Sdim return true; 38218887Sdim } 39218887Sdim return false; 40218887Sdim} 41218887Sdim 42226633Sdimstatic StringRef StripTrailingDots(StringRef s) { 43226633Sdim for (StringRef::size_type i = s.size(); i != 0; --i) 44218887Sdim if (s[i - 1] != '.') 45218887Sdim return s.substr(0, i); 46218887Sdim return ""; 47218887Sdim} 48218887Sdim 49226633SdimPathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 50218887Sdim Kind k, DisplayHint hint) 51263508Sdim : str(StripTrailingDots(s)), kind(k), Hint(hint), 52263508Sdim LastInMainSourceFile(false) {} 53218887Sdim 54218887SdimPathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 55263508Sdim : kind(k), Hint(hint), LastInMainSourceFile(false) {} 56218887Sdim 57218887SdimPathDiagnosticPiece::~PathDiagnosticPiece() {} 58218887SdimPathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 59234353SdimPathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} 60218887SdimPathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 61234353SdimPathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} 62218887Sdim 63218887Sdim 64234353SdimPathPieces::~PathPieces() {} 65239462Sdim 66239462Sdimvoid PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, 67239462Sdim bool ShouldFlattenMacros) const { 68239462Sdim for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 69239462Sdim PathDiagnosticPiece *Piece = I->getPtr(); 70239462Sdim 71239462Sdim switch (Piece->getKind()) { 72239462Sdim case PathDiagnosticPiece::Call: { 73239462Sdim PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece); 74239462Sdim IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter = 75239462Sdim Call->getCallEnterEvent(); 76239462Sdim if (CallEnter) 77239462Sdim Current.push_back(CallEnter); 78239462Sdim Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros); 79239462Sdim IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = 80239462Sdim Call->getCallExitEvent(); 81239462Sdim if (callExit) 82239462Sdim Current.push_back(callExit); 83239462Sdim break; 84239462Sdim } 85239462Sdim case PathDiagnosticPiece::Macro: { 86239462Sdim PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece); 87239462Sdim if (ShouldFlattenMacros) { 88239462Sdim Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 89239462Sdim } else { 90239462Sdim Current.push_back(Piece); 91239462Sdim PathPieces NewPath; 92239462Sdim Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 93239462Sdim // FIXME: This probably shouldn't mutate the original path piece. 94239462Sdim Macro->subPieces = NewPath; 95239462Sdim } 96239462Sdim break; 97239462Sdim } 98239462Sdim case PathDiagnosticPiece::Event: 99239462Sdim case PathDiagnosticPiece::ControlFlow: 100239462Sdim Current.push_back(Piece); 101239462Sdim break; 102239462Sdim } 103239462Sdim } 104239462Sdim} 105239462Sdim 106239462Sdim 107234353SdimPathDiagnostic::~PathDiagnostic() {} 108218887Sdim 109234353SdimPathDiagnostic::PathDiagnostic(const Decl *declWithIssue, 110243830Sdim StringRef bugtype, StringRef verboseDesc, 111249423Sdim StringRef shortDesc, StringRef category, 112249423Sdim PathDiagnosticLocation LocationToUnique, 113249423Sdim const Decl *DeclToUnique) 114234353Sdim : DeclWithIssue(declWithIssue), 115234353Sdim BugType(StripTrailingDots(bugtype)), 116243830Sdim VerboseDesc(StripTrailingDots(verboseDesc)), 117243830Sdim ShortDesc(StripTrailingDots(shortDesc)), 118234353Sdim Category(StripTrailingDots(category)), 119249423Sdim UniqueingLoc(LocationToUnique), 120249423Sdim UniqueingDecl(DeclToUnique), 121234353Sdim path(pathImpl) {} 122234353Sdim 123263508Sdimstatic PathDiagnosticCallPiece * 124263508SdimgetFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, 125263508Sdim const SourceManager &SMgr) { 126263508Sdim SourceLocation CallLoc = CP->callEnter.asLocation(); 127263508Sdim 128263508Sdim // If the call is within a macro, don't do anything (for now). 129263508Sdim if (CallLoc.isMacroID()) 130263508Sdim return 0; 131263508Sdim 132263508Sdim assert(SMgr.isInMainFile(CallLoc) && 133263508Sdim "The call piece should be in the main file."); 134263508Sdim 135263508Sdim // Check if CP represents a path through a function outside of the main file. 136263508Sdim if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation())) 137263508Sdim return CP; 138263508Sdim 139263508Sdim const PathPieces &Path = CP->path; 140263508Sdim if (Path.empty()) 141263508Sdim return 0; 142263508Sdim 143263508Sdim // Check if the last piece in the callee path is a call to a function outside 144263508Sdim // of the main file. 145263508Sdim if (PathDiagnosticCallPiece *CPInner = 146263508Sdim dyn_cast<PathDiagnosticCallPiece>(Path.back())) { 147263508Sdim return getFirstStackedCallToHeaderFile(CPInner, SMgr); 148263508Sdim } 149263508Sdim 150263508Sdim // Otherwise, the last piece is in the main file. 151263508Sdim return 0; 152263508Sdim} 153263508Sdim 154263508Sdimvoid PathDiagnostic::resetDiagnosticLocationToMainFile() { 155263508Sdim if (path.empty()) 156263508Sdim return; 157263508Sdim 158263508Sdim PathDiagnosticPiece *LastP = path.back().getPtr(); 159263508Sdim assert(LastP); 160263508Sdim const SourceManager &SMgr = LastP->getLocation().getManager(); 161263508Sdim 162263508Sdim // We only need to check if the report ends inside headers, if the last piece 163263508Sdim // is a call piece. 164263508Sdim if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) { 165263508Sdim CP = getFirstStackedCallToHeaderFile(CP, SMgr); 166263508Sdim if (CP) { 167263508Sdim // Mark the piece. 168263508Sdim CP->setAsLastInMainSourceFile(); 169263508Sdim 170263508Sdim // Update the path diagnostic message. 171263508Sdim const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee()); 172263508Sdim if (ND) { 173263508Sdim SmallString<200> buf; 174263508Sdim llvm::raw_svector_ostream os(buf); 175263508Sdim os << " (within a call to '" << ND->getDeclName() << "')"; 176263508Sdim appendToDesc(os.str()); 177263508Sdim } 178263508Sdim 179263508Sdim // Reset the report containing declaration and location. 180263508Sdim DeclWithIssue = CP->getCaller(); 181263508Sdim Loc = CP->getLocation(); 182263508Sdim 183263508Sdim return; 184263508Sdim } 185263508Sdim } 186263508Sdim} 187263508Sdim 188234353Sdimvoid PathDiagnosticConsumer::anchor() { } 189234353Sdim 190234353SdimPathDiagnosticConsumer::~PathDiagnosticConsumer() { 191234353Sdim // Delete the contents of the FoldingSet if it isn't empty already. 192234353Sdim for (llvm::FoldingSet<PathDiagnostic>::iterator it = 193234353Sdim Diags.begin(), et = Diags.end() ; it != et ; ++it) { 194234353Sdim delete &*it; 195234353Sdim } 196218887Sdim} 197218887Sdim 198234353Sdimvoid PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { 199249423Sdim OwningPtr<PathDiagnostic> OwningD(D); 200234353Sdim 201234353Sdim if (!D || D->path.empty()) 202234353Sdim return; 203234353Sdim 204234353Sdim // We need to flatten the locations (convert Stmt* to locations) because 205234353Sdim // the referenced statements may be freed by the time the diagnostics 206234353Sdim // are emitted. 207234353Sdim D->flattenLocations(); 208218887Sdim 209234353Sdim // If the PathDiagnosticConsumer does not support diagnostics that 210234353Sdim // cross file boundaries, prune out such diagnostics now. 211234353Sdim if (!supportsCrossFileDiagnostics()) { 212234353Sdim // Verify that the entire path is from the same FileID. 213234353Sdim FileID FID; 214234353Sdim const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager(); 215249423Sdim SmallVector<const PathPieces *, 5> WorkList; 216234353Sdim WorkList.push_back(&D->path); 217218887Sdim 218234353Sdim while (!WorkList.empty()) { 219263508Sdim const PathPieces &path = *WorkList.pop_back_val(); 220234353Sdim 221263508Sdim for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; 222263508Sdim ++I) { 223234353Sdim const PathDiagnosticPiece *piece = I->getPtr(); 224234353Sdim FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 225234353Sdim 226234353Sdim if (FID.isInvalid()) { 227234353Sdim FID = SMgr.getFileID(L); 228234353Sdim } else if (SMgr.getFileID(L) != FID) 229234353Sdim return; // FIXME: Emit a warning? 230234353Sdim 231234353Sdim // Check the source ranges. 232239462Sdim ArrayRef<SourceRange> Ranges = piece->getRanges(); 233239462Sdim for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), 234239462Sdim E = Ranges.end(); I != E; ++I) { 235239462Sdim SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); 236234353Sdim if (!L.isFileID() || SMgr.getFileID(L) != FID) 237234353Sdim return; // FIXME: Emit a warning? 238239462Sdim L = SMgr.getExpansionLoc(I->getEnd()); 239234353Sdim if (!L.isFileID() || SMgr.getFileID(L) != FID) 240234353Sdim return; // FIXME: Emit a warning? 241234353Sdim } 242234353Sdim 243234353Sdim if (const PathDiagnosticCallPiece *call = 244234353Sdim dyn_cast<PathDiagnosticCallPiece>(piece)) { 245234353Sdim WorkList.push_back(&call->path); 246234353Sdim } 247234353Sdim else if (const PathDiagnosticMacroPiece *macro = 248234353Sdim dyn_cast<PathDiagnosticMacroPiece>(piece)) { 249234353Sdim WorkList.push_back(¯o->subPieces); 250234353Sdim } 251234353Sdim } 252234353Sdim } 253234353Sdim 254234353Sdim if (FID.isInvalid()) 255234353Sdim return; // FIXME: Emit a warning? 256234353Sdim } 257234353Sdim 258234353Sdim // Profile the node to see if we already have something matching it 259234353Sdim llvm::FoldingSetNodeID profile; 260234353Sdim D->Profile(profile); 261234353Sdim void *InsertPos = 0; 262234353Sdim 263234353Sdim if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 264234353Sdim // Keep the PathDiagnostic with the shorter path. 265239462Sdim // Note, the enclosing routine is called in deterministic order, so the 266239462Sdim // results will be consistent between runs (no reason to break ties if the 267239462Sdim // size is the same). 268234353Sdim const unsigned orig_size = orig->full_size(); 269234353Sdim const unsigned new_size = D->full_size(); 270239462Sdim if (orig_size <= new_size) 271239462Sdim return; 272234353Sdim 273243830Sdim assert(orig != D); 274234353Sdim Diags.RemoveNode(orig); 275234353Sdim delete orig; 276234353Sdim } 277234353Sdim 278234353Sdim Diags.InsertNode(OwningD.take()); 279218887Sdim} 280218887Sdim 281249423Sdimstatic Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); 282249423Sdimstatic Optional<bool> 283243830SdimcompareControlFlow(const PathDiagnosticControlFlowPiece &X, 284243830Sdim const PathDiagnosticControlFlowPiece &Y) { 285243830Sdim FullSourceLoc XSL = X.getStartLocation().asLocation(); 286243830Sdim FullSourceLoc YSL = Y.getStartLocation().asLocation(); 287243830Sdim if (XSL != YSL) 288243830Sdim return XSL.isBeforeInTranslationUnitThan(YSL); 289243830Sdim FullSourceLoc XEL = X.getEndLocation().asLocation(); 290243830Sdim FullSourceLoc YEL = Y.getEndLocation().asLocation(); 291243830Sdim if (XEL != YEL) 292243830Sdim return XEL.isBeforeInTranslationUnitThan(YEL); 293249423Sdim return None; 294243830Sdim} 295218887Sdim 296249423Sdimstatic Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, 297249423Sdim const PathDiagnosticMacroPiece &Y) { 298243830Sdim return comparePath(X.subPieces, Y.subPieces); 299243830Sdim} 300243830Sdim 301249423Sdimstatic Optional<bool> compareCall(const PathDiagnosticCallPiece &X, 302249423Sdim const PathDiagnosticCallPiece &Y) { 303243830Sdim FullSourceLoc X_CEL = X.callEnter.asLocation(); 304243830Sdim FullSourceLoc Y_CEL = Y.callEnter.asLocation(); 305243830Sdim if (X_CEL != Y_CEL) 306243830Sdim return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); 307243830Sdim FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); 308243830Sdim FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); 309243830Sdim if (X_CEWL != Y_CEWL) 310243830Sdim return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); 311243830Sdim FullSourceLoc X_CRL = X.callReturn.asLocation(); 312243830Sdim FullSourceLoc Y_CRL = Y.callReturn.asLocation(); 313243830Sdim if (X_CRL != Y_CRL) 314243830Sdim return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); 315243830Sdim return comparePath(X.path, Y.path); 316243830Sdim} 317243830Sdim 318249423Sdimstatic Optional<bool> comparePiece(const PathDiagnosticPiece &X, 319249423Sdim const PathDiagnosticPiece &Y) { 320243830Sdim if (X.getKind() != Y.getKind()) 321243830Sdim return X.getKind() < Y.getKind(); 322243830Sdim 323243830Sdim FullSourceLoc XL = X.getLocation().asLocation(); 324243830Sdim FullSourceLoc YL = Y.getLocation().asLocation(); 325243830Sdim if (XL != YL) 326243830Sdim return XL.isBeforeInTranslationUnitThan(YL); 327243830Sdim 328243830Sdim if (X.getString() != Y.getString()) 329243830Sdim return X.getString() < Y.getString(); 330243830Sdim 331243830Sdim if (X.getRanges().size() != Y.getRanges().size()) 332243830Sdim return X.getRanges().size() < Y.getRanges().size(); 333243830Sdim 334243830Sdim const SourceManager &SM = XL.getManager(); 335243830Sdim 336243830Sdim for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { 337243830Sdim SourceRange XR = X.getRanges()[i]; 338243830Sdim SourceRange YR = Y.getRanges()[i]; 339243830Sdim if (XR != YR) { 340243830Sdim if (XR.getBegin() != YR.getBegin()) 341243830Sdim return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); 342243830Sdim return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); 343243830Sdim } 344243830Sdim } 345243830Sdim 346243830Sdim switch (X.getKind()) { 347243830Sdim case clang::ento::PathDiagnosticPiece::ControlFlow: 348243830Sdim return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), 349243830Sdim cast<PathDiagnosticControlFlowPiece>(Y)); 350243830Sdim case clang::ento::PathDiagnosticPiece::Event: 351249423Sdim return None; 352243830Sdim case clang::ento::PathDiagnosticPiece::Macro: 353243830Sdim return compareMacro(cast<PathDiagnosticMacroPiece>(X), 354243830Sdim cast<PathDiagnosticMacroPiece>(Y)); 355243830Sdim case clang::ento::PathDiagnosticPiece::Call: 356243830Sdim return compareCall(cast<PathDiagnosticCallPiece>(X), 357243830Sdim cast<PathDiagnosticCallPiece>(Y)); 358243830Sdim } 359243830Sdim llvm_unreachable("all cases handled"); 360243830Sdim} 361243830Sdim 362249423Sdimstatic Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { 363243830Sdim if (X.size() != Y.size()) 364243830Sdim return X.size() < Y.size(); 365251662Sdim 366251662Sdim PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); 367251662Sdim PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); 368251662Sdim 369251662Sdim for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { 370251662Sdim Optional<bool> b = comparePiece(**X_I, **Y_I); 371243830Sdim if (b.hasValue()) 372243830Sdim return b.getValue(); 373243830Sdim } 374251662Sdim 375249423Sdim return None; 376243830Sdim} 377243830Sdim 378243830Sdimstatic bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { 379243830Sdim FullSourceLoc XL = X.getLocation().asLocation(); 380243830Sdim FullSourceLoc YL = Y.getLocation().asLocation(); 381243830Sdim if (XL != YL) 382243830Sdim return XL.isBeforeInTranslationUnitThan(YL); 383243830Sdim if (X.getBugType() != Y.getBugType()) 384243830Sdim return X.getBugType() < Y.getBugType(); 385243830Sdim if (X.getCategory() != Y.getCategory()) 386243830Sdim return X.getCategory() < Y.getCategory(); 387243830Sdim if (X.getVerboseDescription() != Y.getVerboseDescription()) 388243830Sdim return X.getVerboseDescription() < Y.getVerboseDescription(); 389243830Sdim if (X.getShortDescription() != Y.getShortDescription()) 390243830Sdim return X.getShortDescription() < Y.getShortDescription(); 391243830Sdim if (X.getDeclWithIssue() != Y.getDeclWithIssue()) { 392243830Sdim const Decl *XD = X.getDeclWithIssue(); 393243830Sdim if (!XD) 394243830Sdim return true; 395243830Sdim const Decl *YD = Y.getDeclWithIssue(); 396243830Sdim if (!YD) 397243830Sdim return false; 398243830Sdim SourceLocation XDL = XD->getLocation(); 399243830Sdim SourceLocation YDL = YD->getLocation(); 400243830Sdim if (XDL != YDL) { 401243830Sdim const SourceManager &SM = XL.getManager(); 402243830Sdim return SM.isBeforeInTranslationUnit(XDL, YDL); 403243830Sdim } 404243830Sdim } 405243830Sdim PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); 406243830Sdim PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); 407243830Sdim if (XE - XI != YE - YI) 408243830Sdim return (XE - XI) < (YE - YI); 409243830Sdim for ( ; XI != XE ; ++XI, ++YI) { 410243830Sdim if (*XI != *YI) 411243830Sdim return (*XI) < (*YI); 412243830Sdim } 413249423Sdim Optional<bool> b = comparePath(X.path, Y.path); 414243830Sdim assert(b.hasValue()); 415243830Sdim return b.getValue(); 416243830Sdim} 417243830Sdim 418234353Sdimnamespace { 419234353Sdimstruct CompareDiagnostics { 420234353Sdim // Compare if 'X' is "<" than 'Y'. 421234353Sdim bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { 422243830Sdim if (X == Y) 423234353Sdim return false; 424243830Sdim return compare(*X, *Y); 425243830Sdim } 426243830Sdim}; 427234353Sdim} 428218887Sdim 429239462Sdimvoid PathDiagnosticConsumer::FlushDiagnostics( 430239462Sdim PathDiagnosticConsumer::FilesMade *Files) { 431234353Sdim if (flushed) 432234353Sdim return; 433234353Sdim 434234353Sdim flushed = true; 435234353Sdim 436234353Sdim std::vector<const PathDiagnostic *> BatchDiags; 437234353Sdim for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), 438234353Sdim et = Diags.end(); it != et; ++it) { 439243830Sdim const PathDiagnostic *D = &*it; 440243830Sdim BatchDiags.push_back(D); 441234353Sdim } 442234353Sdim 443234353Sdim // Sort the diagnostics so that they are always emitted in a deterministic 444234353Sdim // order. 445234353Sdim if (!BatchDiags.empty()) 446234353Sdim std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics()); 447234353Sdim 448234353Sdim FlushDiagnosticsImpl(BatchDiags, Files); 449234353Sdim 450234353Sdim // Delete the flushed diagnostics. 451234353Sdim for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), 452234353Sdim et = BatchDiags.end(); it != et; ++it) { 453234353Sdim const PathDiagnostic *D = *it; 454234353Sdim delete D; 455234353Sdim } 456243830Sdim 457243830Sdim // Clear out the FoldingSet. 458243830Sdim Diags.clear(); 459226633Sdim} 460218887Sdim 461243830Sdimvoid PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 462243830Sdim StringRef ConsumerName, 463243830Sdim StringRef FileName) { 464243830Sdim llvm::FoldingSetNodeID NodeID; 465243830Sdim NodeID.Add(PD); 466243830Sdim void *InsertPos; 467243830Sdim PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 468243830Sdim if (!Entry) { 469243830Sdim Entry = Alloc.Allocate<PDFileEntry>(); 470243830Sdim Entry = new (Entry) PDFileEntry(NodeID); 471243830Sdim InsertNode(Entry, InsertPos); 472243830Sdim } 473243830Sdim 474243830Sdim // Allocate persistent storage for the file name. 475243830Sdim char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); 476243830Sdim memcpy(FileName_cstr, FileName.data(), FileName.size()); 477243830Sdim 478243830Sdim Entry->files.push_back(std::make_pair(ConsumerName, 479243830Sdim StringRef(FileName_cstr, 480243830Sdim FileName.size()))); 481243830Sdim} 482243830Sdim 483243830SdimPathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 484243830SdimPathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 485243830Sdim llvm::FoldingSetNodeID NodeID; 486243830Sdim NodeID.Add(PD); 487243830Sdim void *InsertPos; 488243830Sdim PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 489243830Sdim if (!Entry) 490243830Sdim return 0; 491243830Sdim return &Entry->files; 492243830Sdim} 493243830Sdim 494226633Sdim//===----------------------------------------------------------------------===// 495226633Sdim// PathDiagnosticLocation methods. 496226633Sdim//===----------------------------------------------------------------------===// 497218887Sdim 498226633Sdimstatic SourceLocation getValidSourceLocation(const Stmt* S, 499239462Sdim LocationOrAnalysisDeclContext LAC, 500239462Sdim bool UseEnd = false) { 501239462Sdim SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart(); 502234353Sdim assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " 503226633Sdim "be passed to PathDiagnosticLocation upon creation."); 504218887Sdim 505226633Sdim // S might be a temporary statement that does not have a location in the 506239462Sdim // source code, so find an enclosing statement and use its location. 507226633Sdim if (!L.isValid()) { 508226633Sdim 509239462Sdim AnalysisDeclContext *ADC; 510226633Sdim if (LAC.is<const LocationContext*>()) 511239462Sdim ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 512226633Sdim else 513239462Sdim ADC = LAC.get<AnalysisDeclContext*>(); 514226633Sdim 515239462Sdim ParentMap &PM = ADC->getParentMap(); 516239462Sdim 517239462Sdim const Stmt *Parent = S; 518239462Sdim do { 519239462Sdim Parent = PM.getParent(Parent); 520239462Sdim 521239462Sdim // In rare cases, we have implicit top-level expressions, 522239462Sdim // such as arguments for implicit member initializers. 523239462Sdim // In this case, fall back to the start of the body (even if we were 524239462Sdim // asked for the statement end location). 525239462Sdim if (!Parent) { 526239462Sdim const Stmt *Body = ADC->getBody(); 527239462Sdim if (Body) 528239462Sdim L = Body->getLocStart(); 529239462Sdim else 530239462Sdim L = ADC->getDecl()->getLocEnd(); 531239462Sdim break; 532239462Sdim } 533239462Sdim 534239462Sdim L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart(); 535239462Sdim } while (!L.isValid()); 536218887Sdim } 537218887Sdim 538226633Sdim return L; 539226633Sdim} 540218887Sdim 541239462Sdimstatic PathDiagnosticLocation 542239462SdimgetLocationForCaller(const StackFrameContext *SFC, 543239462Sdim const LocationContext *CallerCtx, 544239462Sdim const SourceManager &SM) { 545239462Sdim const CFGBlock &Block = *SFC->getCallSiteBlock(); 546239462Sdim CFGElement Source = Block[SFC->getIndex()]; 547239462Sdim 548239462Sdim switch (Source.getKind()) { 549239462Sdim case CFGElement::Statement: 550249423Sdim return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), 551239462Sdim SM, CallerCtx); 552239462Sdim case CFGElement::Initializer: { 553249423Sdim const CFGInitializer &Init = Source.castAs<CFGInitializer>(); 554239462Sdim return PathDiagnosticLocation(Init.getInitializer()->getInit(), 555239462Sdim SM, CallerCtx); 556239462Sdim } 557239462Sdim case CFGElement::AutomaticObjectDtor: { 558249423Sdim const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); 559239462Sdim return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 560239462Sdim SM, CallerCtx); 561239462Sdim } 562263508Sdim case CFGElement::DeleteDtor: { 563263508Sdim const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); 564263508Sdim return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); 565263508Sdim } 566239462Sdim case CFGElement::BaseDtor: 567239462Sdim case CFGElement::MemberDtor: { 568239462Sdim const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); 569239462Sdim if (const Stmt *CallerBody = CallerInfo->getBody()) 570239462Sdim return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); 571239462Sdim return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); 572239462Sdim } 573239462Sdim case CFGElement::TemporaryDtor: 574239462Sdim llvm_unreachable("not yet implemented!"); 575239462Sdim } 576239462Sdim 577239462Sdim llvm_unreachable("Unknown CFGElement kind"); 578239462Sdim} 579239462Sdim 580239462Sdim 581226633SdimPathDiagnosticLocation 582226633Sdim PathDiagnosticLocation::createBegin(const Decl *D, 583226633Sdim const SourceManager &SM) { 584226633Sdim return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 585226633Sdim} 586218887Sdim 587226633SdimPathDiagnosticLocation 588226633Sdim PathDiagnosticLocation::createBegin(const Stmt *S, 589226633Sdim const SourceManager &SM, 590234353Sdim LocationOrAnalysisDeclContext LAC) { 591226633Sdim return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 592226633Sdim SM, SingleLocK); 593226633Sdim} 594218887Sdim 595239462Sdim 596226633SdimPathDiagnosticLocation 597239462SdimPathDiagnosticLocation::createEnd(const Stmt *S, 598239462Sdim const SourceManager &SM, 599239462Sdim LocationOrAnalysisDeclContext LAC) { 600239462Sdim if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) 601239462Sdim return createEndBrace(CS, SM); 602239462Sdim return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 603239462Sdim SM, SingleLocK); 604239462Sdim} 605239462Sdim 606239462SdimPathDiagnosticLocation 607226633Sdim PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 608226633Sdim const SourceManager &SM) { 609226633Sdim return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 610218887Sdim} 611218887Sdim 612226633SdimPathDiagnosticLocation 613226633Sdim PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 614226633Sdim const SourceManager &SM) { 615226633Sdim return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 616226633Sdim} 617218887Sdim 618226633SdimPathDiagnosticLocation 619226633Sdim PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 620226633Sdim const SourceManager &SM) { 621226633Sdim SourceLocation L = CS->getLBracLoc(); 622226633Sdim return PathDiagnosticLocation(L, SM, SingleLocK); 623226633Sdim} 624226633Sdim 625226633SdimPathDiagnosticLocation 626226633Sdim PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 627226633Sdim const SourceManager &SM) { 628226633Sdim SourceLocation L = CS->getRBracLoc(); 629226633Sdim return PathDiagnosticLocation(L, SM, SingleLocK); 630226633Sdim} 631226633Sdim 632226633SdimPathDiagnosticLocation 633226633Sdim PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 634226633Sdim const SourceManager &SM) { 635226633Sdim // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 636226633Sdim if (const CompoundStmt *CS = 637226633Sdim dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 638226633Sdim if (!CS->body_empty()) { 639226633Sdim SourceLocation Loc = (*CS->body_begin())->getLocStart(); 640226633Sdim return PathDiagnosticLocation(Loc, SM, SingleLocK); 641226633Sdim } 642226633Sdim 643226633Sdim return PathDiagnosticLocation(); 644226633Sdim} 645226633Sdim 646226633SdimPathDiagnosticLocation 647226633Sdim PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 648226633Sdim const SourceManager &SM) { 649226633Sdim SourceLocation L = LC->getDecl()->getBodyRBrace(); 650226633Sdim return PathDiagnosticLocation(L, SM, SingleLocK); 651226633Sdim} 652226633Sdim 653226633SdimPathDiagnosticLocation 654226633Sdim PathDiagnosticLocation::create(const ProgramPoint& P, 655226633Sdim const SourceManager &SMng) { 656226633Sdim 657226633Sdim const Stmt* S = 0; 658249423Sdim if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { 659226633Sdim const CFGBlock *BSrc = BE->getSrc(); 660226633Sdim S = BSrc->getTerminatorCondition(); 661249423Sdim } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { 662243830Sdim S = SP->getStmt(); 663249423Sdim if (P.getAs<PostStmtPurgeDeadSymbols>()) 664249423Sdim return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); 665249423Sdim } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { 666249423Sdim return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), 667249423Sdim SMng); 668249423Sdim } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { 669239462Sdim return PathDiagnosticLocation(PIE->getLocation(), SMng); 670249423Sdim } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { 671239462Sdim return getLocationForCaller(CE->getCalleeContext(), 672239462Sdim CE->getLocationContext(), 673239462Sdim SMng); 674249423Sdim } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { 675239462Sdim return getLocationForCaller(CEE->getCalleeContext(), 676239462Sdim CEE->getLocationContext(), 677239462Sdim SMng); 678249423Sdim } else { 679243830Sdim llvm_unreachable("Unexpected ProgramPoint"); 680243830Sdim } 681226633Sdim 682226633Sdim return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 683226633Sdim} 684226633Sdim 685251662Sdimconst Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { 686251662Sdim ProgramPoint P = N->getLocation(); 687251662Sdim if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) 688251662Sdim return SP->getStmt(); 689251662Sdim if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) 690251662Sdim return BE->getSrc()->getTerminator(); 691251662Sdim if (Optional<CallEnter> CE = P.getAs<CallEnter>()) 692251662Sdim return CE->getCallExpr(); 693251662Sdim if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) 694251662Sdim return CEE->getCalleeContext()->getCallSite(); 695251662Sdim if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) 696251662Sdim return PIPP->getInitializer()->getInit(); 697251662Sdim 698251662Sdim return 0; 699251662Sdim} 700251662Sdim 701251662Sdimconst Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { 702251662Sdim for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) { 703251662Sdim if (const Stmt *S = getStmt(N)) { 704251662Sdim // Check if the statement is '?' or '&&'/'||'. These are "merges", 705251662Sdim // not actual statement points. 706251662Sdim switch (S->getStmtClass()) { 707251662Sdim case Stmt::ChooseExprClass: 708251662Sdim case Stmt::BinaryConditionalOperatorClass: 709251662Sdim case Stmt::ConditionalOperatorClass: 710251662Sdim continue; 711251662Sdim case Stmt::BinaryOperatorClass: { 712251662Sdim BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); 713251662Sdim if (Op == BO_LAnd || Op == BO_LOr) 714251662Sdim continue; 715251662Sdim break; 716251662Sdim } 717251662Sdim default: 718251662Sdim break; 719251662Sdim } 720251662Sdim // We found the statement, so return it. 721251662Sdim return S; 722251662Sdim } 723251662Sdim } 724251662Sdim 725251662Sdim return 0; 726251662Sdim} 727251662Sdim 728226633SdimPathDiagnosticLocation 729251662Sdim PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, 730226633Sdim const SourceManager &SM) { 731226633Sdim assert(N && "Cannot create a location with a null node."); 732251662Sdim const Stmt *S = getStmt(N); 733226633Sdim 734251662Sdim if (!S) 735251662Sdim S = getNextStmt(N); 736226633Sdim 737251662Sdim if (S) { 738251662Sdim ProgramPoint P = N->getLocation(); 739251662Sdim const LocationContext *LC = N->getLocationContext(); 740226633Sdim 741251662Sdim // For member expressions, return the location of the '.' or '->'. 742251662Sdim if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) 743251662Sdim return PathDiagnosticLocation::createMemberLoc(ME, SM); 744251662Sdim 745251662Sdim // For binary operators, return the location of the operator. 746251662Sdim if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) 747251662Sdim return PathDiagnosticLocation::createOperatorLoc(B, SM); 748251662Sdim 749251662Sdim if (P.getAs<PostStmtPurgeDeadSymbols>()) 750251662Sdim return PathDiagnosticLocation::createEnd(S, SM, LC); 751251662Sdim 752243830Sdim if (S->getLocStart().isValid()) 753243830Sdim return PathDiagnosticLocation(S, SM, LC); 754243830Sdim return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); 755243830Sdim } 756243830Sdim 757226633Sdim return createDeclEnd(N->getLocationContext(), SM); 758226633Sdim} 759226633Sdim 760226633SdimPathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 761226633Sdim const PathDiagnosticLocation &PDL) { 762226633Sdim FullSourceLoc L = PDL.asLocation(); 763226633Sdim return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 764226633Sdim} 765226633Sdim 766226633SdimFullSourceLoc 767226633Sdim PathDiagnosticLocation::genLocation(SourceLocation L, 768234353Sdim LocationOrAnalysisDeclContext LAC) const { 769218887Sdim assert(isValid()); 770218887Sdim // Note that we want a 'switch' here so that the compiler can warn us in 771218887Sdim // case we add more cases. 772218887Sdim switch (K) { 773218887Sdim case SingleLocK: 774218887Sdim case RangeK: 775218887Sdim break; 776218887Sdim case StmtK: 777234353Sdim // Defensive checking. 778234353Sdim if (!S) 779234353Sdim break; 780226633Sdim return FullSourceLoc(getValidSourceLocation(S, LAC), 781226633Sdim const_cast<SourceManager&>(*SM)); 782218887Sdim case DeclK: 783234353Sdim // Defensive checking. 784234353Sdim if (!D) 785234353Sdim break; 786218887Sdim return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 787218887Sdim } 788218887Sdim 789226633Sdim return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 790218887Sdim} 791218887Sdim 792226633SdimPathDiagnosticRange 793234353Sdim PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 794218887Sdim assert(isValid()); 795218887Sdim // Note that we want a 'switch' here so that the compiler can warn us in 796218887Sdim // case we add more cases. 797218887Sdim switch (K) { 798218887Sdim case SingleLocK: 799226633Sdim return PathDiagnosticRange(SourceRange(Loc,Loc), true); 800218887Sdim case RangeK: 801218887Sdim break; 802218887Sdim case StmtK: { 803218887Sdim const Stmt *S = asStmt(); 804218887Sdim switch (S->getStmtClass()) { 805218887Sdim default: 806218887Sdim break; 807218887Sdim case Stmt::DeclStmtClass: { 808218887Sdim const DeclStmt *DS = cast<DeclStmt>(S); 809218887Sdim if (DS->isSingleDecl()) { 810218887Sdim // Should always be the case, but we'll be defensive. 811218887Sdim return SourceRange(DS->getLocStart(), 812218887Sdim DS->getSingleDecl()->getLocation()); 813218887Sdim } 814218887Sdim break; 815218887Sdim } 816218887Sdim // FIXME: Provide better range information for different 817218887Sdim // terminators. 818218887Sdim case Stmt::IfStmtClass: 819218887Sdim case Stmt::WhileStmtClass: 820218887Sdim case Stmt::DoStmtClass: 821218887Sdim case Stmt::ForStmtClass: 822218887Sdim case Stmt::ChooseExprClass: 823218887Sdim case Stmt::IndirectGotoStmtClass: 824218887Sdim case Stmt::SwitchStmtClass: 825218887Sdim case Stmt::BinaryConditionalOperatorClass: 826218887Sdim case Stmt::ConditionalOperatorClass: 827218887Sdim case Stmt::ObjCForCollectionStmtClass: { 828226633Sdim SourceLocation L = getValidSourceLocation(S, LAC); 829218887Sdim return SourceRange(L, L); 830218887Sdim } 831218887Sdim } 832226633Sdim SourceRange R = S->getSourceRange(); 833226633Sdim if (R.isValid()) 834226633Sdim return R; 835226633Sdim break; 836218887Sdim } 837218887Sdim case DeclK: 838218887Sdim if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 839218887Sdim return MD->getSourceRange(); 840218887Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 841218887Sdim if (Stmt *Body = FD->getBody()) 842218887Sdim return Body->getSourceRange(); 843218887Sdim } 844218887Sdim else { 845218887Sdim SourceLocation L = D->getLocation(); 846218887Sdim return PathDiagnosticRange(SourceRange(L, L), true); 847218887Sdim } 848218887Sdim } 849218887Sdim 850226633Sdim return SourceRange(Loc,Loc); 851218887Sdim} 852218887Sdim 853218887Sdimvoid PathDiagnosticLocation::flatten() { 854218887Sdim if (K == StmtK) { 855218887Sdim K = RangeK; 856218887Sdim S = 0; 857218887Sdim D = 0; 858218887Sdim } 859218887Sdim else if (K == DeclK) { 860218887Sdim K = SingleLocK; 861218887Sdim S = 0; 862218887Sdim D = 0; 863218887Sdim } 864218887Sdim} 865218887Sdim 866218887Sdim//===----------------------------------------------------------------------===// 867234353Sdim// Manipulation of PathDiagnosticCallPieces. 868234353Sdim//===----------------------------------------------------------------------===// 869234353Sdim 870234353SdimPathDiagnosticCallPiece * 871234353SdimPathDiagnosticCallPiece::construct(const ExplodedNode *N, 872239462Sdim const CallExitEnd &CE, 873234353Sdim const SourceManager &SM) { 874239462Sdim const Decl *caller = CE.getLocationContext()->getDecl(); 875239462Sdim PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 876239462Sdim CE.getLocationContext(), 877239462Sdim SM); 878234353Sdim return new PathDiagnosticCallPiece(caller, pos); 879234353Sdim} 880234353Sdim 881234353SdimPathDiagnosticCallPiece * 882234353SdimPathDiagnosticCallPiece::construct(PathPieces &path, 883234353Sdim const Decl *caller) { 884234353Sdim PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller); 885234353Sdim path.clear(); 886234353Sdim path.push_front(C); 887234353Sdim return C; 888234353Sdim} 889234353Sdim 890234353Sdimvoid PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 891234353Sdim const SourceManager &SM) { 892239462Sdim const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 893239462Sdim Callee = CalleeCtx->getDecl(); 894239462Sdim 895239462Sdim callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 896239462Sdim callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 897234353Sdim} 898234353Sdim 899249423Sdimstatic inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, 900249423Sdim StringRef Prefix = StringRef()) { 901249423Sdim if (!D->getIdentifier()) 902249423Sdim return; 903249423Sdim Out << Prefix << '\'' << *D << '\''; 904249423Sdim} 905249423Sdim 906249423Sdimstatic bool describeCodeDecl(raw_ostream &Out, const Decl *D, 907249423Sdim bool ExtendedDescription, 908249423Sdim StringRef Prefix = StringRef()) { 909249423Sdim if (!D) 910249423Sdim return false; 911249423Sdim 912249423Sdim if (isa<BlockDecl>(D)) { 913249423Sdim if (ExtendedDescription) 914249423Sdim Out << Prefix << "anonymous block"; 915249423Sdim return ExtendedDescription; 916249423Sdim } 917249423Sdim 918249423Sdim if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { 919249423Sdim Out << Prefix; 920249423Sdim if (ExtendedDescription && !MD->isUserProvided()) { 921249423Sdim if (MD->isExplicitlyDefaulted()) 922249423Sdim Out << "defaulted "; 923249423Sdim else 924249423Sdim Out << "implicit "; 925249423Sdim } 926249423Sdim 927249423Sdim if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) { 928249423Sdim if (CD->isDefaultConstructor()) 929249423Sdim Out << "default "; 930249423Sdim else if (CD->isCopyConstructor()) 931249423Sdim Out << "copy "; 932249423Sdim else if (CD->isMoveConstructor()) 933249423Sdim Out << "move "; 934249423Sdim 935249423Sdim Out << "constructor"; 936249423Sdim describeClass(Out, MD->getParent(), " for "); 937249423Sdim 938249423Sdim } else if (isa<CXXDestructorDecl>(MD)) { 939249423Sdim if (!MD->isUserProvided()) { 940249423Sdim Out << "destructor"; 941249423Sdim describeClass(Out, MD->getParent(), " for "); 942249423Sdim } else { 943249423Sdim // Use ~Foo for explicitly-written destructors. 944249423Sdim Out << "'" << *MD << "'"; 945249423Sdim } 946249423Sdim 947249423Sdim } else if (MD->isCopyAssignmentOperator()) { 948249423Sdim Out << "copy assignment operator"; 949249423Sdim describeClass(Out, MD->getParent(), " for "); 950249423Sdim 951249423Sdim } else if (MD->isMoveAssignmentOperator()) { 952249423Sdim Out << "move assignment operator"; 953249423Sdim describeClass(Out, MD->getParent(), " for "); 954249423Sdim 955249423Sdim } else { 956249423Sdim if (MD->getParent()->getIdentifier()) 957249423Sdim Out << "'" << *MD->getParent() << "::" << *MD << "'"; 958249423Sdim else 959249423Sdim Out << "'" << *MD << "'"; 960249423Sdim } 961249423Sdim 962249423Sdim return true; 963249423Sdim } 964249423Sdim 965249423Sdim Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\''; 966249423Sdim return true; 967249423Sdim} 968249423Sdim 969234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece> 970234353SdimPathDiagnosticCallPiece::getCallEnterEvent() const { 971234353Sdim if (!Callee) 972234353Sdim return 0; 973249423Sdim 974234353Sdim SmallString<256> buf; 975234353Sdim llvm::raw_svector_ostream Out(buf); 976249423Sdim 977249423Sdim Out << "Calling "; 978249423Sdim describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); 979249423Sdim 980249423Sdim assert(callEnter.asLocation().isValid()); 981249423Sdim return new PathDiagnosticEventPiece(callEnter, Out.str()); 982234353Sdim} 983234353Sdim 984234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece> 985234353SdimPathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 986249423Sdim if (!callEnterWithin.asLocation().isValid()) 987249423Sdim return 0; 988263508Sdim if (Callee->isImplicit() || !Callee->hasBody()) 989249423Sdim return 0; 990249423Sdim if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) 991249423Sdim if (MD->isDefaulted()) 992249423Sdim return 0; 993249423Sdim 994234353Sdim SmallString<256> buf; 995234353Sdim llvm::raw_svector_ostream Out(buf); 996249423Sdim 997249423Sdim Out << "Entered call"; 998249423Sdim describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); 999249423Sdim 1000249423Sdim return new PathDiagnosticEventPiece(callEnterWithin, Out.str()); 1001234353Sdim} 1002234353Sdim 1003234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece> 1004234353SdimPathDiagnosticCallPiece::getCallExitEvent() const { 1005234353Sdim if (NoExit) 1006234353Sdim return 0; 1007249423Sdim 1008234353Sdim SmallString<256> buf; 1009234353Sdim llvm::raw_svector_ostream Out(buf); 1010249423Sdim 1011249423Sdim if (!CallStackMessage.empty()) { 1012234353Sdim Out << CallStackMessage; 1013249423Sdim } else { 1014249423Sdim bool DidDescribe = describeCodeDecl(Out, Callee, 1015249423Sdim /*ExtendedDescription=*/false, 1016249423Sdim "Returning from "); 1017249423Sdim if (!DidDescribe) 1018249423Sdim Out << "Returning to caller"; 1019249423Sdim } 1020249423Sdim 1021249423Sdim assert(callReturn.asLocation().isValid()); 1022234353Sdim return new PathDiagnosticEventPiece(callReturn, Out.str()); 1023234353Sdim} 1024234353Sdim 1025234353Sdimstatic void compute_path_size(const PathPieces &pieces, unsigned &size) { 1026234353Sdim for (PathPieces::const_iterator it = pieces.begin(), 1027234353Sdim et = pieces.end(); it != et; ++it) { 1028234353Sdim const PathDiagnosticPiece *piece = it->getPtr(); 1029234353Sdim if (const PathDiagnosticCallPiece *cp = 1030234353Sdim dyn_cast<PathDiagnosticCallPiece>(piece)) { 1031234353Sdim compute_path_size(cp->path, size); 1032234353Sdim } 1033234353Sdim else 1034234353Sdim ++size; 1035234353Sdim } 1036234353Sdim} 1037234353Sdim 1038234353Sdimunsigned PathDiagnostic::full_size() { 1039234353Sdim unsigned size = 0; 1040234353Sdim compute_path_size(path, size); 1041234353Sdim return size; 1042234353Sdim} 1043234353Sdim 1044234353Sdim//===----------------------------------------------------------------------===// 1045218887Sdim// FoldingSet profiling methods. 1046218887Sdim//===----------------------------------------------------------------------===// 1047218887Sdim 1048218887Sdimvoid PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 1049226633Sdim ID.AddInteger(Range.getBegin().getRawEncoding()); 1050226633Sdim ID.AddInteger(Range.getEnd().getRawEncoding()); 1051226633Sdim ID.AddInteger(Loc.getRawEncoding()); 1052218887Sdim return; 1053218887Sdim} 1054218887Sdim 1055218887Sdimvoid PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1056218887Sdim ID.AddInteger((unsigned) getKind()); 1057218887Sdim ID.AddString(str); 1058218887Sdim // FIXME: Add profiling support for code hints. 1059218887Sdim ID.AddInteger((unsigned) getDisplayHint()); 1060239462Sdim ArrayRef<SourceRange> Ranges = getRanges(); 1061239462Sdim for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 1062239462Sdim I != E; ++I) { 1063218887Sdim ID.AddInteger(I->getBegin().getRawEncoding()); 1064218887Sdim ID.AddInteger(I->getEnd().getRawEncoding()); 1065218887Sdim } 1066218887Sdim} 1067218887Sdim 1068234353Sdimvoid PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1069234353Sdim PathDiagnosticPiece::Profile(ID); 1070234353Sdim for (PathPieces::const_iterator it = path.begin(), 1071234353Sdim et = path.end(); it != et; ++it) { 1072234353Sdim ID.Add(**it); 1073234353Sdim } 1074234353Sdim} 1075234353Sdim 1076218887Sdimvoid PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1077218887Sdim PathDiagnosticPiece::Profile(ID); 1078218887Sdim ID.Add(Pos); 1079218887Sdim} 1080218887Sdim 1081218887Sdimvoid PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1082218887Sdim PathDiagnosticPiece::Profile(ID); 1083218887Sdim for (const_iterator I = begin(), E = end(); I != E; ++I) 1084218887Sdim ID.Add(*I); 1085218887Sdim} 1086218887Sdim 1087218887Sdimvoid PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1088218887Sdim PathDiagnosticSpotPiece::Profile(ID); 1089234353Sdim for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 1090234353Sdim I != E; ++I) 1091218887Sdim ID.Add(**I); 1092218887Sdim} 1093218887Sdim 1094218887Sdimvoid PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 1095243830Sdim ID.Add(getLocation()); 1096218887Sdim ID.AddString(BugType); 1097243830Sdim ID.AddString(VerboseDesc); 1098218887Sdim ID.AddString(Category); 1099234353Sdim} 1100234353Sdim 1101234353Sdimvoid PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 1102234353Sdim Profile(ID); 1103234353Sdim for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) 1104234353Sdim ID.Add(**I); 1105218887Sdim for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 1106218887Sdim ID.AddString(*I); 1107218887Sdim} 1108234353Sdim 1109234353SdimStackHintGenerator::~StackHintGenerator() {} 1110234353Sdim 1111234353Sdimstd::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ 1112234353Sdim ProgramPoint P = N->getLocation(); 1113249423Sdim CallExitEnd CExit = P.castAs<CallExitEnd>(); 1114234353Sdim 1115239462Sdim // FIXME: Use CallEvent to abstract this over all calls. 1116249423Sdim const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); 1117239462Sdim const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); 1118234353Sdim if (!CE) 1119234353Sdim return ""; 1120234353Sdim 1121234353Sdim if (!N) 1122234353Sdim return getMessageForSymbolNotFound(); 1123234353Sdim 1124234353Sdim // Check if one of the parameters are set to the interesting symbol. 1125234353Sdim ProgramStateRef State = N->getState(); 1126234353Sdim const LocationContext *LCtx = N->getLocationContext(); 1127234353Sdim unsigned ArgIndex = 0; 1128234353Sdim for (CallExpr::const_arg_iterator I = CE->arg_begin(), 1129234353Sdim E = CE->arg_end(); I != E; ++I, ++ArgIndex){ 1130234353Sdim SVal SV = State->getSVal(*I, LCtx); 1131234353Sdim 1132234353Sdim // Check if the variable corresponding to the symbol is passed by value. 1133234353Sdim SymbolRef AS = SV.getAsLocSymbol(); 1134234353Sdim if (AS == Sym) { 1135234353Sdim return getMessageForArg(*I, ArgIndex); 1136234353Sdim } 1137234353Sdim 1138234353Sdim // Check if the parameter is a pointer to the symbol. 1139249423Sdim if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { 1140234353Sdim SVal PSV = State->getSVal(Reg->getRegion()); 1141234353Sdim SymbolRef AS = PSV.getAsLocSymbol(); 1142234353Sdim if (AS == Sym) { 1143234353Sdim return getMessageForArg(*I, ArgIndex); 1144234353Sdim } 1145234353Sdim } 1146234353Sdim } 1147234353Sdim 1148234353Sdim // Check if we are returning the interesting symbol. 1149234353Sdim SVal SV = State->getSVal(CE, LCtx); 1150234353Sdim SymbolRef RetSym = SV.getAsLocSymbol(); 1151234353Sdim if (RetSym == Sym) { 1152234353Sdim return getMessageForReturn(CE); 1153234353Sdim } 1154234353Sdim 1155234353Sdim return getMessageForSymbolNotFound(); 1156234353Sdim} 1157234353Sdim 1158243830Sdimstd::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, 1159243830Sdim unsigned ArgIndex) { 1160243830Sdim // Printed parameters start at 1, not 0. 1161243830Sdim ++ArgIndex; 1162234353Sdim 1163234353Sdim SmallString<200> buf; 1164234353Sdim llvm::raw_svector_ostream os(buf); 1165234353Sdim 1166243830Sdim os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) 1167243830Sdim << " parameter"; 1168234353Sdim 1169234353Sdim return os.str(); 1170234353Sdim} 1171