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) 51218887Sdim : str(StripTrailingDots(s)), kind(k), Hint(hint) {} 52218887Sdim 53218887SdimPathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 54218887Sdim : kind(k), Hint(hint) {} 55218887Sdim 56218887SdimPathDiagnosticPiece::~PathDiagnosticPiece() {} 57218887SdimPathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 58234353SdimPathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} 59218887SdimPathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 60234353SdimPathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} 61218887Sdim 62218887Sdim 63234353SdimPathPieces::~PathPieces() {} 64239462Sdim 65239462Sdimvoid PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, 66239462Sdim bool ShouldFlattenMacros) const { 67239462Sdim for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 68239462Sdim PathDiagnosticPiece *Piece = I->getPtr(); 69239462Sdim 70239462Sdim switch (Piece->getKind()) { 71239462Sdim case PathDiagnosticPiece::Call: { 72239462Sdim PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece); 73239462Sdim IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter = 74239462Sdim Call->getCallEnterEvent(); 75239462Sdim if (CallEnter) 76239462Sdim Current.push_back(CallEnter); 77239462Sdim Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros); 78239462Sdim IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = 79239462Sdim Call->getCallExitEvent(); 80239462Sdim if (callExit) 81239462Sdim Current.push_back(callExit); 82239462Sdim break; 83239462Sdim } 84239462Sdim case PathDiagnosticPiece::Macro: { 85239462Sdim PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece); 86239462Sdim if (ShouldFlattenMacros) { 87239462Sdim Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 88239462Sdim } else { 89239462Sdim Current.push_back(Piece); 90239462Sdim PathPieces NewPath; 91239462Sdim Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 92239462Sdim // FIXME: This probably shouldn't mutate the original path piece. 93239462Sdim Macro->subPieces = NewPath; 94239462Sdim } 95239462Sdim break; 96239462Sdim } 97239462Sdim case PathDiagnosticPiece::Event: 98239462Sdim case PathDiagnosticPiece::ControlFlow: 99239462Sdim Current.push_back(Piece); 100239462Sdim break; 101239462Sdim } 102239462Sdim } 103239462Sdim} 104239462Sdim 105239462Sdim 106234353SdimPathDiagnostic::~PathDiagnostic() {} 107218887Sdim 108234353SdimPathDiagnostic::PathDiagnostic(const Decl *declWithIssue, 109243830Sdim StringRef bugtype, StringRef verboseDesc, 110249423Sdim StringRef shortDesc, StringRef category, 111249423Sdim PathDiagnosticLocation LocationToUnique, 112249423Sdim const Decl *DeclToUnique) 113234353Sdim : DeclWithIssue(declWithIssue), 114234353Sdim BugType(StripTrailingDots(bugtype)), 115243830Sdim VerboseDesc(StripTrailingDots(verboseDesc)), 116243830Sdim ShortDesc(StripTrailingDots(shortDesc)), 117234353Sdim Category(StripTrailingDots(category)), 118249423Sdim UniqueingLoc(LocationToUnique), 119249423Sdim UniqueingDecl(DeclToUnique), 120234353Sdim path(pathImpl) {} 121234353Sdim 122234353Sdimvoid PathDiagnosticConsumer::anchor() { } 123234353Sdim 124234353SdimPathDiagnosticConsumer::~PathDiagnosticConsumer() { 125234353Sdim // Delete the contents of the FoldingSet if it isn't empty already. 126234353Sdim for (llvm::FoldingSet<PathDiagnostic>::iterator it = 127234353Sdim Diags.begin(), et = Diags.end() ; it != et ; ++it) { 128234353Sdim delete &*it; 129234353Sdim } 130218887Sdim} 131218887Sdim 132234353Sdimvoid PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { 133249423Sdim OwningPtr<PathDiagnostic> OwningD(D); 134234353Sdim 135234353Sdim if (!D || D->path.empty()) 136234353Sdim return; 137234353Sdim 138234353Sdim // We need to flatten the locations (convert Stmt* to locations) because 139234353Sdim // the referenced statements may be freed by the time the diagnostics 140234353Sdim // are emitted. 141234353Sdim D->flattenLocations(); 142218887Sdim 143234353Sdim // If the PathDiagnosticConsumer does not support diagnostics that 144234353Sdim // cross file boundaries, prune out such diagnostics now. 145234353Sdim if (!supportsCrossFileDiagnostics()) { 146234353Sdim // Verify that the entire path is from the same FileID. 147234353Sdim FileID FID; 148234353Sdim const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager(); 149249423Sdim SmallVector<const PathPieces *, 5> WorkList; 150234353Sdim WorkList.push_back(&D->path); 151218887Sdim 152234353Sdim while (!WorkList.empty()) { 153234353Sdim const PathPieces &path = *WorkList.back(); 154234353Sdim WorkList.pop_back(); 155234353Sdim 156234353Sdim for (PathPieces::const_iterator I = path.begin(), E = path.end(); 157234353Sdim I != E; ++I) { 158234353Sdim const PathDiagnosticPiece *piece = I->getPtr(); 159234353Sdim FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 160234353Sdim 161234353Sdim if (FID.isInvalid()) { 162234353Sdim FID = SMgr.getFileID(L); 163234353Sdim } else if (SMgr.getFileID(L) != FID) 164234353Sdim return; // FIXME: Emit a warning? 165234353Sdim 166234353Sdim // Check the source ranges. 167239462Sdim ArrayRef<SourceRange> Ranges = piece->getRanges(); 168239462Sdim for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), 169239462Sdim E = Ranges.end(); I != E; ++I) { 170239462Sdim SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); 171234353Sdim if (!L.isFileID() || SMgr.getFileID(L) != FID) 172234353Sdim return; // FIXME: Emit a warning? 173239462Sdim L = SMgr.getExpansionLoc(I->getEnd()); 174234353Sdim if (!L.isFileID() || SMgr.getFileID(L) != FID) 175234353Sdim return; // FIXME: Emit a warning? 176234353Sdim } 177234353Sdim 178234353Sdim if (const PathDiagnosticCallPiece *call = 179234353Sdim dyn_cast<PathDiagnosticCallPiece>(piece)) { 180234353Sdim WorkList.push_back(&call->path); 181234353Sdim } 182234353Sdim else if (const PathDiagnosticMacroPiece *macro = 183234353Sdim dyn_cast<PathDiagnosticMacroPiece>(piece)) { 184234353Sdim WorkList.push_back(¯o->subPieces); 185234353Sdim } 186234353Sdim } 187234353Sdim } 188234353Sdim 189234353Sdim if (FID.isInvalid()) 190234353Sdim return; // FIXME: Emit a warning? 191234353Sdim } 192234353Sdim 193234353Sdim // Profile the node to see if we already have something matching it 194234353Sdim llvm::FoldingSetNodeID profile; 195234353Sdim D->Profile(profile); 196234353Sdim void *InsertPos = 0; 197234353Sdim 198234353Sdim if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 199234353Sdim // Keep the PathDiagnostic with the shorter path. 200239462Sdim // Note, the enclosing routine is called in deterministic order, so the 201239462Sdim // results will be consistent between runs (no reason to break ties if the 202239462Sdim // size is the same). 203234353Sdim const unsigned orig_size = orig->full_size(); 204234353Sdim const unsigned new_size = D->full_size(); 205239462Sdim if (orig_size <= new_size) 206239462Sdim return; 207234353Sdim 208243830Sdim assert(orig != D); 209234353Sdim Diags.RemoveNode(orig); 210234353Sdim delete orig; 211234353Sdim } 212234353Sdim 213234353Sdim Diags.InsertNode(OwningD.take()); 214218887Sdim} 215218887Sdim 216249423Sdimstatic Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); 217249423Sdimstatic Optional<bool> 218243830SdimcompareControlFlow(const PathDiagnosticControlFlowPiece &X, 219243830Sdim const PathDiagnosticControlFlowPiece &Y) { 220243830Sdim FullSourceLoc XSL = X.getStartLocation().asLocation(); 221243830Sdim FullSourceLoc YSL = Y.getStartLocation().asLocation(); 222243830Sdim if (XSL != YSL) 223243830Sdim return XSL.isBeforeInTranslationUnitThan(YSL); 224243830Sdim FullSourceLoc XEL = X.getEndLocation().asLocation(); 225243830Sdim FullSourceLoc YEL = Y.getEndLocation().asLocation(); 226243830Sdim if (XEL != YEL) 227243830Sdim return XEL.isBeforeInTranslationUnitThan(YEL); 228249423Sdim return None; 229243830Sdim} 230218887Sdim 231249423Sdimstatic Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, 232249423Sdim const PathDiagnosticMacroPiece &Y) { 233243830Sdim return comparePath(X.subPieces, Y.subPieces); 234243830Sdim} 235243830Sdim 236249423Sdimstatic Optional<bool> compareCall(const PathDiagnosticCallPiece &X, 237249423Sdim const PathDiagnosticCallPiece &Y) { 238243830Sdim FullSourceLoc X_CEL = X.callEnter.asLocation(); 239243830Sdim FullSourceLoc Y_CEL = Y.callEnter.asLocation(); 240243830Sdim if (X_CEL != Y_CEL) 241243830Sdim return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); 242243830Sdim FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); 243243830Sdim FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); 244243830Sdim if (X_CEWL != Y_CEWL) 245243830Sdim return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); 246243830Sdim FullSourceLoc X_CRL = X.callReturn.asLocation(); 247243830Sdim FullSourceLoc Y_CRL = Y.callReturn.asLocation(); 248243830Sdim if (X_CRL != Y_CRL) 249243830Sdim return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); 250243830Sdim return comparePath(X.path, Y.path); 251243830Sdim} 252243830Sdim 253249423Sdimstatic Optional<bool> comparePiece(const PathDiagnosticPiece &X, 254249423Sdim const PathDiagnosticPiece &Y) { 255243830Sdim if (X.getKind() != Y.getKind()) 256243830Sdim return X.getKind() < Y.getKind(); 257243830Sdim 258243830Sdim FullSourceLoc XL = X.getLocation().asLocation(); 259243830Sdim FullSourceLoc YL = Y.getLocation().asLocation(); 260243830Sdim if (XL != YL) 261243830Sdim return XL.isBeforeInTranslationUnitThan(YL); 262243830Sdim 263243830Sdim if (X.getString() != Y.getString()) 264243830Sdim return X.getString() < Y.getString(); 265243830Sdim 266243830Sdim if (X.getRanges().size() != Y.getRanges().size()) 267243830Sdim return X.getRanges().size() < Y.getRanges().size(); 268243830Sdim 269243830Sdim const SourceManager &SM = XL.getManager(); 270243830Sdim 271243830Sdim for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { 272243830Sdim SourceRange XR = X.getRanges()[i]; 273243830Sdim SourceRange YR = Y.getRanges()[i]; 274243830Sdim if (XR != YR) { 275243830Sdim if (XR.getBegin() != YR.getBegin()) 276243830Sdim return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); 277243830Sdim return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); 278243830Sdim } 279243830Sdim } 280243830Sdim 281243830Sdim switch (X.getKind()) { 282243830Sdim case clang::ento::PathDiagnosticPiece::ControlFlow: 283243830Sdim return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), 284243830Sdim cast<PathDiagnosticControlFlowPiece>(Y)); 285243830Sdim case clang::ento::PathDiagnosticPiece::Event: 286249423Sdim return None; 287243830Sdim case clang::ento::PathDiagnosticPiece::Macro: 288243830Sdim return compareMacro(cast<PathDiagnosticMacroPiece>(X), 289243830Sdim cast<PathDiagnosticMacroPiece>(Y)); 290243830Sdim case clang::ento::PathDiagnosticPiece::Call: 291243830Sdim return compareCall(cast<PathDiagnosticCallPiece>(X), 292243830Sdim cast<PathDiagnosticCallPiece>(Y)); 293243830Sdim } 294243830Sdim llvm_unreachable("all cases handled"); 295243830Sdim} 296243830Sdim 297249423Sdimstatic Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { 298243830Sdim if (X.size() != Y.size()) 299243830Sdim return X.size() < Y.size(); 300251662Sdim 301251662Sdim PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); 302251662Sdim PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); 303251662Sdim 304251662Sdim for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { 305251662Sdim Optional<bool> b = comparePiece(**X_I, **Y_I); 306243830Sdim if (b.hasValue()) 307243830Sdim return b.getValue(); 308243830Sdim } 309251662Sdim 310249423Sdim return None; 311243830Sdim} 312243830Sdim 313243830Sdimstatic bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { 314243830Sdim FullSourceLoc XL = X.getLocation().asLocation(); 315243830Sdim FullSourceLoc YL = Y.getLocation().asLocation(); 316243830Sdim if (XL != YL) 317243830Sdim return XL.isBeforeInTranslationUnitThan(YL); 318243830Sdim if (X.getBugType() != Y.getBugType()) 319243830Sdim return X.getBugType() < Y.getBugType(); 320243830Sdim if (X.getCategory() != Y.getCategory()) 321243830Sdim return X.getCategory() < Y.getCategory(); 322243830Sdim if (X.getVerboseDescription() != Y.getVerboseDescription()) 323243830Sdim return X.getVerboseDescription() < Y.getVerboseDescription(); 324243830Sdim if (X.getShortDescription() != Y.getShortDescription()) 325243830Sdim return X.getShortDescription() < Y.getShortDescription(); 326243830Sdim if (X.getDeclWithIssue() != Y.getDeclWithIssue()) { 327243830Sdim const Decl *XD = X.getDeclWithIssue(); 328243830Sdim if (!XD) 329243830Sdim return true; 330243830Sdim const Decl *YD = Y.getDeclWithIssue(); 331243830Sdim if (!YD) 332243830Sdim return false; 333243830Sdim SourceLocation XDL = XD->getLocation(); 334243830Sdim SourceLocation YDL = YD->getLocation(); 335243830Sdim if (XDL != YDL) { 336243830Sdim const SourceManager &SM = XL.getManager(); 337243830Sdim return SM.isBeforeInTranslationUnit(XDL, YDL); 338243830Sdim } 339243830Sdim } 340243830Sdim PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); 341243830Sdim PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); 342243830Sdim if (XE - XI != YE - YI) 343243830Sdim return (XE - XI) < (YE - YI); 344243830Sdim for ( ; XI != XE ; ++XI, ++YI) { 345243830Sdim if (*XI != *YI) 346243830Sdim return (*XI) < (*YI); 347243830Sdim } 348249423Sdim Optional<bool> b = comparePath(X.path, Y.path); 349243830Sdim assert(b.hasValue()); 350243830Sdim return b.getValue(); 351243830Sdim} 352243830Sdim 353234353Sdimnamespace { 354234353Sdimstruct CompareDiagnostics { 355234353Sdim // Compare if 'X' is "<" than 'Y'. 356234353Sdim bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { 357243830Sdim if (X == Y) 358234353Sdim return false; 359243830Sdim return compare(*X, *Y); 360243830Sdim } 361243830Sdim}; 362234353Sdim} 363218887Sdim 364239462Sdimvoid PathDiagnosticConsumer::FlushDiagnostics( 365239462Sdim PathDiagnosticConsumer::FilesMade *Files) { 366234353Sdim if (flushed) 367234353Sdim return; 368234353Sdim 369234353Sdim flushed = true; 370234353Sdim 371234353Sdim std::vector<const PathDiagnostic *> BatchDiags; 372234353Sdim for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), 373234353Sdim et = Diags.end(); it != et; ++it) { 374243830Sdim const PathDiagnostic *D = &*it; 375243830Sdim BatchDiags.push_back(D); 376234353Sdim } 377234353Sdim 378234353Sdim // Sort the diagnostics so that they are always emitted in a deterministic 379234353Sdim // order. 380234353Sdim if (!BatchDiags.empty()) 381234353Sdim std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics()); 382234353Sdim 383234353Sdim FlushDiagnosticsImpl(BatchDiags, Files); 384234353Sdim 385234353Sdim // Delete the flushed diagnostics. 386234353Sdim for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), 387234353Sdim et = BatchDiags.end(); it != et; ++it) { 388234353Sdim const PathDiagnostic *D = *it; 389234353Sdim delete D; 390234353Sdim } 391243830Sdim 392243830Sdim // Clear out the FoldingSet. 393243830Sdim Diags.clear(); 394226633Sdim} 395218887Sdim 396243830Sdimvoid PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 397243830Sdim StringRef ConsumerName, 398243830Sdim StringRef FileName) { 399243830Sdim llvm::FoldingSetNodeID NodeID; 400243830Sdim NodeID.Add(PD); 401243830Sdim void *InsertPos; 402243830Sdim PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 403243830Sdim if (!Entry) { 404243830Sdim Entry = Alloc.Allocate<PDFileEntry>(); 405243830Sdim Entry = new (Entry) PDFileEntry(NodeID); 406243830Sdim InsertNode(Entry, InsertPos); 407243830Sdim } 408243830Sdim 409243830Sdim // Allocate persistent storage for the file name. 410243830Sdim char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); 411243830Sdim memcpy(FileName_cstr, FileName.data(), FileName.size()); 412243830Sdim 413243830Sdim Entry->files.push_back(std::make_pair(ConsumerName, 414243830Sdim StringRef(FileName_cstr, 415243830Sdim FileName.size()))); 416243830Sdim} 417243830Sdim 418243830SdimPathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 419243830SdimPathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 420243830Sdim llvm::FoldingSetNodeID NodeID; 421243830Sdim NodeID.Add(PD); 422243830Sdim void *InsertPos; 423243830Sdim PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 424243830Sdim if (!Entry) 425243830Sdim return 0; 426243830Sdim return &Entry->files; 427243830Sdim} 428243830Sdim 429226633Sdim//===----------------------------------------------------------------------===// 430226633Sdim// PathDiagnosticLocation methods. 431226633Sdim//===----------------------------------------------------------------------===// 432218887Sdim 433226633Sdimstatic SourceLocation getValidSourceLocation(const Stmt* S, 434239462Sdim LocationOrAnalysisDeclContext LAC, 435239462Sdim bool UseEnd = false) { 436239462Sdim SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart(); 437234353Sdim assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " 438226633Sdim "be passed to PathDiagnosticLocation upon creation."); 439218887Sdim 440226633Sdim // S might be a temporary statement that does not have a location in the 441239462Sdim // source code, so find an enclosing statement and use its location. 442226633Sdim if (!L.isValid()) { 443226633Sdim 444239462Sdim AnalysisDeclContext *ADC; 445226633Sdim if (LAC.is<const LocationContext*>()) 446239462Sdim ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 447226633Sdim else 448239462Sdim ADC = LAC.get<AnalysisDeclContext*>(); 449226633Sdim 450239462Sdim ParentMap &PM = ADC->getParentMap(); 451239462Sdim 452239462Sdim const Stmt *Parent = S; 453239462Sdim do { 454239462Sdim Parent = PM.getParent(Parent); 455239462Sdim 456239462Sdim // In rare cases, we have implicit top-level expressions, 457239462Sdim // such as arguments for implicit member initializers. 458239462Sdim // In this case, fall back to the start of the body (even if we were 459239462Sdim // asked for the statement end location). 460239462Sdim if (!Parent) { 461239462Sdim const Stmt *Body = ADC->getBody(); 462239462Sdim if (Body) 463239462Sdim L = Body->getLocStart(); 464239462Sdim else 465239462Sdim L = ADC->getDecl()->getLocEnd(); 466239462Sdim break; 467239462Sdim } 468239462Sdim 469239462Sdim L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart(); 470239462Sdim } while (!L.isValid()); 471218887Sdim } 472218887Sdim 473226633Sdim return L; 474226633Sdim} 475218887Sdim 476239462Sdimstatic PathDiagnosticLocation 477239462SdimgetLocationForCaller(const StackFrameContext *SFC, 478239462Sdim const LocationContext *CallerCtx, 479239462Sdim const SourceManager &SM) { 480239462Sdim const CFGBlock &Block = *SFC->getCallSiteBlock(); 481239462Sdim CFGElement Source = Block[SFC->getIndex()]; 482239462Sdim 483239462Sdim switch (Source.getKind()) { 484239462Sdim case CFGElement::Statement: 485249423Sdim return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), 486239462Sdim SM, CallerCtx); 487239462Sdim case CFGElement::Initializer: { 488249423Sdim const CFGInitializer &Init = Source.castAs<CFGInitializer>(); 489239462Sdim return PathDiagnosticLocation(Init.getInitializer()->getInit(), 490239462Sdim SM, CallerCtx); 491239462Sdim } 492239462Sdim case CFGElement::AutomaticObjectDtor: { 493249423Sdim const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); 494239462Sdim return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 495239462Sdim SM, CallerCtx); 496239462Sdim } 497239462Sdim case CFGElement::BaseDtor: 498239462Sdim case CFGElement::MemberDtor: { 499239462Sdim const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); 500239462Sdim if (const Stmt *CallerBody = CallerInfo->getBody()) 501239462Sdim return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); 502239462Sdim return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); 503239462Sdim } 504239462Sdim case CFGElement::TemporaryDtor: 505239462Sdim llvm_unreachable("not yet implemented!"); 506239462Sdim } 507239462Sdim 508239462Sdim llvm_unreachable("Unknown CFGElement kind"); 509239462Sdim} 510239462Sdim 511239462Sdim 512226633SdimPathDiagnosticLocation 513226633Sdim PathDiagnosticLocation::createBegin(const Decl *D, 514226633Sdim const SourceManager &SM) { 515226633Sdim return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 516226633Sdim} 517218887Sdim 518226633SdimPathDiagnosticLocation 519226633Sdim PathDiagnosticLocation::createBegin(const Stmt *S, 520226633Sdim const SourceManager &SM, 521234353Sdim LocationOrAnalysisDeclContext LAC) { 522226633Sdim return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 523226633Sdim SM, SingleLocK); 524226633Sdim} 525218887Sdim 526239462Sdim 527226633SdimPathDiagnosticLocation 528239462SdimPathDiagnosticLocation::createEnd(const Stmt *S, 529239462Sdim const SourceManager &SM, 530239462Sdim LocationOrAnalysisDeclContext LAC) { 531239462Sdim if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) 532239462Sdim return createEndBrace(CS, SM); 533239462Sdim return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 534239462Sdim SM, SingleLocK); 535239462Sdim} 536239462Sdim 537239462SdimPathDiagnosticLocation 538226633Sdim PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 539226633Sdim const SourceManager &SM) { 540226633Sdim return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 541218887Sdim} 542218887Sdim 543226633SdimPathDiagnosticLocation 544226633Sdim PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 545226633Sdim const SourceManager &SM) { 546226633Sdim return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 547226633Sdim} 548218887Sdim 549226633SdimPathDiagnosticLocation 550226633Sdim PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 551226633Sdim const SourceManager &SM) { 552226633Sdim SourceLocation L = CS->getLBracLoc(); 553226633Sdim return PathDiagnosticLocation(L, SM, SingleLocK); 554226633Sdim} 555226633Sdim 556226633SdimPathDiagnosticLocation 557226633Sdim PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 558226633Sdim const SourceManager &SM) { 559226633Sdim SourceLocation L = CS->getRBracLoc(); 560226633Sdim return PathDiagnosticLocation(L, SM, SingleLocK); 561226633Sdim} 562226633Sdim 563226633SdimPathDiagnosticLocation 564226633Sdim PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 565226633Sdim const SourceManager &SM) { 566226633Sdim // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 567226633Sdim if (const CompoundStmt *CS = 568226633Sdim dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 569226633Sdim if (!CS->body_empty()) { 570226633Sdim SourceLocation Loc = (*CS->body_begin())->getLocStart(); 571226633Sdim return PathDiagnosticLocation(Loc, SM, SingleLocK); 572226633Sdim } 573226633Sdim 574226633Sdim return PathDiagnosticLocation(); 575226633Sdim} 576226633Sdim 577226633SdimPathDiagnosticLocation 578226633Sdim PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 579226633Sdim const SourceManager &SM) { 580226633Sdim SourceLocation L = LC->getDecl()->getBodyRBrace(); 581226633Sdim return PathDiagnosticLocation(L, SM, SingleLocK); 582226633Sdim} 583226633Sdim 584226633SdimPathDiagnosticLocation 585226633Sdim PathDiagnosticLocation::create(const ProgramPoint& P, 586226633Sdim const SourceManager &SMng) { 587226633Sdim 588226633Sdim const Stmt* S = 0; 589249423Sdim if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { 590226633Sdim const CFGBlock *BSrc = BE->getSrc(); 591226633Sdim S = BSrc->getTerminatorCondition(); 592249423Sdim } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { 593243830Sdim S = SP->getStmt(); 594249423Sdim if (P.getAs<PostStmtPurgeDeadSymbols>()) 595249423Sdim return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); 596249423Sdim } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { 597249423Sdim return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), 598249423Sdim SMng); 599249423Sdim } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { 600239462Sdim return PathDiagnosticLocation(PIE->getLocation(), SMng); 601249423Sdim } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { 602239462Sdim return getLocationForCaller(CE->getCalleeContext(), 603239462Sdim CE->getLocationContext(), 604239462Sdim SMng); 605249423Sdim } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { 606239462Sdim return getLocationForCaller(CEE->getCalleeContext(), 607239462Sdim CEE->getLocationContext(), 608239462Sdim SMng); 609249423Sdim } else { 610243830Sdim llvm_unreachable("Unexpected ProgramPoint"); 611243830Sdim } 612226633Sdim 613226633Sdim return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 614226633Sdim} 615226633Sdim 616251662Sdimconst Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { 617251662Sdim ProgramPoint P = N->getLocation(); 618251662Sdim if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) 619251662Sdim return SP->getStmt(); 620251662Sdim if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) 621251662Sdim return BE->getSrc()->getTerminator(); 622251662Sdim if (Optional<CallEnter> CE = P.getAs<CallEnter>()) 623251662Sdim return CE->getCallExpr(); 624251662Sdim if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) 625251662Sdim return CEE->getCalleeContext()->getCallSite(); 626251662Sdim if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) 627251662Sdim return PIPP->getInitializer()->getInit(); 628251662Sdim 629251662Sdim return 0; 630251662Sdim} 631251662Sdim 632251662Sdimconst Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { 633251662Sdim for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) { 634251662Sdim if (const Stmt *S = getStmt(N)) { 635251662Sdim // Check if the statement is '?' or '&&'/'||'. These are "merges", 636251662Sdim // not actual statement points. 637251662Sdim switch (S->getStmtClass()) { 638251662Sdim case Stmt::ChooseExprClass: 639251662Sdim case Stmt::BinaryConditionalOperatorClass: 640251662Sdim case Stmt::ConditionalOperatorClass: 641251662Sdim continue; 642251662Sdim case Stmt::BinaryOperatorClass: { 643251662Sdim BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); 644251662Sdim if (Op == BO_LAnd || Op == BO_LOr) 645251662Sdim continue; 646251662Sdim break; 647251662Sdim } 648251662Sdim default: 649251662Sdim break; 650251662Sdim } 651251662Sdim // We found the statement, so return it. 652251662Sdim return S; 653251662Sdim } 654251662Sdim } 655251662Sdim 656251662Sdim return 0; 657251662Sdim} 658251662Sdim 659226633SdimPathDiagnosticLocation 660251662Sdim PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, 661226633Sdim const SourceManager &SM) { 662226633Sdim assert(N && "Cannot create a location with a null node."); 663251662Sdim const Stmt *S = getStmt(N); 664226633Sdim 665251662Sdim if (!S) 666251662Sdim S = getNextStmt(N); 667226633Sdim 668251662Sdim if (S) { 669251662Sdim ProgramPoint P = N->getLocation(); 670251662Sdim const LocationContext *LC = N->getLocationContext(); 671226633Sdim 672251662Sdim // For member expressions, return the location of the '.' or '->'. 673251662Sdim if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) 674251662Sdim return PathDiagnosticLocation::createMemberLoc(ME, SM); 675251662Sdim 676251662Sdim // For binary operators, return the location of the operator. 677251662Sdim if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) 678251662Sdim return PathDiagnosticLocation::createOperatorLoc(B, SM); 679251662Sdim 680251662Sdim if (P.getAs<PostStmtPurgeDeadSymbols>()) 681251662Sdim return PathDiagnosticLocation::createEnd(S, SM, LC); 682251662Sdim 683243830Sdim if (S->getLocStart().isValid()) 684243830Sdim return PathDiagnosticLocation(S, SM, LC); 685243830Sdim return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); 686243830Sdim } 687243830Sdim 688226633Sdim return createDeclEnd(N->getLocationContext(), SM); 689226633Sdim} 690226633Sdim 691226633SdimPathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 692226633Sdim const PathDiagnosticLocation &PDL) { 693226633Sdim FullSourceLoc L = PDL.asLocation(); 694226633Sdim return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 695226633Sdim} 696226633Sdim 697226633SdimFullSourceLoc 698226633Sdim PathDiagnosticLocation::genLocation(SourceLocation L, 699234353Sdim LocationOrAnalysisDeclContext LAC) const { 700218887Sdim assert(isValid()); 701218887Sdim // Note that we want a 'switch' here so that the compiler can warn us in 702218887Sdim // case we add more cases. 703218887Sdim switch (K) { 704218887Sdim case SingleLocK: 705218887Sdim case RangeK: 706218887Sdim break; 707218887Sdim case StmtK: 708234353Sdim // Defensive checking. 709234353Sdim if (!S) 710234353Sdim break; 711226633Sdim return FullSourceLoc(getValidSourceLocation(S, LAC), 712226633Sdim const_cast<SourceManager&>(*SM)); 713218887Sdim case DeclK: 714234353Sdim // Defensive checking. 715234353Sdim if (!D) 716234353Sdim break; 717218887Sdim return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 718218887Sdim } 719218887Sdim 720226633Sdim return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 721218887Sdim} 722218887Sdim 723226633SdimPathDiagnosticRange 724234353Sdim PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 725218887Sdim assert(isValid()); 726218887Sdim // Note that we want a 'switch' here so that the compiler can warn us in 727218887Sdim // case we add more cases. 728218887Sdim switch (K) { 729218887Sdim case SingleLocK: 730226633Sdim return PathDiagnosticRange(SourceRange(Loc,Loc), true); 731218887Sdim case RangeK: 732218887Sdim break; 733218887Sdim case StmtK: { 734218887Sdim const Stmt *S = asStmt(); 735218887Sdim switch (S->getStmtClass()) { 736218887Sdim default: 737218887Sdim break; 738218887Sdim case Stmt::DeclStmtClass: { 739218887Sdim const DeclStmt *DS = cast<DeclStmt>(S); 740218887Sdim if (DS->isSingleDecl()) { 741218887Sdim // Should always be the case, but we'll be defensive. 742218887Sdim return SourceRange(DS->getLocStart(), 743218887Sdim DS->getSingleDecl()->getLocation()); 744218887Sdim } 745218887Sdim break; 746218887Sdim } 747218887Sdim // FIXME: Provide better range information for different 748218887Sdim // terminators. 749218887Sdim case Stmt::IfStmtClass: 750218887Sdim case Stmt::WhileStmtClass: 751218887Sdim case Stmt::DoStmtClass: 752218887Sdim case Stmt::ForStmtClass: 753218887Sdim case Stmt::ChooseExprClass: 754218887Sdim case Stmt::IndirectGotoStmtClass: 755218887Sdim case Stmt::SwitchStmtClass: 756218887Sdim case Stmt::BinaryConditionalOperatorClass: 757218887Sdim case Stmt::ConditionalOperatorClass: 758218887Sdim case Stmt::ObjCForCollectionStmtClass: { 759226633Sdim SourceLocation L = getValidSourceLocation(S, LAC); 760218887Sdim return SourceRange(L, L); 761218887Sdim } 762218887Sdim } 763226633Sdim SourceRange R = S->getSourceRange(); 764226633Sdim if (R.isValid()) 765226633Sdim return R; 766226633Sdim break; 767218887Sdim } 768218887Sdim case DeclK: 769218887Sdim if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 770218887Sdim return MD->getSourceRange(); 771218887Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 772218887Sdim if (Stmt *Body = FD->getBody()) 773218887Sdim return Body->getSourceRange(); 774218887Sdim } 775218887Sdim else { 776218887Sdim SourceLocation L = D->getLocation(); 777218887Sdim return PathDiagnosticRange(SourceRange(L, L), true); 778218887Sdim } 779218887Sdim } 780218887Sdim 781226633Sdim return SourceRange(Loc,Loc); 782218887Sdim} 783218887Sdim 784218887Sdimvoid PathDiagnosticLocation::flatten() { 785218887Sdim if (K == StmtK) { 786218887Sdim K = RangeK; 787218887Sdim S = 0; 788218887Sdim D = 0; 789218887Sdim } 790218887Sdim else if (K == DeclK) { 791218887Sdim K = SingleLocK; 792218887Sdim S = 0; 793218887Sdim D = 0; 794218887Sdim } 795218887Sdim} 796218887Sdim 797218887Sdim//===----------------------------------------------------------------------===// 798234353Sdim// Manipulation of PathDiagnosticCallPieces. 799234353Sdim//===----------------------------------------------------------------------===// 800234353Sdim 801234353SdimPathDiagnosticCallPiece * 802234353SdimPathDiagnosticCallPiece::construct(const ExplodedNode *N, 803239462Sdim const CallExitEnd &CE, 804234353Sdim const SourceManager &SM) { 805239462Sdim const Decl *caller = CE.getLocationContext()->getDecl(); 806239462Sdim PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 807239462Sdim CE.getLocationContext(), 808239462Sdim SM); 809234353Sdim return new PathDiagnosticCallPiece(caller, pos); 810234353Sdim} 811234353Sdim 812234353SdimPathDiagnosticCallPiece * 813234353SdimPathDiagnosticCallPiece::construct(PathPieces &path, 814234353Sdim const Decl *caller) { 815234353Sdim PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller); 816234353Sdim path.clear(); 817234353Sdim path.push_front(C); 818234353Sdim return C; 819234353Sdim} 820234353Sdim 821234353Sdimvoid PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 822234353Sdim const SourceManager &SM) { 823239462Sdim const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 824239462Sdim Callee = CalleeCtx->getDecl(); 825239462Sdim 826239462Sdim callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 827239462Sdim callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 828234353Sdim} 829234353Sdim 830249423Sdimstatic inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, 831249423Sdim StringRef Prefix = StringRef()) { 832249423Sdim if (!D->getIdentifier()) 833249423Sdim return; 834249423Sdim Out << Prefix << '\'' << *D << '\''; 835249423Sdim} 836249423Sdim 837249423Sdimstatic bool describeCodeDecl(raw_ostream &Out, const Decl *D, 838249423Sdim bool ExtendedDescription, 839249423Sdim StringRef Prefix = StringRef()) { 840249423Sdim if (!D) 841249423Sdim return false; 842249423Sdim 843249423Sdim if (isa<BlockDecl>(D)) { 844249423Sdim if (ExtendedDescription) 845249423Sdim Out << Prefix << "anonymous block"; 846249423Sdim return ExtendedDescription; 847249423Sdim } 848249423Sdim 849249423Sdim if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { 850249423Sdim Out << Prefix; 851249423Sdim if (ExtendedDescription && !MD->isUserProvided()) { 852249423Sdim if (MD->isExplicitlyDefaulted()) 853249423Sdim Out << "defaulted "; 854249423Sdim else 855249423Sdim Out << "implicit "; 856249423Sdim } 857249423Sdim 858249423Sdim if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) { 859249423Sdim if (CD->isDefaultConstructor()) 860249423Sdim Out << "default "; 861249423Sdim else if (CD->isCopyConstructor()) 862249423Sdim Out << "copy "; 863249423Sdim else if (CD->isMoveConstructor()) 864249423Sdim Out << "move "; 865249423Sdim 866249423Sdim Out << "constructor"; 867249423Sdim describeClass(Out, MD->getParent(), " for "); 868249423Sdim 869249423Sdim } else if (isa<CXXDestructorDecl>(MD)) { 870249423Sdim if (!MD->isUserProvided()) { 871249423Sdim Out << "destructor"; 872249423Sdim describeClass(Out, MD->getParent(), " for "); 873249423Sdim } else { 874249423Sdim // Use ~Foo for explicitly-written destructors. 875249423Sdim Out << "'" << *MD << "'"; 876249423Sdim } 877249423Sdim 878249423Sdim } else if (MD->isCopyAssignmentOperator()) { 879249423Sdim Out << "copy assignment operator"; 880249423Sdim describeClass(Out, MD->getParent(), " for "); 881249423Sdim 882249423Sdim } else if (MD->isMoveAssignmentOperator()) { 883249423Sdim Out << "move assignment operator"; 884249423Sdim describeClass(Out, MD->getParent(), " for "); 885249423Sdim 886249423Sdim } else { 887249423Sdim if (MD->getParent()->getIdentifier()) 888249423Sdim Out << "'" << *MD->getParent() << "::" << *MD << "'"; 889249423Sdim else 890249423Sdim Out << "'" << *MD << "'"; 891249423Sdim } 892249423Sdim 893249423Sdim return true; 894249423Sdim } 895249423Sdim 896249423Sdim Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\''; 897249423Sdim return true; 898249423Sdim} 899249423Sdim 900234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece> 901234353SdimPathDiagnosticCallPiece::getCallEnterEvent() const { 902234353Sdim if (!Callee) 903234353Sdim return 0; 904249423Sdim 905234353Sdim SmallString<256> buf; 906234353Sdim llvm::raw_svector_ostream Out(buf); 907249423Sdim 908249423Sdim Out << "Calling "; 909249423Sdim describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); 910249423Sdim 911249423Sdim assert(callEnter.asLocation().isValid()); 912249423Sdim return new PathDiagnosticEventPiece(callEnter, Out.str()); 913234353Sdim} 914234353Sdim 915234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece> 916234353SdimPathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 917249423Sdim if (!callEnterWithin.asLocation().isValid()) 918249423Sdim return 0; 919249423Sdim if (Callee->isImplicit()) 920249423Sdim return 0; 921249423Sdim if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) 922249423Sdim if (MD->isDefaulted()) 923249423Sdim return 0; 924249423Sdim 925234353Sdim SmallString<256> buf; 926234353Sdim llvm::raw_svector_ostream Out(buf); 927249423Sdim 928249423Sdim Out << "Entered call"; 929249423Sdim describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); 930249423Sdim 931249423Sdim return new PathDiagnosticEventPiece(callEnterWithin, Out.str()); 932234353Sdim} 933234353Sdim 934234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece> 935234353SdimPathDiagnosticCallPiece::getCallExitEvent() const { 936234353Sdim if (NoExit) 937234353Sdim return 0; 938249423Sdim 939234353Sdim SmallString<256> buf; 940234353Sdim llvm::raw_svector_ostream Out(buf); 941249423Sdim 942249423Sdim if (!CallStackMessage.empty()) { 943234353Sdim Out << CallStackMessage; 944249423Sdim } else { 945249423Sdim bool DidDescribe = describeCodeDecl(Out, Callee, 946249423Sdim /*ExtendedDescription=*/false, 947249423Sdim "Returning from "); 948249423Sdim if (!DidDescribe) 949249423Sdim Out << "Returning to caller"; 950249423Sdim } 951249423Sdim 952249423Sdim assert(callReturn.asLocation().isValid()); 953234353Sdim return new PathDiagnosticEventPiece(callReturn, Out.str()); 954234353Sdim} 955234353Sdim 956234353Sdimstatic void compute_path_size(const PathPieces &pieces, unsigned &size) { 957234353Sdim for (PathPieces::const_iterator it = pieces.begin(), 958234353Sdim et = pieces.end(); it != et; ++it) { 959234353Sdim const PathDiagnosticPiece *piece = it->getPtr(); 960234353Sdim if (const PathDiagnosticCallPiece *cp = 961234353Sdim dyn_cast<PathDiagnosticCallPiece>(piece)) { 962234353Sdim compute_path_size(cp->path, size); 963234353Sdim } 964234353Sdim else 965234353Sdim ++size; 966234353Sdim } 967234353Sdim} 968234353Sdim 969234353Sdimunsigned PathDiagnostic::full_size() { 970234353Sdim unsigned size = 0; 971234353Sdim compute_path_size(path, size); 972234353Sdim return size; 973234353Sdim} 974234353Sdim 975234353Sdim//===----------------------------------------------------------------------===// 976218887Sdim// FoldingSet profiling methods. 977218887Sdim//===----------------------------------------------------------------------===// 978218887Sdim 979218887Sdimvoid PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 980226633Sdim ID.AddInteger(Range.getBegin().getRawEncoding()); 981226633Sdim ID.AddInteger(Range.getEnd().getRawEncoding()); 982226633Sdim ID.AddInteger(Loc.getRawEncoding()); 983218887Sdim return; 984218887Sdim} 985218887Sdim 986218887Sdimvoid PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 987218887Sdim ID.AddInteger((unsigned) getKind()); 988218887Sdim ID.AddString(str); 989218887Sdim // FIXME: Add profiling support for code hints. 990218887Sdim ID.AddInteger((unsigned) getDisplayHint()); 991239462Sdim ArrayRef<SourceRange> Ranges = getRanges(); 992239462Sdim for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 993239462Sdim I != E; ++I) { 994218887Sdim ID.AddInteger(I->getBegin().getRawEncoding()); 995218887Sdim ID.AddInteger(I->getEnd().getRawEncoding()); 996218887Sdim } 997218887Sdim} 998218887Sdim 999234353Sdimvoid PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1000234353Sdim PathDiagnosticPiece::Profile(ID); 1001234353Sdim for (PathPieces::const_iterator it = path.begin(), 1002234353Sdim et = path.end(); it != et; ++it) { 1003234353Sdim ID.Add(**it); 1004234353Sdim } 1005234353Sdim} 1006234353Sdim 1007218887Sdimvoid PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1008218887Sdim PathDiagnosticPiece::Profile(ID); 1009218887Sdim ID.Add(Pos); 1010218887Sdim} 1011218887Sdim 1012218887Sdimvoid PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1013218887Sdim PathDiagnosticPiece::Profile(ID); 1014218887Sdim for (const_iterator I = begin(), E = end(); I != E; ++I) 1015218887Sdim ID.Add(*I); 1016218887Sdim} 1017218887Sdim 1018218887Sdimvoid PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1019218887Sdim PathDiagnosticSpotPiece::Profile(ID); 1020234353Sdim for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 1021234353Sdim I != E; ++I) 1022218887Sdim ID.Add(**I); 1023218887Sdim} 1024218887Sdim 1025218887Sdimvoid PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 1026243830Sdim ID.Add(getLocation()); 1027218887Sdim ID.AddString(BugType); 1028243830Sdim ID.AddString(VerboseDesc); 1029218887Sdim ID.AddString(Category); 1030234353Sdim} 1031234353Sdim 1032234353Sdimvoid PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 1033234353Sdim Profile(ID); 1034234353Sdim for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) 1035234353Sdim ID.Add(**I); 1036218887Sdim for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 1037218887Sdim ID.AddString(*I); 1038218887Sdim} 1039234353Sdim 1040234353SdimStackHintGenerator::~StackHintGenerator() {} 1041234353Sdim 1042234353Sdimstd::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ 1043234353Sdim ProgramPoint P = N->getLocation(); 1044249423Sdim CallExitEnd CExit = P.castAs<CallExitEnd>(); 1045234353Sdim 1046239462Sdim // FIXME: Use CallEvent to abstract this over all calls. 1047249423Sdim const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); 1048239462Sdim const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); 1049234353Sdim if (!CE) 1050234353Sdim return ""; 1051234353Sdim 1052234353Sdim if (!N) 1053234353Sdim return getMessageForSymbolNotFound(); 1054234353Sdim 1055234353Sdim // Check if one of the parameters are set to the interesting symbol. 1056234353Sdim ProgramStateRef State = N->getState(); 1057234353Sdim const LocationContext *LCtx = N->getLocationContext(); 1058234353Sdim unsigned ArgIndex = 0; 1059234353Sdim for (CallExpr::const_arg_iterator I = CE->arg_begin(), 1060234353Sdim E = CE->arg_end(); I != E; ++I, ++ArgIndex){ 1061234353Sdim SVal SV = State->getSVal(*I, LCtx); 1062234353Sdim 1063234353Sdim // Check if the variable corresponding to the symbol is passed by value. 1064234353Sdim SymbolRef AS = SV.getAsLocSymbol(); 1065234353Sdim if (AS == Sym) { 1066234353Sdim return getMessageForArg(*I, ArgIndex); 1067234353Sdim } 1068234353Sdim 1069234353Sdim // Check if the parameter is a pointer to the symbol. 1070249423Sdim if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { 1071234353Sdim SVal PSV = State->getSVal(Reg->getRegion()); 1072234353Sdim SymbolRef AS = PSV.getAsLocSymbol(); 1073234353Sdim if (AS == Sym) { 1074234353Sdim return getMessageForArg(*I, ArgIndex); 1075234353Sdim } 1076234353Sdim } 1077234353Sdim } 1078234353Sdim 1079234353Sdim // Check if we are returning the interesting symbol. 1080234353Sdim SVal SV = State->getSVal(CE, LCtx); 1081234353Sdim SymbolRef RetSym = SV.getAsLocSymbol(); 1082234353Sdim if (RetSym == Sym) { 1083234353Sdim return getMessageForReturn(CE); 1084234353Sdim } 1085234353Sdim 1086234353Sdim return getMessageForSymbolNotFound(); 1087234353Sdim} 1088234353Sdim 1089243830Sdimstd::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, 1090243830Sdim unsigned ArgIndex) { 1091243830Sdim // Printed parameters start at 1, not 0. 1092243830Sdim ++ArgIndex; 1093234353Sdim 1094234353Sdim SmallString<200> buf; 1095234353Sdim llvm::raw_svector_ostream os(buf); 1096234353Sdim 1097243830Sdim os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) 1098243830Sdim << " parameter"; 1099234353Sdim 1100234353Sdim return os.str(); 1101234353Sdim} 1102