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