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