PathDiagnostic.cpp revision 3a46f5fd1709f6df03bbb8b0abf84052dc0f39ff
1860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===// 2860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// 3860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// The LLVM Compiler Infrastructure 4860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// 5860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// This file is distributed under the University of Illinois Open Source 6860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// License. See LICENSE.TXT for details. 7860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// 8860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//===----------------------------------------------------------------------===// 9860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// 10860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// This file defines the PathDiagnostic-related interfaces. 11860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// 12860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//===----------------------------------------------------------------------===// 13860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 14860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 15860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 16860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/Basic/SourceManager.h" 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/Expr.h" 18860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/Decl.h" 19860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/DeclCXX.h" 20860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/DeclObjC.h" 21860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/ParentMap.h" 22860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/StmtCXX.h" 23860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "llvm/ADT/SmallString.h" 24860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 25860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootusing namespace clang; 26860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootusing namespace ento; 27860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 28860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootbool PathDiagnosticMacroPiece::containsEvent() const { 29860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 30860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root I!=E; ++I) { 31860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (isa<PathDiagnosticEventPiece>(*I)) 32860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return true; 33860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I)) 34860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (MP->containsEvent()) 35860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return true; 36860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 37860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return false; 38860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root} 39860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 40860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootstatic StringRef StripTrailingDots(StringRef s) { 41860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root for (StringRef::size_type i = s.size(); i != 0; --i) 42860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (s[i - 1] != '.') 43860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return s.substr(0, i); 44860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root return ""; 45860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root} 46860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 47860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 48860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Kind k, DisplayHint hint) 49860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root : str(StripTrailingDots(s)), kind(k), Hint(hint) {} 50860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 51860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 52860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root : kind(k), Hint(hint) {} 53860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 54860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticPiece::~PathDiagnosticPiece() {} 55860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 56860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} 57860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 58860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} 59860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 60860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 61860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathPieces::~PathPieces() {} 62860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 63860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootvoid PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, 64860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root bool ShouldFlattenMacros) const { 65860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 66860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root PathDiagnosticPiece *Piece = I->getPtr(); 67860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 68860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root switch (Piece->getKind()) { 69860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root case PathDiagnosticPiece::Call: { 70860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece); 71860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter = 72860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Call->getCallEnterEvent(); 73860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (CallEnter) 74860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Current.push_back(CallEnter); 75860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros); 76860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = 77860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Call->getCallExitEvent(); 78860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (callExit) 79860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Current.push_back(callExit); 80860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root break; 81860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 82860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root case PathDiagnosticPiece::Macro: { 83860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece); 84860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root if (ShouldFlattenMacros) { 85860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 86860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } else { 87860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Current.push_back(Piece); 88860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root PathPieces NewPath; 89860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 90860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // FIXME: This probably shouldn't mutate the original path piece. 91860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Macro->subPieces = NewPath; 92860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 93860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root break; 94860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 95860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root case PathDiagnosticPiece::Event: 96860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root case PathDiagnosticPiece::ControlFlow: 97860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Current.push_back(Piece); 98860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root break; 99860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 100860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root } 101860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root} 102860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 103860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 104860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnostic::~PathDiagnostic() {} 105860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 106860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnostic::PathDiagnostic(const Decl *declWithIssue, 107860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root StringRef bugtype, StringRef verboseDesc, 108860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root StringRef shortDesc, StringRef category) 109860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root : DeclWithIssue(declWithIssue), 110860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root BugType(StripTrailingDots(bugtype)), 111860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root VerboseDesc(StripTrailingDots(verboseDesc)), 112860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root ShortDesc(StripTrailingDots(shortDesc)), 113860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root Category(StripTrailingDots(category)), 114860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root path(pathImpl) {} 115860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 116860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootvoid PathDiagnosticConsumer::anchor() { } 117860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root 118860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticConsumer::~PathDiagnosticConsumer() { 119860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root // Delete the contents of the FoldingSet if it isn't empty already. 120860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root for (llvm::FoldingSet<PathDiagnostic>::iterator it = 121 Diags.begin(), et = Diags.end() ; it != et ; ++it) { 122 delete &*it; 123 } 124} 125 126void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { 127 llvm::OwningPtr<PathDiagnostic> OwningD(D); 128 129 if (!D || D->path.empty()) 130 return; 131 132 // We need to flatten the locations (convert Stmt* to locations) because 133 // the referenced statements may be freed by the time the diagnostics 134 // are emitted. 135 D->flattenLocations(); 136 137 // If the PathDiagnosticConsumer does not support diagnostics that 138 // cross file boundaries, prune out such diagnostics now. 139 if (!supportsCrossFileDiagnostics()) { 140 // Verify that the entire path is from the same FileID. 141 FileID FID; 142 const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager(); 143 llvm::SmallVector<const PathPieces *, 5> WorkList; 144 WorkList.push_back(&D->path); 145 146 while (!WorkList.empty()) { 147 const PathPieces &path = *WorkList.back(); 148 WorkList.pop_back(); 149 150 for (PathPieces::const_iterator I = path.begin(), E = path.end(); 151 I != E; ++I) { 152 const PathDiagnosticPiece *piece = I->getPtr(); 153 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 154 155 if (FID.isInvalid()) { 156 FID = SMgr.getFileID(L); 157 } else if (SMgr.getFileID(L) != FID) 158 return; // FIXME: Emit a warning? 159 160 // Check the source ranges. 161 ArrayRef<SourceRange> Ranges = piece->getRanges(); 162 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), 163 E = Ranges.end(); I != E; ++I) { 164 SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); 165 if (!L.isFileID() || SMgr.getFileID(L) != FID) 166 return; // FIXME: Emit a warning? 167 L = SMgr.getExpansionLoc(I->getEnd()); 168 if (!L.isFileID() || SMgr.getFileID(L) != FID) 169 return; // FIXME: Emit a warning? 170 } 171 172 if (const PathDiagnosticCallPiece *call = 173 dyn_cast<PathDiagnosticCallPiece>(piece)) { 174 WorkList.push_back(&call->path); 175 } 176 else if (const PathDiagnosticMacroPiece *macro = 177 dyn_cast<PathDiagnosticMacroPiece>(piece)) { 178 WorkList.push_back(¯o->subPieces); 179 } 180 } 181 } 182 183 if (FID.isInvalid()) 184 return; // FIXME: Emit a warning? 185 } 186 187 // Profile the node to see if we already have something matching it 188 llvm::FoldingSetNodeID profile; 189 D->Profile(profile); 190 void *InsertPos = 0; 191 192 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 193 // Keep the PathDiagnostic with the shorter path. 194 // Note, the enclosing routine is called in deterministic order, so the 195 // results will be consistent between runs (no reason to break ties if the 196 // size is the same). 197 const unsigned orig_size = orig->full_size(); 198 const unsigned new_size = D->full_size(); 199 if (orig_size <= new_size) 200 return; 201 202 Diags.RemoveNode(orig); 203 delete orig; 204 } 205 206 Diags.InsertNode(OwningD.take()); 207} 208 209 210namespace { 211struct CompareDiagnostics { 212 // Compare if 'X' is "<" than 'Y'. 213 bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { 214 // First compare by location 215 const FullSourceLoc &XLoc = X->getLocation().asLocation(); 216 const FullSourceLoc &YLoc = Y->getLocation().asLocation(); 217 if (XLoc < YLoc) 218 return true; 219 if (XLoc != YLoc) 220 return false; 221 222 // Next, compare by bug type. 223 StringRef XBugType = X->getBugType(); 224 StringRef YBugType = Y->getBugType(); 225 if (XBugType < YBugType) 226 return true; 227 if (XBugType != YBugType) 228 return false; 229 230 // Next, compare by bug description. 231 StringRef XDesc = X->getVerboseDescription(); 232 StringRef YDesc = Y->getVerboseDescription(); 233 if (XDesc < YDesc) 234 return true; 235 if (XDesc != YDesc) 236 return false; 237 238 // FIXME: Further refine by comparing PathDiagnosticPieces? 239 return false; 240 } 241}; 242} 243 244void PathDiagnosticConsumer::FlushDiagnostics( 245 PathDiagnosticConsumer::FilesMade *Files) { 246 if (flushed) 247 return; 248 249 flushed = true; 250 251 std::vector<const PathDiagnostic *> BatchDiags; 252 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), 253 et = Diags.end(); it != et; ++it) { 254 BatchDiags.push_back(&*it); 255 } 256 257 // Clear out the FoldingSet. 258 Diags.clear(); 259 260 // Sort the diagnostics so that they are always emitted in a deterministic 261 // order. 262 if (!BatchDiags.empty()) 263 std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics()); 264 265 FlushDiagnosticsImpl(BatchDiags, Files); 266 267 // Delete the flushed diagnostics. 268 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), 269 et = BatchDiags.end(); it != et; ++it) { 270 const PathDiagnostic *D = *it; 271 delete D; 272 } 273} 274 275void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 276 StringRef ConsumerName, 277 StringRef FileName) { 278 llvm::FoldingSetNodeID NodeID; 279 NodeID.Add(PD); 280 void *InsertPos; 281 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 282 if (!Entry) { 283 Entry = Alloc.Allocate<PDFileEntry>(); 284 Entry = new (Entry) PDFileEntry(NodeID); 285 InsertNode(Entry, InsertPos); 286 } 287 288 // Allocate persistent storage for the file name. 289 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); 290 memcpy(FileName_cstr, FileName.data(), FileName.size()); 291 292 Entry->files.push_back(std::make_pair(ConsumerName, 293 StringRef(FileName_cstr, 294 FileName.size()))); 295} 296 297PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 298PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 299 llvm::FoldingSetNodeID NodeID; 300 NodeID.Add(PD); 301 void *InsertPos; 302 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); 303 if (!Entry) 304 return 0; 305 return &Entry->files; 306} 307 308//===----------------------------------------------------------------------===// 309// PathDiagnosticLocation methods. 310//===----------------------------------------------------------------------===// 311 312static SourceLocation getValidSourceLocation(const Stmt* S, 313 LocationOrAnalysisDeclContext LAC, 314 bool UseEnd = false) { 315 SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart(); 316 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " 317 "be passed to PathDiagnosticLocation upon creation."); 318 319 // S might be a temporary statement that does not have a location in the 320 // source code, so find an enclosing statement and use its location. 321 if (!L.isValid()) { 322 323 AnalysisDeclContext *ADC; 324 if (LAC.is<const LocationContext*>()) 325 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 326 else 327 ADC = LAC.get<AnalysisDeclContext*>(); 328 329 ParentMap &PM = ADC->getParentMap(); 330 331 const Stmt *Parent = S; 332 do { 333 Parent = PM.getParent(Parent); 334 335 // In rare cases, we have implicit top-level expressions, 336 // such as arguments for implicit member initializers. 337 // In this case, fall back to the start of the body (even if we were 338 // asked for the statement end location). 339 if (!Parent) { 340 const Stmt *Body = ADC->getBody(); 341 if (Body) 342 L = Body->getLocStart(); 343 else 344 L = ADC->getDecl()->getLocEnd(); 345 break; 346 } 347 348 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart(); 349 } while (!L.isValid()); 350 } 351 352 return L; 353} 354 355static PathDiagnosticLocation 356getLocationForCaller(const StackFrameContext *SFC, 357 const LocationContext *CallerCtx, 358 const SourceManager &SM) { 359 const CFGBlock &Block = *SFC->getCallSiteBlock(); 360 CFGElement Source = Block[SFC->getIndex()]; 361 362 switch (Source.getKind()) { 363 case CFGElement::Invalid: 364 llvm_unreachable("Invalid CFGElement"); 365 case CFGElement::Statement: 366 return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(), 367 SM, CallerCtx); 368 case CFGElement::Initializer: { 369 const CFGInitializer &Init = cast<CFGInitializer>(Source); 370 return PathDiagnosticLocation(Init.getInitializer()->getInit(), 371 SM, CallerCtx); 372 } 373 case CFGElement::AutomaticObjectDtor: { 374 const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source); 375 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 376 SM, CallerCtx); 377 } 378 case CFGElement::BaseDtor: 379 case CFGElement::MemberDtor: { 380 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); 381 if (const Stmt *CallerBody = CallerInfo->getBody()) 382 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); 383 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); 384 } 385 case CFGElement::TemporaryDtor: 386 llvm_unreachable("not yet implemented!"); 387 } 388 389 llvm_unreachable("Unknown CFGElement kind"); 390} 391 392 393PathDiagnosticLocation 394 PathDiagnosticLocation::createBegin(const Decl *D, 395 const SourceManager &SM) { 396 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 397} 398 399PathDiagnosticLocation 400 PathDiagnosticLocation::createBegin(const Stmt *S, 401 const SourceManager &SM, 402 LocationOrAnalysisDeclContext LAC) { 403 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 404 SM, SingleLocK); 405} 406 407 408PathDiagnosticLocation 409PathDiagnosticLocation::createEnd(const Stmt *S, 410 const SourceManager &SM, 411 LocationOrAnalysisDeclContext LAC) { 412 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) 413 return createEndBrace(CS, SM); 414 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 415 SM, SingleLocK); 416} 417 418PathDiagnosticLocation 419 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 420 const SourceManager &SM) { 421 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 422} 423 424PathDiagnosticLocation 425 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 426 const SourceManager &SM) { 427 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 428} 429 430PathDiagnosticLocation 431 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 432 const SourceManager &SM) { 433 SourceLocation L = CS->getLBracLoc(); 434 return PathDiagnosticLocation(L, SM, SingleLocK); 435} 436 437PathDiagnosticLocation 438 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 439 const SourceManager &SM) { 440 SourceLocation L = CS->getRBracLoc(); 441 return PathDiagnosticLocation(L, SM, SingleLocK); 442} 443 444PathDiagnosticLocation 445 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 446 const SourceManager &SM) { 447 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 448 if (const CompoundStmt *CS = 449 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 450 if (!CS->body_empty()) { 451 SourceLocation Loc = (*CS->body_begin())->getLocStart(); 452 return PathDiagnosticLocation(Loc, SM, SingleLocK); 453 } 454 455 return PathDiagnosticLocation(); 456} 457 458PathDiagnosticLocation 459 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 460 const SourceManager &SM) { 461 SourceLocation L = LC->getDecl()->getBodyRBrace(); 462 return PathDiagnosticLocation(L, SM, SingleLocK); 463} 464 465PathDiagnosticLocation 466 PathDiagnosticLocation::create(const ProgramPoint& P, 467 const SourceManager &SMng) { 468 469 const Stmt* S = 0; 470 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 471 const CFGBlock *BSrc = BE->getSrc(); 472 S = BSrc->getTerminatorCondition(); 473 } 474 else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { 475 S = PS->getStmt(); 476 } 477 else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) { 478 return PathDiagnosticLocation(PIE->getLocation(), SMng); 479 } 480 else if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) { 481 return getLocationForCaller(CE->getCalleeContext(), 482 CE->getLocationContext(), 483 SMng); 484 } 485 else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P)) { 486 return getLocationForCaller(CEE->getCalleeContext(), 487 CEE->getLocationContext(), 488 SMng); 489 } 490 491 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 492} 493 494PathDiagnosticLocation 495 PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N, 496 const SourceManager &SM) { 497 assert(N && "Cannot create a location with a null node."); 498 499 const ExplodedNode *NI = N; 500 501 while (NI) { 502 ProgramPoint P = NI->getLocation(); 503 const LocationContext *LC = P.getLocationContext(); 504 if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) 505 return PathDiagnosticLocation(PS->getStmt(), SM, LC); 506 else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 507 const Stmt *Term = BE->getSrc()->getTerminator(); 508 if (Term) { 509 return PathDiagnosticLocation(Term, SM, LC); 510 } 511 } 512 NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); 513 } 514 515 return createDeclEnd(N->getLocationContext(), SM); 516} 517 518PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 519 const PathDiagnosticLocation &PDL) { 520 FullSourceLoc L = PDL.asLocation(); 521 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 522} 523 524FullSourceLoc 525 PathDiagnosticLocation::genLocation(SourceLocation L, 526 LocationOrAnalysisDeclContext LAC) const { 527 assert(isValid()); 528 // Note that we want a 'switch' here so that the compiler can warn us in 529 // case we add more cases. 530 switch (K) { 531 case SingleLocK: 532 case RangeK: 533 break; 534 case StmtK: 535 // Defensive checking. 536 if (!S) 537 break; 538 return FullSourceLoc(getValidSourceLocation(S, LAC), 539 const_cast<SourceManager&>(*SM)); 540 case DeclK: 541 // Defensive checking. 542 if (!D) 543 break; 544 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 545 } 546 547 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 548} 549 550PathDiagnosticRange 551 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 552 assert(isValid()); 553 // Note that we want a 'switch' here so that the compiler can warn us in 554 // case we add more cases. 555 switch (K) { 556 case SingleLocK: 557 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 558 case RangeK: 559 break; 560 case StmtK: { 561 const Stmt *S = asStmt(); 562 switch (S->getStmtClass()) { 563 default: 564 break; 565 case Stmt::DeclStmtClass: { 566 const DeclStmt *DS = cast<DeclStmt>(S); 567 if (DS->isSingleDecl()) { 568 // Should always be the case, but we'll be defensive. 569 return SourceRange(DS->getLocStart(), 570 DS->getSingleDecl()->getLocation()); 571 } 572 break; 573 } 574 // FIXME: Provide better range information for different 575 // terminators. 576 case Stmt::IfStmtClass: 577 case Stmt::WhileStmtClass: 578 case Stmt::DoStmtClass: 579 case Stmt::ForStmtClass: 580 case Stmt::ChooseExprClass: 581 case Stmt::IndirectGotoStmtClass: 582 case Stmt::SwitchStmtClass: 583 case Stmt::BinaryConditionalOperatorClass: 584 case Stmt::ConditionalOperatorClass: 585 case Stmt::ObjCForCollectionStmtClass: { 586 SourceLocation L = getValidSourceLocation(S, LAC); 587 return SourceRange(L, L); 588 } 589 } 590 SourceRange R = S->getSourceRange(); 591 if (R.isValid()) 592 return R; 593 break; 594 } 595 case DeclK: 596 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 597 return MD->getSourceRange(); 598 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 599 if (Stmt *Body = FD->getBody()) 600 return Body->getSourceRange(); 601 } 602 else { 603 SourceLocation L = D->getLocation(); 604 return PathDiagnosticRange(SourceRange(L, L), true); 605 } 606 } 607 608 return SourceRange(Loc,Loc); 609} 610 611void PathDiagnosticLocation::flatten() { 612 if (K == StmtK) { 613 K = RangeK; 614 S = 0; 615 D = 0; 616 } 617 else if (K == DeclK) { 618 K = SingleLocK; 619 S = 0; 620 D = 0; 621 } 622} 623 624//===----------------------------------------------------------------------===// 625// Manipulation of PathDiagnosticCallPieces. 626//===----------------------------------------------------------------------===// 627 628PathDiagnosticCallPiece * 629PathDiagnosticCallPiece::construct(const ExplodedNode *N, 630 const CallExitEnd &CE, 631 const SourceManager &SM) { 632 const Decl *caller = CE.getLocationContext()->getDecl(); 633 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 634 CE.getLocationContext(), 635 SM); 636 return new PathDiagnosticCallPiece(caller, pos); 637} 638 639PathDiagnosticCallPiece * 640PathDiagnosticCallPiece::construct(PathPieces &path, 641 const Decl *caller) { 642 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller); 643 path.clear(); 644 path.push_front(C); 645 return C; 646} 647 648void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 649 const SourceManager &SM) { 650 const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 651 Callee = CalleeCtx->getDecl(); 652 653 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 654 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 655} 656 657IntrusiveRefCntPtr<PathDiagnosticEventPiece> 658PathDiagnosticCallPiece::getCallEnterEvent() const { 659 if (!Callee) 660 return 0; 661 SmallString<256> buf; 662 llvm::raw_svector_ostream Out(buf); 663 if (isa<BlockDecl>(Callee)) 664 Out << "Calling anonymous block"; 665 else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee)) 666 Out << "Calling '" << *ND << "'"; 667 StringRef msg = Out.str(); 668 if (msg.empty()) 669 return 0; 670 return new PathDiagnosticEventPiece(callEnter, msg); 671} 672 673IntrusiveRefCntPtr<PathDiagnosticEventPiece> 674PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 675 SmallString<256> buf; 676 llvm::raw_svector_ostream Out(buf); 677 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller)) 678 Out << "Entered call from '" << *ND << "'"; 679 else 680 Out << "Entered call"; 681 StringRef msg = Out.str(); 682 if (msg.empty()) 683 return 0; 684 return new PathDiagnosticEventPiece(callEnterWithin, msg); 685} 686 687IntrusiveRefCntPtr<PathDiagnosticEventPiece> 688PathDiagnosticCallPiece::getCallExitEvent() const { 689 if (NoExit) 690 return 0; 691 SmallString<256> buf; 692 llvm::raw_svector_ostream Out(buf); 693 if (!CallStackMessage.empty()) 694 Out << CallStackMessage; 695 else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee)) 696 Out << "Returning from '" << *ND << "'"; 697 else 698 Out << "Returning to caller"; 699 return new PathDiagnosticEventPiece(callReturn, Out.str()); 700} 701 702static void compute_path_size(const PathPieces &pieces, unsigned &size) { 703 for (PathPieces::const_iterator it = pieces.begin(), 704 et = pieces.end(); it != et; ++it) { 705 const PathDiagnosticPiece *piece = it->getPtr(); 706 if (const PathDiagnosticCallPiece *cp = 707 dyn_cast<PathDiagnosticCallPiece>(piece)) { 708 compute_path_size(cp->path, size); 709 } 710 else 711 ++size; 712 } 713} 714 715unsigned PathDiagnostic::full_size() { 716 unsigned size = 0; 717 compute_path_size(path, size); 718 return size; 719} 720 721//===----------------------------------------------------------------------===// 722// FoldingSet profiling methods. 723//===----------------------------------------------------------------------===// 724 725void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 726 ID.AddInteger(Range.getBegin().getRawEncoding()); 727 ID.AddInteger(Range.getEnd().getRawEncoding()); 728 ID.AddInteger(Loc.getRawEncoding()); 729 return; 730} 731 732void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 733 ID.AddInteger((unsigned) getKind()); 734 ID.AddString(str); 735 // FIXME: Add profiling support for code hints. 736 ID.AddInteger((unsigned) getDisplayHint()); 737 ArrayRef<SourceRange> Ranges = getRanges(); 738 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 739 I != E; ++I) { 740 ID.AddInteger(I->getBegin().getRawEncoding()); 741 ID.AddInteger(I->getEnd().getRawEncoding()); 742 } 743} 744 745void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 746 PathDiagnosticPiece::Profile(ID); 747 for (PathPieces::const_iterator it = path.begin(), 748 et = path.end(); it != et; ++it) { 749 ID.Add(**it); 750 } 751} 752 753void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 754 PathDiagnosticPiece::Profile(ID); 755 ID.Add(Pos); 756} 757 758void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 759 PathDiagnosticPiece::Profile(ID); 760 for (const_iterator I = begin(), E = end(); I != E; ++I) 761 ID.Add(*I); 762} 763 764void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 765 PathDiagnosticSpotPiece::Profile(ID); 766 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); 767 I != E; ++I) 768 ID.Add(**I); 769} 770 771void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 772 ID.Add(getLocation()); 773 ID.AddString(BugType); 774 ID.AddString(VerboseDesc); 775 ID.AddString(Category); 776} 777 778void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 779 Profile(ID); 780 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) 781 ID.Add(**I); 782 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 783 ID.AddString(*I); 784} 785 786StackHintGenerator::~StackHintGenerator() {} 787 788std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ 789 ProgramPoint P = N->getLocation(); 790 const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P); 791 assert(CExit && "Stack Hints should be constructed at CallExitEnd points."); 792 793 // FIXME: Use CallEvent to abstract this over all calls. 794 const Stmt *CallSite = CExit->getCalleeContext()->getCallSite(); 795 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); 796 if (!CE) 797 return ""; 798 799 if (!N) 800 return getMessageForSymbolNotFound(); 801 802 // Check if one of the parameters are set to the interesting symbol. 803 ProgramStateRef State = N->getState(); 804 const LocationContext *LCtx = N->getLocationContext(); 805 unsigned ArgIndex = 0; 806 for (CallExpr::const_arg_iterator I = CE->arg_begin(), 807 E = CE->arg_end(); I != E; ++I, ++ArgIndex){ 808 SVal SV = State->getSVal(*I, LCtx); 809 810 // Check if the variable corresponding to the symbol is passed by value. 811 SymbolRef AS = SV.getAsLocSymbol(); 812 if (AS == Sym) { 813 return getMessageForArg(*I, ArgIndex); 814 } 815 816 // Check if the parameter is a pointer to the symbol. 817 if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) { 818 SVal PSV = State->getSVal(Reg->getRegion()); 819 SymbolRef AS = PSV.getAsLocSymbol(); 820 if (AS == Sym) { 821 return getMessageForArg(*I, ArgIndex); 822 } 823 } 824 } 825 826 // Check if we are returning the interesting symbol. 827 SVal SV = State->getSVal(CE, LCtx); 828 SymbolRef RetSym = SV.getAsLocSymbol(); 829 if (RetSym == Sym) { 830 return getMessageForReturn(CE); 831 } 832 833 return getMessageForSymbolNotFound(); 834} 835 836/// TODO: This is copied from clang diagnostics. Maybe we could just move it to 837/// some common place. (Same as HandleOrdinalModifier.) 838void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo, 839 llvm::raw_svector_ostream &Out) { 840 assert(ValNo != 0 && "ValNo must be strictly positive!"); 841 842 // We could use text forms for the first N ordinals, but the numeric 843 // forms are actually nicer in diagnostics because they stand out. 844 Out << ValNo; 845 846 // It is critically important that we do this perfectly for 847 // user-written sequences with over 100 elements. 848 switch (ValNo % 100) { 849 case 11: 850 case 12: 851 case 13: 852 Out << "th"; return; 853 default: 854 switch (ValNo % 10) { 855 case 1: Out << "st"; return; 856 case 2: Out << "nd"; return; 857 case 3: Out << "rd"; return; 858 default: Out << "th"; return; 859 } 860 } 861} 862 863std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, 864 unsigned ArgIndex) { 865 SmallString<200> buf; 866 llvm::raw_svector_ostream os(buf); 867 868 os << Msg << " via "; 869 // Printed parameters start at 1, not 0. 870 printOrdinal(++ArgIndex, os); 871 os << " parameter"; 872 873 return os.str(); 874} 875