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/ParentMap.h"
20 #include "clang/AST/StmtCXX.h"
21 #include "clang/Basic/SourceManager.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Support/raw_ostream.h"
26
27 using namespace clang;
28 using namespace ento;
29
containsEvent() const30 bool PathDiagnosticMacroPiece::containsEvent() const {
31 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
32 I!=E; ++I) {
33 if (isa<PathDiagnosticEventPiece>(*I))
34 return true;
35 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
36 if (MP->containsEvent())
37 return true;
38 }
39 return false;
40 }
41
StripTrailingDots(StringRef s)42 static StringRef StripTrailingDots(StringRef s) {
43 for (StringRef::size_type i = s.size(); i != 0; --i)
44 if (s[i - 1] != '.')
45 return s.substr(0, i);
46 return "";
47 }
48
PathDiagnosticPiece(StringRef s,Kind k,DisplayHint hint)49 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
50 Kind k, DisplayHint hint)
51 : str(StripTrailingDots(s)), kind(k), Hint(hint),
52 LastInMainSourceFile(false) {}
53
PathDiagnosticPiece(Kind k,DisplayHint hint)54 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
55 : kind(k), Hint(hint), LastInMainSourceFile(false) {}
56
~PathDiagnosticPiece()57 PathDiagnosticPiece::~PathDiagnosticPiece() {}
~PathDiagnosticEventPiece()58 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
~PathDiagnosticCallPiece()59 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
~PathDiagnosticControlFlowPiece()60 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
~PathDiagnosticMacroPiece()61 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
62
63
~PathPieces()64 PathPieces::~PathPieces() {}
65
flattenTo(PathPieces & Primary,PathPieces & Current,bool ShouldFlattenMacros) const66 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
67 bool ShouldFlattenMacros) const {
68 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
69 PathDiagnosticPiece *Piece = I->getPtr();
70
71 switch (Piece->getKind()) {
72 case PathDiagnosticPiece::Call: {
73 PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
74 IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
75 Call->getCallEnterEvent();
76 if (CallEnter)
77 Current.push_back(CallEnter);
78 Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
79 IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
80 Call->getCallExitEvent();
81 if (callExit)
82 Current.push_back(callExit);
83 break;
84 }
85 case PathDiagnosticPiece::Macro: {
86 PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
87 if (ShouldFlattenMacros) {
88 Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
89 } else {
90 Current.push_back(Piece);
91 PathPieces NewPath;
92 Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
93 // FIXME: This probably shouldn't mutate the original path piece.
94 Macro->subPieces = NewPath;
95 }
96 break;
97 }
98 case PathDiagnosticPiece::Event:
99 case PathDiagnosticPiece::ControlFlow:
100 Current.push_back(Piece);
101 break;
102 }
103 }
104 }
105
106
~PathDiagnostic()107 PathDiagnostic::~PathDiagnostic() {}
108
PathDiagnostic(const Decl * declWithIssue,StringRef bugtype,StringRef verboseDesc,StringRef shortDesc,StringRef category,PathDiagnosticLocation LocationToUnique,const Decl * DeclToUnique)109 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
110 StringRef bugtype, StringRef verboseDesc,
111 StringRef shortDesc, StringRef category,
112 PathDiagnosticLocation LocationToUnique,
113 const Decl *DeclToUnique)
114 : DeclWithIssue(declWithIssue),
115 BugType(StripTrailingDots(bugtype)),
116 VerboseDesc(StripTrailingDots(verboseDesc)),
117 ShortDesc(StripTrailingDots(shortDesc)),
118 Category(StripTrailingDots(category)),
119 UniqueingLoc(LocationToUnique),
120 UniqueingDecl(DeclToUnique),
121 path(pathImpl) {}
122
123 static PathDiagnosticCallPiece *
getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece * CP,const SourceManager & SMgr)124 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
125 const SourceManager &SMgr) {
126 SourceLocation CallLoc = CP->callEnter.asLocation();
127
128 // If the call is within a macro, don't do anything (for now).
129 if (CallLoc.isMacroID())
130 return 0;
131
132 assert(SMgr.isFromMainFile(CallLoc) &&
133 "The call piece should be in the main file.");
134
135 // Check if CP represents a path through a function outside of the main file.
136 if (!SMgr.isFromMainFile(CP->callEnterWithin.asLocation()))
137 return CP;
138
139 const PathPieces &Path = CP->path;
140 if (Path.empty())
141 return 0;
142
143 // Check if the last piece in the callee path is a call to a function outside
144 // of the main file.
145 if (PathDiagnosticCallPiece *CPInner =
146 dyn_cast<PathDiagnosticCallPiece>(Path.back())) {
147 return getFirstStackedCallToHeaderFile(CPInner, SMgr);
148 }
149
150 // Otherwise, the last piece is in the main file.
151 return 0;
152 }
153
resetDiagnosticLocationToMainFile()154 void PathDiagnostic::resetDiagnosticLocationToMainFile() {
155 if (path.empty())
156 return;
157
158 PathDiagnosticPiece *LastP = path.back().getPtr();
159 assert(LastP);
160 const SourceManager &SMgr = LastP->getLocation().getManager();
161
162 // We only need to check if the report ends inside headers, if the last piece
163 // is a call piece.
164 if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
165 CP = getFirstStackedCallToHeaderFile(CP, SMgr);
166 if (CP) {
167 // Mark the piece.
168 CP->setAsLastInMainSourceFile();
169
170 // Update the path diagnostic message.
171 const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee());
172 if (ND) {
173 SmallString<200> buf;
174 llvm::raw_svector_ostream os(buf);
175 os << " (within a call to '" << ND->getDeclName() << "')";
176 appendToDesc(os.str());
177 }
178
179 // Reset the report containing declaration and location.
180 DeclWithIssue = CP->getCaller();
181 Loc = CP->getLocation();
182
183 return;
184 }
185 }
186 }
187
anchor()188 void PathDiagnosticConsumer::anchor() { }
189
~PathDiagnosticConsumer()190 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
191 // Delete the contents of the FoldingSet if it isn't empty already.
192 for (llvm::FoldingSet<PathDiagnostic>::iterator it =
193 Diags.begin(), et = Diags.end() ; it != et ; ++it) {
194 delete &*it;
195 }
196 }
197
HandlePathDiagnostic(PathDiagnostic * D)198 void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
199 OwningPtr<PathDiagnostic> OwningD(D);
200
201 if (!D || D->path.empty())
202 return;
203
204 // We need to flatten the locations (convert Stmt* to locations) because
205 // the referenced statements may be freed by the time the diagnostics
206 // are emitted.
207 D->flattenLocations();
208
209 // If the PathDiagnosticConsumer does not support diagnostics that
210 // cross file boundaries, prune out such diagnostics now.
211 if (!supportsCrossFileDiagnostics()) {
212 // Verify that the entire path is from the same FileID.
213 FileID FID;
214 const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
215 SmallVector<const PathPieces *, 5> WorkList;
216 WorkList.push_back(&D->path);
217
218 while (!WorkList.empty()) {
219 const PathPieces &path = *WorkList.back();
220 WorkList.pop_back();
221
222 for (PathPieces::const_iterator I = path.begin(), E = path.end();
223 I != E; ++I) {
224 const PathDiagnosticPiece *piece = I->getPtr();
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 = 0;
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);
275 Diags.RemoveNode(orig);
276 delete orig;
277 }
278
279 Diags.InsertNode(OwningD.take());
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
419 namespace {
420 struct CompareDiagnostics {
421 // Compare if 'X' is "<" than 'Y'.
operator ()__anon9fd94c0d0111::CompareDiagnostics422 bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
423 if (X == Y)
424 return false;
425 return compare(*X, *Y);
426 }
427 };
428 }
429
FlushDiagnostics(PathDiagnosticConsumer::FilesMade * Files)430 void PathDiagnosticConsumer::FlushDiagnostics(
431 PathDiagnosticConsumer::FilesMade *Files) {
432 if (flushed)
433 return;
434
435 flushed = true;
436
437 std::vector<const PathDiagnostic *> BatchDiags;
438 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
439 et = Diags.end(); it != et; ++it) {
440 const PathDiagnostic *D = &*it;
441 BatchDiags.push_back(D);
442 }
443
444 // Sort the diagnostics so that they are always emitted in a deterministic
445 // order.
446 if (!BatchDiags.empty())
447 std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
448
449 FlushDiagnosticsImpl(BatchDiags, Files);
450
451 // Delete the flushed diagnostics.
452 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
453 et = BatchDiags.end(); it != et; ++it) {
454 const PathDiagnostic *D = *it;
455 delete D;
456 }
457
458 // Clear out the FoldingSet.
459 Diags.clear();
460 }
461
addDiagnostic(const PathDiagnostic & PD,StringRef ConsumerName,StringRef FileName)462 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
463 StringRef ConsumerName,
464 StringRef FileName) {
465 llvm::FoldingSetNodeID NodeID;
466 NodeID.Add(PD);
467 void *InsertPos;
468 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
469 if (!Entry) {
470 Entry = Alloc.Allocate<PDFileEntry>();
471 Entry = new (Entry) PDFileEntry(NodeID);
472 InsertNode(Entry, InsertPos);
473 }
474
475 // Allocate persistent storage for the file name.
476 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
477 memcpy(FileName_cstr, FileName.data(), FileName.size());
478
479 Entry->files.push_back(std::make_pair(ConsumerName,
480 StringRef(FileName_cstr,
481 FileName.size())));
482 }
483
484 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
getFiles(const PathDiagnostic & PD)485 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
486 llvm::FoldingSetNodeID NodeID;
487 NodeID.Add(PD);
488 void *InsertPos;
489 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
490 if (!Entry)
491 return 0;
492 return &Entry->files;
493 }
494
495 //===----------------------------------------------------------------------===//
496 // PathDiagnosticLocation methods.
497 //===----------------------------------------------------------------------===//
498
getValidSourceLocation(const Stmt * S,LocationOrAnalysisDeclContext LAC,bool UseEnd=false)499 static SourceLocation getValidSourceLocation(const Stmt* S,
500 LocationOrAnalysisDeclContext LAC,
501 bool UseEnd = false) {
502 SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
503 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
504 "be passed to PathDiagnosticLocation upon creation.");
505
506 // S might be a temporary statement that does not have a location in the
507 // source code, so find an enclosing statement and use its location.
508 if (!L.isValid()) {
509
510 AnalysisDeclContext *ADC;
511 if (LAC.is<const LocationContext*>())
512 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
513 else
514 ADC = LAC.get<AnalysisDeclContext*>();
515
516 ParentMap &PM = ADC->getParentMap();
517
518 const Stmt *Parent = S;
519 do {
520 Parent = PM.getParent(Parent);
521
522 // In rare cases, we have implicit top-level expressions,
523 // such as arguments for implicit member initializers.
524 // In this case, fall back to the start of the body (even if we were
525 // asked for the statement end location).
526 if (!Parent) {
527 const Stmt *Body = ADC->getBody();
528 if (Body)
529 L = Body->getLocStart();
530 else
531 L = ADC->getDecl()->getLocEnd();
532 break;
533 }
534
535 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
536 } while (!L.isValid());
537 }
538
539 return L;
540 }
541
542 static PathDiagnosticLocation
getLocationForCaller(const StackFrameContext * SFC,const LocationContext * CallerCtx,const SourceManager & SM)543 getLocationForCaller(const StackFrameContext *SFC,
544 const LocationContext *CallerCtx,
545 const SourceManager &SM) {
546 const CFGBlock &Block = *SFC->getCallSiteBlock();
547 CFGElement Source = Block[SFC->getIndex()];
548
549 switch (Source.getKind()) {
550 case CFGElement::Statement:
551 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
552 SM, CallerCtx);
553 case CFGElement::Initializer: {
554 const CFGInitializer &Init = Source.castAs<CFGInitializer>();
555 return PathDiagnosticLocation(Init.getInitializer()->getInit(),
556 SM, CallerCtx);
557 }
558 case CFGElement::AutomaticObjectDtor: {
559 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
560 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
561 SM, CallerCtx);
562 }
563 case CFGElement::BaseDtor:
564 case CFGElement::MemberDtor: {
565 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
566 if (const Stmt *CallerBody = CallerInfo->getBody())
567 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
568 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
569 }
570 case CFGElement::TemporaryDtor:
571 llvm_unreachable("not yet implemented!");
572 }
573
574 llvm_unreachable("Unknown CFGElement kind");
575 }
576
577
578 PathDiagnosticLocation
createBegin(const Decl * D,const SourceManager & SM)579 PathDiagnosticLocation::createBegin(const Decl *D,
580 const SourceManager &SM) {
581 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
582 }
583
584 PathDiagnosticLocation
createBegin(const Stmt * S,const SourceManager & SM,LocationOrAnalysisDeclContext LAC)585 PathDiagnosticLocation::createBegin(const Stmt *S,
586 const SourceManager &SM,
587 LocationOrAnalysisDeclContext LAC) {
588 return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
589 SM, SingleLocK);
590 }
591
592
593 PathDiagnosticLocation
createEnd(const Stmt * S,const SourceManager & SM,LocationOrAnalysisDeclContext LAC)594 PathDiagnosticLocation::createEnd(const Stmt *S,
595 const SourceManager &SM,
596 LocationOrAnalysisDeclContext LAC) {
597 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
598 return createEndBrace(CS, SM);
599 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
600 SM, SingleLocK);
601 }
602
603 PathDiagnosticLocation
createOperatorLoc(const BinaryOperator * BO,const SourceManager & SM)604 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
605 const SourceManager &SM) {
606 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
607 }
608
609 PathDiagnosticLocation
createMemberLoc(const MemberExpr * ME,const SourceManager & SM)610 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
611 const SourceManager &SM) {
612 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
613 }
614
615 PathDiagnosticLocation
createBeginBrace(const CompoundStmt * CS,const SourceManager & SM)616 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
617 const SourceManager &SM) {
618 SourceLocation L = CS->getLBracLoc();
619 return PathDiagnosticLocation(L, SM, SingleLocK);
620 }
621
622 PathDiagnosticLocation
createEndBrace(const CompoundStmt * CS,const SourceManager & SM)623 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
624 const SourceManager &SM) {
625 SourceLocation L = CS->getRBracLoc();
626 return PathDiagnosticLocation(L, SM, SingleLocK);
627 }
628
629 PathDiagnosticLocation
createDeclBegin(const LocationContext * LC,const SourceManager & SM)630 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
631 const SourceManager &SM) {
632 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
633 if (const CompoundStmt *CS =
634 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
635 if (!CS->body_empty()) {
636 SourceLocation Loc = (*CS->body_begin())->getLocStart();
637 return PathDiagnosticLocation(Loc, SM, SingleLocK);
638 }
639
640 return PathDiagnosticLocation();
641 }
642
643 PathDiagnosticLocation
createDeclEnd(const LocationContext * LC,const SourceManager & SM)644 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
645 const SourceManager &SM) {
646 SourceLocation L = LC->getDecl()->getBodyRBrace();
647 return PathDiagnosticLocation(L, SM, SingleLocK);
648 }
649
650 PathDiagnosticLocation
create(const ProgramPoint & P,const SourceManager & SMng)651 PathDiagnosticLocation::create(const ProgramPoint& P,
652 const SourceManager &SMng) {
653
654 const Stmt* S = 0;
655 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
656 const CFGBlock *BSrc = BE->getSrc();
657 S = BSrc->getTerminatorCondition();
658 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
659 S = SP->getStmt();
660 if (P.getAs<PostStmtPurgeDeadSymbols>())
661 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
662 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
663 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
664 SMng);
665 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
666 return PathDiagnosticLocation(PIE->getLocation(), SMng);
667 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
668 return getLocationForCaller(CE->getCalleeContext(),
669 CE->getLocationContext(),
670 SMng);
671 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
672 return getLocationForCaller(CEE->getCalleeContext(),
673 CEE->getLocationContext(),
674 SMng);
675 } else {
676 llvm_unreachable("Unexpected ProgramPoint");
677 }
678
679 return PathDiagnosticLocation(S, SMng, P.getLocationContext());
680 }
681
getStmt(const ExplodedNode * N)682 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
683 ProgramPoint P = N->getLocation();
684 if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
685 return SP->getStmt();
686 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
687 return BE->getSrc()->getTerminator();
688 if (Optional<CallEnter> CE = P.getAs<CallEnter>())
689 return CE->getCallExpr();
690 if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
691 return CEE->getCalleeContext()->getCallSite();
692 if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>())
693 return PIPP->getInitializer()->getInit();
694
695 return 0;
696 }
697
getNextStmt(const ExplodedNode * N)698 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
699 for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
700 if (const Stmt *S = getStmt(N)) {
701 // Check if the statement is '?' or '&&'/'||'. These are "merges",
702 // not actual statement points.
703 switch (S->getStmtClass()) {
704 case Stmt::ChooseExprClass:
705 case Stmt::BinaryConditionalOperatorClass:
706 case Stmt::ConditionalOperatorClass:
707 continue;
708 case Stmt::BinaryOperatorClass: {
709 BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
710 if (Op == BO_LAnd || Op == BO_LOr)
711 continue;
712 break;
713 }
714 default:
715 break;
716 }
717 // We found the statement, so return it.
718 return S;
719 }
720 }
721
722 return 0;
723 }
724
725 PathDiagnosticLocation
createEndOfPath(const ExplodedNode * N,const SourceManager & SM)726 PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
727 const SourceManager &SM) {
728 assert(N && "Cannot create a location with a null node.");
729 const Stmt *S = getStmt(N);
730
731 if (!S)
732 S = getNextStmt(N);
733
734 if (S) {
735 ProgramPoint P = N->getLocation();
736 const LocationContext *LC = N->getLocationContext();
737
738 // For member expressions, return the location of the '.' or '->'.
739 if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
740 return PathDiagnosticLocation::createMemberLoc(ME, SM);
741
742 // For binary operators, return the location of the operator.
743 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
744 return PathDiagnosticLocation::createOperatorLoc(B, SM);
745
746 if (P.getAs<PostStmtPurgeDeadSymbols>())
747 return PathDiagnosticLocation::createEnd(S, SM, LC);
748
749 if (S->getLocStart().isValid())
750 return PathDiagnosticLocation(S, SM, LC);
751 return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
752 }
753
754 return createDeclEnd(N->getLocationContext(), SM);
755 }
756
createSingleLocation(const PathDiagnosticLocation & PDL)757 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
758 const PathDiagnosticLocation &PDL) {
759 FullSourceLoc L = PDL.asLocation();
760 return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
761 }
762
763 FullSourceLoc
genLocation(SourceLocation L,LocationOrAnalysisDeclContext LAC) const764 PathDiagnosticLocation::genLocation(SourceLocation L,
765 LocationOrAnalysisDeclContext LAC) const {
766 assert(isValid());
767 // Note that we want a 'switch' here so that the compiler can warn us in
768 // case we add more cases.
769 switch (K) {
770 case SingleLocK:
771 case RangeK:
772 break;
773 case StmtK:
774 // Defensive checking.
775 if (!S)
776 break;
777 return FullSourceLoc(getValidSourceLocation(S, LAC),
778 const_cast<SourceManager&>(*SM));
779 case DeclK:
780 // Defensive checking.
781 if (!D)
782 break;
783 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
784 }
785
786 return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
787 }
788
789 PathDiagnosticRange
genRange(LocationOrAnalysisDeclContext LAC) const790 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
791 assert(isValid());
792 // Note that we want a 'switch' here so that the compiler can warn us in
793 // case we add more cases.
794 switch (K) {
795 case SingleLocK:
796 return PathDiagnosticRange(SourceRange(Loc,Loc), true);
797 case RangeK:
798 break;
799 case StmtK: {
800 const Stmt *S = asStmt();
801 switch (S->getStmtClass()) {
802 default:
803 break;
804 case Stmt::DeclStmtClass: {
805 const DeclStmt *DS = cast<DeclStmt>(S);
806 if (DS->isSingleDecl()) {
807 // Should always be the case, but we'll be defensive.
808 return SourceRange(DS->getLocStart(),
809 DS->getSingleDecl()->getLocation());
810 }
811 break;
812 }
813 // FIXME: Provide better range information for different
814 // terminators.
815 case Stmt::IfStmtClass:
816 case Stmt::WhileStmtClass:
817 case Stmt::DoStmtClass:
818 case Stmt::ForStmtClass:
819 case Stmt::ChooseExprClass:
820 case Stmt::IndirectGotoStmtClass:
821 case Stmt::SwitchStmtClass:
822 case Stmt::BinaryConditionalOperatorClass:
823 case Stmt::ConditionalOperatorClass:
824 case Stmt::ObjCForCollectionStmtClass: {
825 SourceLocation L = getValidSourceLocation(S, LAC);
826 return SourceRange(L, L);
827 }
828 }
829 SourceRange R = S->getSourceRange();
830 if (R.isValid())
831 return R;
832 break;
833 }
834 case DeclK:
835 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
836 return MD->getSourceRange();
837 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
838 if (Stmt *Body = FD->getBody())
839 return Body->getSourceRange();
840 }
841 else {
842 SourceLocation L = D->getLocation();
843 return PathDiagnosticRange(SourceRange(L, L), true);
844 }
845 }
846
847 return SourceRange(Loc,Loc);
848 }
849
flatten()850 void PathDiagnosticLocation::flatten() {
851 if (K == StmtK) {
852 K = RangeK;
853 S = 0;
854 D = 0;
855 }
856 else if (K == DeclK) {
857 K = SingleLocK;
858 S = 0;
859 D = 0;
860 }
861 }
862
863 //===----------------------------------------------------------------------===//
864 // Manipulation of PathDiagnosticCallPieces.
865 //===----------------------------------------------------------------------===//
866
867 PathDiagnosticCallPiece *
construct(const ExplodedNode * N,const CallExitEnd & CE,const SourceManager & SM)868 PathDiagnosticCallPiece::construct(const ExplodedNode *N,
869 const CallExitEnd &CE,
870 const SourceManager &SM) {
871 const Decl *caller = CE.getLocationContext()->getDecl();
872 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
873 CE.getLocationContext(),
874 SM);
875 return new PathDiagnosticCallPiece(caller, pos);
876 }
877
878 PathDiagnosticCallPiece *
construct(PathPieces & path,const Decl * caller)879 PathDiagnosticCallPiece::construct(PathPieces &path,
880 const Decl *caller) {
881 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
882 path.clear();
883 path.push_front(C);
884 return C;
885 }
886
setCallee(const CallEnter & CE,const SourceManager & SM)887 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
888 const SourceManager &SM) {
889 const StackFrameContext *CalleeCtx = CE.getCalleeContext();
890 Callee = CalleeCtx->getDecl();
891
892 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
893 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
894 }
895
describeClass(raw_ostream & Out,const CXXRecordDecl * D,StringRef Prefix=StringRef ())896 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
897 StringRef Prefix = StringRef()) {
898 if (!D->getIdentifier())
899 return;
900 Out << Prefix << '\'' << *D << '\'';
901 }
902
describeCodeDecl(raw_ostream & Out,const Decl * D,bool ExtendedDescription,StringRef Prefix=StringRef ())903 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
904 bool ExtendedDescription,
905 StringRef Prefix = StringRef()) {
906 if (!D)
907 return false;
908
909 if (isa<BlockDecl>(D)) {
910 if (ExtendedDescription)
911 Out << Prefix << "anonymous block";
912 return ExtendedDescription;
913 }
914
915 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
916 Out << Prefix;
917 if (ExtendedDescription && !MD->isUserProvided()) {
918 if (MD->isExplicitlyDefaulted())
919 Out << "defaulted ";
920 else
921 Out << "implicit ";
922 }
923
924 if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
925 if (CD->isDefaultConstructor())
926 Out << "default ";
927 else if (CD->isCopyConstructor())
928 Out << "copy ";
929 else if (CD->isMoveConstructor())
930 Out << "move ";
931
932 Out << "constructor";
933 describeClass(Out, MD->getParent(), " for ");
934
935 } else if (isa<CXXDestructorDecl>(MD)) {
936 if (!MD->isUserProvided()) {
937 Out << "destructor";
938 describeClass(Out, MD->getParent(), " for ");
939 } else {
940 // Use ~Foo for explicitly-written destructors.
941 Out << "'" << *MD << "'";
942 }
943
944 } else if (MD->isCopyAssignmentOperator()) {
945 Out << "copy assignment operator";
946 describeClass(Out, MD->getParent(), " for ");
947
948 } else if (MD->isMoveAssignmentOperator()) {
949 Out << "move assignment operator";
950 describeClass(Out, MD->getParent(), " for ");
951
952 } else {
953 if (MD->getParent()->getIdentifier())
954 Out << "'" << *MD->getParent() << "::" << *MD << "'";
955 else
956 Out << "'" << *MD << "'";
957 }
958
959 return true;
960 }
961
962 Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
963 return true;
964 }
965
966 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallEnterEvent() const967 PathDiagnosticCallPiece::getCallEnterEvent() const {
968 if (!Callee)
969 return 0;
970
971 SmallString<256> buf;
972 llvm::raw_svector_ostream Out(buf);
973
974 Out << "Calling ";
975 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
976
977 assert(callEnter.asLocation().isValid());
978 return new PathDiagnosticEventPiece(callEnter, Out.str());
979 }
980
981 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallEnterWithinCallerEvent() const982 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
983 if (!callEnterWithin.asLocation().isValid())
984 return 0;
985 if (Callee->isImplicit() || !Callee->hasBody())
986 return 0;
987 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
988 if (MD->isDefaulted())
989 return 0;
990
991 SmallString<256> buf;
992 llvm::raw_svector_ostream Out(buf);
993
994 Out << "Entered call";
995 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
996
997 return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
998 }
999
1000 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallExitEvent() const1001 PathDiagnosticCallPiece::getCallExitEvent() const {
1002 if (NoExit)
1003 return 0;
1004
1005 SmallString<256> buf;
1006 llvm::raw_svector_ostream Out(buf);
1007
1008 if (!CallStackMessage.empty()) {
1009 Out << CallStackMessage;
1010 } else {
1011 bool DidDescribe = describeCodeDecl(Out, Callee,
1012 /*ExtendedDescription=*/false,
1013 "Returning from ");
1014 if (!DidDescribe)
1015 Out << "Returning to caller";
1016 }
1017
1018 assert(callReturn.asLocation().isValid());
1019 return new PathDiagnosticEventPiece(callReturn, Out.str());
1020 }
1021
compute_path_size(const PathPieces & pieces,unsigned & size)1022 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
1023 for (PathPieces::const_iterator it = pieces.begin(),
1024 et = pieces.end(); it != et; ++it) {
1025 const PathDiagnosticPiece *piece = it->getPtr();
1026 if (const PathDiagnosticCallPiece *cp =
1027 dyn_cast<PathDiagnosticCallPiece>(piece)) {
1028 compute_path_size(cp->path, size);
1029 }
1030 else
1031 ++size;
1032 }
1033 }
1034
full_size()1035 unsigned PathDiagnostic::full_size() {
1036 unsigned size = 0;
1037 compute_path_size(path, size);
1038 return size;
1039 }
1040
1041 //===----------------------------------------------------------------------===//
1042 // FoldingSet profiling methods.
1043 //===----------------------------------------------------------------------===//
1044
Profile(llvm::FoldingSetNodeID & ID) const1045 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
1046 ID.AddInteger(Range.getBegin().getRawEncoding());
1047 ID.AddInteger(Range.getEnd().getRawEncoding());
1048 ID.AddInteger(Loc.getRawEncoding());
1049 return;
1050 }
1051
Profile(llvm::FoldingSetNodeID & ID) const1052 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1053 ID.AddInteger((unsigned) getKind());
1054 ID.AddString(str);
1055 // FIXME: Add profiling support for code hints.
1056 ID.AddInteger((unsigned) getDisplayHint());
1057 ArrayRef<SourceRange> Ranges = getRanges();
1058 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
1059 I != E; ++I) {
1060 ID.AddInteger(I->getBegin().getRawEncoding());
1061 ID.AddInteger(I->getEnd().getRawEncoding());
1062 }
1063 }
1064
Profile(llvm::FoldingSetNodeID & ID) const1065 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1066 PathDiagnosticPiece::Profile(ID);
1067 for (PathPieces::const_iterator it = path.begin(),
1068 et = path.end(); it != et; ++it) {
1069 ID.Add(**it);
1070 }
1071 }
1072
Profile(llvm::FoldingSetNodeID & ID) const1073 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1074 PathDiagnosticPiece::Profile(ID);
1075 ID.Add(Pos);
1076 }
1077
Profile(llvm::FoldingSetNodeID & ID) const1078 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1079 PathDiagnosticPiece::Profile(ID);
1080 for (const_iterator I = begin(), E = end(); I != E; ++I)
1081 ID.Add(*I);
1082 }
1083
Profile(llvm::FoldingSetNodeID & ID) const1084 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1085 PathDiagnosticSpotPiece::Profile(ID);
1086 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
1087 I != E; ++I)
1088 ID.Add(**I);
1089 }
1090
Profile(llvm::FoldingSetNodeID & ID) const1091 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
1092 ID.Add(getLocation());
1093 ID.AddString(BugType);
1094 ID.AddString(VerboseDesc);
1095 ID.AddString(Category);
1096 }
1097
FullProfile(llvm::FoldingSetNodeID & ID) const1098 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
1099 Profile(ID);
1100 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
1101 ID.Add(**I);
1102 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1103 ID.AddString(*I);
1104 }
1105
~StackHintGenerator()1106 StackHintGenerator::~StackHintGenerator() {}
1107
getMessage(const ExplodedNode * N)1108 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
1109 ProgramPoint P = N->getLocation();
1110 CallExitEnd CExit = P.castAs<CallExitEnd>();
1111
1112 // FIXME: Use CallEvent to abstract this over all calls.
1113 const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
1114 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
1115 if (!CE)
1116 return "";
1117
1118 if (!N)
1119 return getMessageForSymbolNotFound();
1120
1121 // Check if one of the parameters are set to the interesting symbol.
1122 ProgramStateRef State = N->getState();
1123 const LocationContext *LCtx = N->getLocationContext();
1124 unsigned ArgIndex = 0;
1125 for (CallExpr::const_arg_iterator I = CE->arg_begin(),
1126 E = CE->arg_end(); I != E; ++I, ++ArgIndex){
1127 SVal SV = State->getSVal(*I, LCtx);
1128
1129 // Check if the variable corresponding to the symbol is passed by value.
1130 SymbolRef AS = SV.getAsLocSymbol();
1131 if (AS == Sym) {
1132 return getMessageForArg(*I, ArgIndex);
1133 }
1134
1135 // Check if the parameter is a pointer to the symbol.
1136 if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
1137 SVal PSV = State->getSVal(Reg->getRegion());
1138 SymbolRef AS = PSV.getAsLocSymbol();
1139 if (AS == Sym) {
1140 return getMessageForArg(*I, ArgIndex);
1141 }
1142 }
1143 }
1144
1145 // Check if we are returning the interesting symbol.
1146 SVal SV = State->getSVal(CE, LCtx);
1147 SymbolRef RetSym = SV.getAsLocSymbol();
1148 if (RetSym == Sym) {
1149 return getMessageForReturn(CE);
1150 }
1151
1152 return getMessageForSymbolNotFound();
1153 }
1154
getMessageForArg(const Expr * ArgE,unsigned ArgIndex)1155 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
1156 unsigned ArgIndex) {
1157 // Printed parameters start at 1, not 0.
1158 ++ArgIndex;
1159
1160 SmallString<200> buf;
1161 llvm::raw_svector_ostream os(buf);
1162
1163 os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1164 << " parameter";
1165
1166 return os.str();
1167 }
1168