• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PathDiagnosticPiece(Kind k,DisplayHint hint)53 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
54   : kind(k), Hint(hint) {}
55 
~PathDiagnosticPiece()56 PathDiagnosticPiece::~PathDiagnosticPiece() {}
~PathDiagnosticEventPiece()57 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
~PathDiagnosticCallPiece()58 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
~PathDiagnosticControlFlowPiece()59 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
~PathDiagnosticMacroPiece()60 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
61 
62 
~PathPieces()63 PathPieces::~PathPieces() {}
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->getPtr();
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(const Decl * declWithIssue,StringRef bugtype,StringRef verboseDesc,StringRef shortDesc,StringRef category,PathDiagnosticLocation LocationToUnique,const Decl * DeclToUnique)108 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
109                                StringRef bugtype, StringRef verboseDesc,
110                                StringRef shortDesc, StringRef category,
111                                PathDiagnosticLocation LocationToUnique,
112                                const Decl *DeclToUnique)
113   : DeclWithIssue(declWithIssue),
114     BugType(StripTrailingDots(bugtype)),
115     VerboseDesc(StripTrailingDots(verboseDesc)),
116     ShortDesc(StripTrailingDots(shortDesc)),
117     Category(StripTrailingDots(category)),
118     UniqueingLoc(LocationToUnique),
119     UniqueingDecl(DeclToUnique),
120     path(pathImpl) {}
121 
anchor()122 void PathDiagnosticConsumer::anchor() { }
123 
~PathDiagnosticConsumer()124 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
125   // Delete the contents of the FoldingSet if it isn't empty already.
126   for (llvm::FoldingSet<PathDiagnostic>::iterator it =
127        Diags.begin(), et = Diags.end() ; it != et ; ++it) {
128     delete &*it;
129   }
130 }
131 
HandlePathDiagnostic(PathDiagnostic * D)132 void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
133   OwningPtr<PathDiagnostic> OwningD(D);
134 
135   if (!D || D->path.empty())
136     return;
137 
138   // We need to flatten the locations (convert Stmt* to locations) because
139   // the referenced statements may be freed by the time the diagnostics
140   // are emitted.
141   D->flattenLocations();
142 
143   // If the PathDiagnosticConsumer does not support diagnostics that
144   // cross file boundaries, prune out such diagnostics now.
145   if (!supportsCrossFileDiagnostics()) {
146     // Verify that the entire path is from the same FileID.
147     FileID FID;
148     const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
149     SmallVector<const PathPieces *, 5> WorkList;
150     WorkList.push_back(&D->path);
151 
152     while (!WorkList.empty()) {
153       const PathPieces &path = *WorkList.back();
154       WorkList.pop_back();
155 
156       for (PathPieces::const_iterator I = path.begin(), E = path.end();
157            I != E; ++I) {
158         const PathDiagnosticPiece *piece = I->getPtr();
159         FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
160 
161         if (FID.isInvalid()) {
162           FID = SMgr.getFileID(L);
163         } else if (SMgr.getFileID(L) != FID)
164           return; // FIXME: Emit a warning?
165 
166         // Check the source ranges.
167         ArrayRef<SourceRange> Ranges = piece->getRanges();
168         for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
169                                              E = Ranges.end(); I != E; ++I) {
170           SourceLocation L = SMgr.getExpansionLoc(I->getBegin());
171           if (!L.isFileID() || SMgr.getFileID(L) != FID)
172             return; // FIXME: Emit a warning?
173           L = SMgr.getExpansionLoc(I->getEnd());
174           if (!L.isFileID() || SMgr.getFileID(L) != FID)
175             return; // FIXME: Emit a warning?
176         }
177 
178         if (const PathDiagnosticCallPiece *call =
179             dyn_cast<PathDiagnosticCallPiece>(piece)) {
180           WorkList.push_back(&call->path);
181         }
182         else if (const PathDiagnosticMacroPiece *macro =
183                  dyn_cast<PathDiagnosticMacroPiece>(piece)) {
184           WorkList.push_back(&macro->subPieces);
185         }
186       }
187     }
188 
189     if (FID.isInvalid())
190       return; // FIXME: Emit a warning?
191   }
192 
193   // Profile the node to see if we already have something matching it
194   llvm::FoldingSetNodeID profile;
195   D->Profile(profile);
196   void *InsertPos = 0;
197 
198   if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
199     // Keep the PathDiagnostic with the shorter path.
200     // Note, the enclosing routine is called in deterministic order, so the
201     // results will be consistent between runs (no reason to break ties if the
202     // size is the same).
203     const unsigned orig_size = orig->full_size();
204     const unsigned new_size = D->full_size();
205     if (orig_size <= new_size)
206       return;
207 
208     assert(orig != D);
209     Diags.RemoveNode(orig);
210     delete orig;
211   }
212 
213   Diags.InsertNode(OwningD.take());
214 }
215 
216 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
217 static Optional<bool>
compareControlFlow(const PathDiagnosticControlFlowPiece & X,const PathDiagnosticControlFlowPiece & Y)218 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
219                    const PathDiagnosticControlFlowPiece &Y) {
220   FullSourceLoc XSL = X.getStartLocation().asLocation();
221   FullSourceLoc YSL = Y.getStartLocation().asLocation();
222   if (XSL != YSL)
223     return XSL.isBeforeInTranslationUnitThan(YSL);
224   FullSourceLoc XEL = X.getEndLocation().asLocation();
225   FullSourceLoc YEL = Y.getEndLocation().asLocation();
226   if (XEL != YEL)
227     return XEL.isBeforeInTranslationUnitThan(YEL);
228   return None;
229 }
230 
compareMacro(const PathDiagnosticMacroPiece & X,const PathDiagnosticMacroPiece & Y)231 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
232                                    const PathDiagnosticMacroPiece &Y) {
233   return comparePath(X.subPieces, Y.subPieces);
234 }
235 
compareCall(const PathDiagnosticCallPiece & X,const PathDiagnosticCallPiece & Y)236 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
237                                   const PathDiagnosticCallPiece &Y) {
238   FullSourceLoc X_CEL = X.callEnter.asLocation();
239   FullSourceLoc Y_CEL = Y.callEnter.asLocation();
240   if (X_CEL != Y_CEL)
241     return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
242   FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
243   FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
244   if (X_CEWL != Y_CEWL)
245     return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
246   FullSourceLoc X_CRL = X.callReturn.asLocation();
247   FullSourceLoc Y_CRL = Y.callReturn.asLocation();
248   if (X_CRL != Y_CRL)
249     return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
250   return comparePath(X.path, Y.path);
251 }
252 
comparePiece(const PathDiagnosticPiece & X,const PathDiagnosticPiece & Y)253 static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
254                                    const PathDiagnosticPiece &Y) {
255   if (X.getKind() != Y.getKind())
256     return X.getKind() < Y.getKind();
257 
258   FullSourceLoc XL = X.getLocation().asLocation();
259   FullSourceLoc YL = Y.getLocation().asLocation();
260   if (XL != YL)
261     return XL.isBeforeInTranslationUnitThan(YL);
262 
263   if (X.getString() != Y.getString())
264     return X.getString() < Y.getString();
265 
266   if (X.getRanges().size() != Y.getRanges().size())
267     return X.getRanges().size() < Y.getRanges().size();
268 
269   const SourceManager &SM = XL.getManager();
270 
271   for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
272     SourceRange XR = X.getRanges()[i];
273     SourceRange YR = Y.getRanges()[i];
274     if (XR != YR) {
275       if (XR.getBegin() != YR.getBegin())
276         return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
277       return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
278     }
279   }
280 
281   switch (X.getKind()) {
282     case clang::ento::PathDiagnosticPiece::ControlFlow:
283       return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
284                                 cast<PathDiagnosticControlFlowPiece>(Y));
285     case clang::ento::PathDiagnosticPiece::Event:
286       return None;
287     case clang::ento::PathDiagnosticPiece::Macro:
288       return compareMacro(cast<PathDiagnosticMacroPiece>(X),
289                           cast<PathDiagnosticMacroPiece>(Y));
290     case clang::ento::PathDiagnosticPiece::Call:
291       return compareCall(cast<PathDiagnosticCallPiece>(X),
292                          cast<PathDiagnosticCallPiece>(Y));
293   }
294   llvm_unreachable("all cases handled");
295 }
296 
comparePath(const PathPieces & X,const PathPieces & Y)297 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
298   if (X.size() != Y.size())
299     return X.size() < Y.size();
300   for (unsigned i = 0, n = X.size(); i != n; ++i) {
301     Optional<bool> b = comparePiece(*X[i], *Y[i]);
302     if (b.hasValue())
303       return b.getValue();
304   }
305   return None;
306 }
307 
compare(const PathDiagnostic & X,const PathDiagnostic & Y)308 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
309   FullSourceLoc XL = X.getLocation().asLocation();
310   FullSourceLoc YL = Y.getLocation().asLocation();
311   if (XL != YL)
312     return XL.isBeforeInTranslationUnitThan(YL);
313   if (X.getBugType() != Y.getBugType())
314     return X.getBugType() < Y.getBugType();
315   if (X.getCategory() != Y.getCategory())
316     return X.getCategory() < Y.getCategory();
317   if (X.getVerboseDescription() != Y.getVerboseDescription())
318     return X.getVerboseDescription() < Y.getVerboseDescription();
319   if (X.getShortDescription() != Y.getShortDescription())
320     return X.getShortDescription() < Y.getShortDescription();
321   if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
322     const Decl *XD = X.getDeclWithIssue();
323     if (!XD)
324       return true;
325     const Decl *YD = Y.getDeclWithIssue();
326     if (!YD)
327       return false;
328     SourceLocation XDL = XD->getLocation();
329     SourceLocation YDL = YD->getLocation();
330     if (XDL != YDL) {
331       const SourceManager &SM = XL.getManager();
332       return SM.isBeforeInTranslationUnit(XDL, YDL);
333     }
334   }
335   PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
336   PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
337   if (XE - XI != YE - YI)
338     return (XE - XI) < (YE - YI);
339   for ( ; XI != XE ; ++XI, ++YI) {
340     if (*XI != *YI)
341       return (*XI) < (*YI);
342   }
343   Optional<bool> b = comparePath(X.path, Y.path);
344   assert(b.hasValue());
345   return b.getValue();
346 }
347 
348 namespace {
349 struct CompareDiagnostics {
350   // Compare if 'X' is "<" than 'Y'.
operator ()__anon5987c2290111::CompareDiagnostics351   bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
352     if (X == Y)
353       return false;
354     return compare(*X, *Y);
355   }
356 };
357 }
358 
FlushDiagnostics(PathDiagnosticConsumer::FilesMade * Files)359 void PathDiagnosticConsumer::FlushDiagnostics(
360                                      PathDiagnosticConsumer::FilesMade *Files) {
361   if (flushed)
362     return;
363 
364   flushed = true;
365 
366   std::vector<const PathDiagnostic *> BatchDiags;
367   for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
368        et = Diags.end(); it != et; ++it) {
369     const PathDiagnostic *D = &*it;
370     BatchDiags.push_back(D);
371   }
372 
373   // Sort the diagnostics so that they are always emitted in a deterministic
374   // order.
375   if (!BatchDiags.empty())
376     std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
377 
378   FlushDiagnosticsImpl(BatchDiags, Files);
379 
380   // Delete the flushed diagnostics.
381   for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
382        et = BatchDiags.end(); it != et; ++it) {
383     const PathDiagnostic *D = *it;
384     delete D;
385   }
386 
387   // Clear out the FoldingSet.
388   Diags.clear();
389 }
390 
addDiagnostic(const PathDiagnostic & PD,StringRef ConsumerName,StringRef FileName)391 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
392                                                       StringRef ConsumerName,
393                                                       StringRef FileName) {
394   llvm::FoldingSetNodeID NodeID;
395   NodeID.Add(PD);
396   void *InsertPos;
397   PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
398   if (!Entry) {
399     Entry = Alloc.Allocate<PDFileEntry>();
400     Entry = new (Entry) PDFileEntry(NodeID);
401     InsertNode(Entry, InsertPos);
402   }
403 
404   // Allocate persistent storage for the file name.
405   char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
406   memcpy(FileName_cstr, FileName.data(), FileName.size());
407 
408   Entry->files.push_back(std::make_pair(ConsumerName,
409                                         StringRef(FileName_cstr,
410                                                   FileName.size())));
411 }
412 
413 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
getFiles(const PathDiagnostic & PD)414 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
415   llvm::FoldingSetNodeID NodeID;
416   NodeID.Add(PD);
417   void *InsertPos;
418   PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
419   if (!Entry)
420     return 0;
421   return &Entry->files;
422 }
423 
424 //===----------------------------------------------------------------------===//
425 // PathDiagnosticLocation methods.
426 //===----------------------------------------------------------------------===//
427 
getValidSourceLocation(const Stmt * S,LocationOrAnalysisDeclContext LAC,bool UseEnd=false)428 static SourceLocation getValidSourceLocation(const Stmt* S,
429                                              LocationOrAnalysisDeclContext LAC,
430                                              bool UseEnd = false) {
431   SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
432   assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
433                           "be passed to PathDiagnosticLocation upon creation.");
434 
435   // S might be a temporary statement that does not have a location in the
436   // source code, so find an enclosing statement and use its location.
437   if (!L.isValid()) {
438 
439     AnalysisDeclContext *ADC;
440     if (LAC.is<const LocationContext*>())
441       ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
442     else
443       ADC = LAC.get<AnalysisDeclContext*>();
444 
445     ParentMap &PM = ADC->getParentMap();
446 
447     const Stmt *Parent = S;
448     do {
449       Parent = PM.getParent(Parent);
450 
451       // In rare cases, we have implicit top-level expressions,
452       // such as arguments for implicit member initializers.
453       // In this case, fall back to the start of the body (even if we were
454       // asked for the statement end location).
455       if (!Parent) {
456         const Stmt *Body = ADC->getBody();
457         if (Body)
458           L = Body->getLocStart();
459         else
460           L = ADC->getDecl()->getLocEnd();
461         break;
462       }
463 
464       L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
465     } while (!L.isValid());
466   }
467 
468   return L;
469 }
470 
471 static PathDiagnosticLocation
getLocationForCaller(const StackFrameContext * SFC,const LocationContext * CallerCtx,const SourceManager & SM)472 getLocationForCaller(const StackFrameContext *SFC,
473                      const LocationContext *CallerCtx,
474                      const SourceManager &SM) {
475   const CFGBlock &Block = *SFC->getCallSiteBlock();
476   CFGElement Source = Block[SFC->getIndex()];
477 
478   switch (Source.getKind()) {
479   case CFGElement::Statement:
480     return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
481                                   SM, CallerCtx);
482   case CFGElement::Initializer: {
483     const CFGInitializer &Init = Source.castAs<CFGInitializer>();
484     return PathDiagnosticLocation(Init.getInitializer()->getInit(),
485                                   SM, CallerCtx);
486   }
487   case CFGElement::AutomaticObjectDtor: {
488     const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
489     return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
490                                              SM, CallerCtx);
491   }
492   case CFGElement::BaseDtor:
493   case CFGElement::MemberDtor: {
494     const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
495     if (const Stmt *CallerBody = CallerInfo->getBody())
496       return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
497     return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
498   }
499   case CFGElement::TemporaryDtor:
500     llvm_unreachable("not yet implemented!");
501   }
502 
503   llvm_unreachable("Unknown CFGElement kind");
504 }
505 
506 
507 PathDiagnosticLocation
createBegin(const Decl * D,const SourceManager & SM)508   PathDiagnosticLocation::createBegin(const Decl *D,
509                                       const SourceManager &SM) {
510   return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
511 }
512 
513 PathDiagnosticLocation
createBegin(const Stmt * S,const SourceManager & SM,LocationOrAnalysisDeclContext LAC)514   PathDiagnosticLocation::createBegin(const Stmt *S,
515                                       const SourceManager &SM,
516                                       LocationOrAnalysisDeclContext LAC) {
517   return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
518                                 SM, SingleLocK);
519 }
520 
521 
522 PathDiagnosticLocation
createEnd(const Stmt * S,const SourceManager & SM,LocationOrAnalysisDeclContext LAC)523 PathDiagnosticLocation::createEnd(const Stmt *S,
524                                   const SourceManager &SM,
525                                   LocationOrAnalysisDeclContext LAC) {
526   if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
527     return createEndBrace(CS, SM);
528   return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
529                                 SM, SingleLocK);
530 }
531 
532 PathDiagnosticLocation
createOperatorLoc(const BinaryOperator * BO,const SourceManager & SM)533   PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
534                                             const SourceManager &SM) {
535   return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
536 }
537 
538 PathDiagnosticLocation
createMemberLoc(const MemberExpr * ME,const SourceManager & SM)539   PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
540                                           const SourceManager &SM) {
541   return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
542 }
543 
544 PathDiagnosticLocation
createBeginBrace(const CompoundStmt * CS,const SourceManager & SM)545   PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
546                                            const SourceManager &SM) {
547   SourceLocation L = CS->getLBracLoc();
548   return PathDiagnosticLocation(L, SM, SingleLocK);
549 }
550 
551 PathDiagnosticLocation
createEndBrace(const CompoundStmt * CS,const SourceManager & SM)552   PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
553                                          const SourceManager &SM) {
554   SourceLocation L = CS->getRBracLoc();
555   return PathDiagnosticLocation(L, SM, SingleLocK);
556 }
557 
558 PathDiagnosticLocation
createDeclBegin(const LocationContext * LC,const SourceManager & SM)559   PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
560                                           const SourceManager &SM) {
561   // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
562   if (const CompoundStmt *CS =
563         dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
564     if (!CS->body_empty()) {
565       SourceLocation Loc = (*CS->body_begin())->getLocStart();
566       return PathDiagnosticLocation(Loc, SM, SingleLocK);
567     }
568 
569   return PathDiagnosticLocation();
570 }
571 
572 PathDiagnosticLocation
createDeclEnd(const LocationContext * LC,const SourceManager & SM)573   PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
574                                         const SourceManager &SM) {
575   SourceLocation L = LC->getDecl()->getBodyRBrace();
576   return PathDiagnosticLocation(L, SM, SingleLocK);
577 }
578 
579 PathDiagnosticLocation
create(const ProgramPoint & P,const SourceManager & SMng)580   PathDiagnosticLocation::create(const ProgramPoint& P,
581                                  const SourceManager &SMng) {
582 
583   const Stmt* S = 0;
584   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
585     const CFGBlock *BSrc = BE->getSrc();
586     S = BSrc->getTerminatorCondition();
587   } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
588     S = SP->getStmt();
589     if (P.getAs<PostStmtPurgeDeadSymbols>())
590       return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
591   } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
592     return PathDiagnosticLocation(PIE->getLocation(), SMng);
593   } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
594     return getLocationForCaller(CE->getCalleeContext(),
595                                 CE->getLocationContext(),
596                                 SMng);
597   } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
598     return getLocationForCaller(CEE->getCalleeContext(),
599                                 CEE->getLocationContext(),
600                                 SMng);
601   } else {
602     llvm_unreachable("Unexpected ProgramPoint");
603   }
604 
605   return PathDiagnosticLocation(S, SMng, P.getLocationContext());
606 }
607 
608 PathDiagnosticLocation
createEndOfPath(const ExplodedNode * N,const SourceManager & SM)609   PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
610                                           const SourceManager &SM) {
611   assert(N && "Cannot create a location with a null node.");
612 
613   const ExplodedNode *NI = N;
614   const Stmt *S = 0;
615 
616   while (NI) {
617     ProgramPoint P = NI->getLocation();
618     if (Optional<StmtPoint> PS = P.getAs<StmtPoint>()) {
619       S = PS->getStmt();
620       if (P.getAs<PostStmtPurgeDeadSymbols>())
621         return PathDiagnosticLocation::createEnd(S, SM,
622                                                  NI->getLocationContext());
623       break;
624     } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
625       S = BE->getSrc()->getTerminator();
626       break;
627     }
628     NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
629   }
630 
631   if (S) {
632     const LocationContext *LC = NI->getLocationContext();
633     if (S->getLocStart().isValid())
634       return PathDiagnosticLocation(S, SM, LC);
635     return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
636   }
637 
638   return createDeclEnd(N->getLocationContext(), SM);
639 }
640 
createSingleLocation(const PathDiagnosticLocation & PDL)641 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
642                                            const PathDiagnosticLocation &PDL) {
643   FullSourceLoc L = PDL.asLocation();
644   return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
645 }
646 
647 FullSourceLoc
genLocation(SourceLocation L,LocationOrAnalysisDeclContext LAC) const648   PathDiagnosticLocation::genLocation(SourceLocation L,
649                                       LocationOrAnalysisDeclContext LAC) const {
650   assert(isValid());
651   // Note that we want a 'switch' here so that the compiler can warn us in
652   // case we add more cases.
653   switch (K) {
654     case SingleLocK:
655     case RangeK:
656       break;
657     case StmtK:
658       // Defensive checking.
659       if (!S)
660         break;
661       return FullSourceLoc(getValidSourceLocation(S, LAC),
662                            const_cast<SourceManager&>(*SM));
663     case DeclK:
664       // Defensive checking.
665       if (!D)
666         break;
667       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
668   }
669 
670   return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
671 }
672 
673 PathDiagnosticRange
genRange(LocationOrAnalysisDeclContext LAC) const674   PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
675   assert(isValid());
676   // Note that we want a 'switch' here so that the compiler can warn us in
677   // case we add more cases.
678   switch (K) {
679     case SingleLocK:
680       return PathDiagnosticRange(SourceRange(Loc,Loc), true);
681     case RangeK:
682       break;
683     case StmtK: {
684       const Stmt *S = asStmt();
685       switch (S->getStmtClass()) {
686         default:
687           break;
688         case Stmt::DeclStmtClass: {
689           const DeclStmt *DS = cast<DeclStmt>(S);
690           if (DS->isSingleDecl()) {
691             // Should always be the case, but we'll be defensive.
692             return SourceRange(DS->getLocStart(),
693                                DS->getSingleDecl()->getLocation());
694           }
695           break;
696         }
697           // FIXME: Provide better range information for different
698           //  terminators.
699         case Stmt::IfStmtClass:
700         case Stmt::WhileStmtClass:
701         case Stmt::DoStmtClass:
702         case Stmt::ForStmtClass:
703         case Stmt::ChooseExprClass:
704         case Stmt::IndirectGotoStmtClass:
705         case Stmt::SwitchStmtClass:
706         case Stmt::BinaryConditionalOperatorClass:
707         case Stmt::ConditionalOperatorClass:
708         case Stmt::ObjCForCollectionStmtClass: {
709           SourceLocation L = getValidSourceLocation(S, LAC);
710           return SourceRange(L, L);
711         }
712       }
713       SourceRange R = S->getSourceRange();
714       if (R.isValid())
715         return R;
716       break;
717     }
718     case DeclK:
719       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
720         return MD->getSourceRange();
721       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
722         if (Stmt *Body = FD->getBody())
723           return Body->getSourceRange();
724       }
725       else {
726         SourceLocation L = D->getLocation();
727         return PathDiagnosticRange(SourceRange(L, L), true);
728       }
729   }
730 
731   return SourceRange(Loc,Loc);
732 }
733 
flatten()734 void PathDiagnosticLocation::flatten() {
735   if (K == StmtK) {
736     K = RangeK;
737     S = 0;
738     D = 0;
739   }
740   else if (K == DeclK) {
741     K = SingleLocK;
742     S = 0;
743     D = 0;
744   }
745 }
746 
747 //===----------------------------------------------------------------------===//
748 // Manipulation of PathDiagnosticCallPieces.
749 //===----------------------------------------------------------------------===//
750 
751 PathDiagnosticCallPiece *
construct(const ExplodedNode * N,const CallExitEnd & CE,const SourceManager & SM)752 PathDiagnosticCallPiece::construct(const ExplodedNode *N,
753                                    const CallExitEnd &CE,
754                                    const SourceManager &SM) {
755   const Decl *caller = CE.getLocationContext()->getDecl();
756   PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
757                                                     CE.getLocationContext(),
758                                                     SM);
759   return new PathDiagnosticCallPiece(caller, pos);
760 }
761 
762 PathDiagnosticCallPiece *
construct(PathPieces & path,const Decl * caller)763 PathDiagnosticCallPiece::construct(PathPieces &path,
764                                    const Decl *caller) {
765   PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
766   path.clear();
767   path.push_front(C);
768   return C;
769 }
770 
setCallee(const CallEnter & CE,const SourceManager & SM)771 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
772                                         const SourceManager &SM) {
773   const StackFrameContext *CalleeCtx = CE.getCalleeContext();
774   Callee = CalleeCtx->getDecl();
775 
776   callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
777   callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
778 }
779 
describeClass(raw_ostream & Out,const CXXRecordDecl * D,StringRef Prefix=StringRef ())780 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
781                                  StringRef Prefix = StringRef()) {
782   if (!D->getIdentifier())
783     return;
784   Out << Prefix << '\'' << *D << '\'';
785 }
786 
describeCodeDecl(raw_ostream & Out,const Decl * D,bool ExtendedDescription,StringRef Prefix=StringRef ())787 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
788                              bool ExtendedDescription,
789                              StringRef Prefix = StringRef()) {
790   if (!D)
791     return false;
792 
793   if (isa<BlockDecl>(D)) {
794     if (ExtendedDescription)
795       Out << Prefix << "anonymous block";
796     return ExtendedDescription;
797   }
798 
799   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
800     Out << Prefix;
801     if (ExtendedDescription && !MD->isUserProvided()) {
802       if (MD->isExplicitlyDefaulted())
803         Out << "defaulted ";
804       else
805         Out << "implicit ";
806     }
807 
808     if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
809       if (CD->isDefaultConstructor())
810         Out << "default ";
811       else if (CD->isCopyConstructor())
812         Out << "copy ";
813       else if (CD->isMoveConstructor())
814         Out << "move ";
815 
816       Out << "constructor";
817       describeClass(Out, MD->getParent(), " for ");
818 
819     } else if (isa<CXXDestructorDecl>(MD)) {
820       if (!MD->isUserProvided()) {
821         Out << "destructor";
822         describeClass(Out, MD->getParent(), " for ");
823       } else {
824         // Use ~Foo for explicitly-written destructors.
825         Out << "'" << *MD << "'";
826       }
827 
828     } else if (MD->isCopyAssignmentOperator()) {
829         Out << "copy assignment operator";
830         describeClass(Out, MD->getParent(), " for ");
831 
832     } else if (MD->isMoveAssignmentOperator()) {
833         Out << "move assignment operator";
834         describeClass(Out, MD->getParent(), " for ");
835 
836     } else {
837       if (MD->getParent()->getIdentifier())
838         Out << "'" << *MD->getParent() << "::" << *MD << "'";
839       else
840         Out << "'" << *MD << "'";
841     }
842 
843     return true;
844   }
845 
846   Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
847   return true;
848 }
849 
850 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallEnterEvent() const851 PathDiagnosticCallPiece::getCallEnterEvent() const {
852   if (!Callee)
853     return 0;
854 
855   SmallString<256> buf;
856   llvm::raw_svector_ostream Out(buf);
857 
858   Out << "Calling ";
859   describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
860 
861   assert(callEnter.asLocation().isValid());
862   return new PathDiagnosticEventPiece(callEnter, Out.str());
863 }
864 
865 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallEnterWithinCallerEvent() const866 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
867   if (!callEnterWithin.asLocation().isValid())
868     return 0;
869   if (Callee->isImplicit())
870     return 0;
871   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
872     if (MD->isDefaulted())
873       return 0;
874 
875   SmallString<256> buf;
876   llvm::raw_svector_ostream Out(buf);
877 
878   Out << "Entered call";
879   describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
880 
881   return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
882 }
883 
884 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallExitEvent() const885 PathDiagnosticCallPiece::getCallExitEvent() const {
886   if (NoExit)
887     return 0;
888 
889   SmallString<256> buf;
890   llvm::raw_svector_ostream Out(buf);
891 
892   if (!CallStackMessage.empty()) {
893     Out << CallStackMessage;
894   } else {
895     bool DidDescribe = describeCodeDecl(Out, Callee,
896                                         /*ExtendedDescription=*/false,
897                                         "Returning from ");
898     if (!DidDescribe)
899       Out << "Returning to caller";
900   }
901 
902   assert(callReturn.asLocation().isValid());
903   return new PathDiagnosticEventPiece(callReturn, Out.str());
904 }
905 
compute_path_size(const PathPieces & pieces,unsigned & size)906 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
907   for (PathPieces::const_iterator it = pieces.begin(),
908                                   et = pieces.end(); it != et; ++it) {
909     const PathDiagnosticPiece *piece = it->getPtr();
910     if (const PathDiagnosticCallPiece *cp =
911         dyn_cast<PathDiagnosticCallPiece>(piece)) {
912       compute_path_size(cp->path, size);
913     }
914     else
915       ++size;
916   }
917 }
918 
full_size()919 unsigned PathDiagnostic::full_size() {
920   unsigned size = 0;
921   compute_path_size(path, size);
922   return size;
923 }
924 
925 //===----------------------------------------------------------------------===//
926 // FoldingSet profiling methods.
927 //===----------------------------------------------------------------------===//
928 
Profile(llvm::FoldingSetNodeID & ID) const929 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
930   ID.AddInteger(Range.getBegin().getRawEncoding());
931   ID.AddInteger(Range.getEnd().getRawEncoding());
932   ID.AddInteger(Loc.getRawEncoding());
933   return;
934 }
935 
Profile(llvm::FoldingSetNodeID & ID) const936 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
937   ID.AddInteger((unsigned) getKind());
938   ID.AddString(str);
939   // FIXME: Add profiling support for code hints.
940   ID.AddInteger((unsigned) getDisplayHint());
941   ArrayRef<SourceRange> Ranges = getRanges();
942   for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
943                                         I != E; ++I) {
944     ID.AddInteger(I->getBegin().getRawEncoding());
945     ID.AddInteger(I->getEnd().getRawEncoding());
946   }
947 }
948 
Profile(llvm::FoldingSetNodeID & ID) const949 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
950   PathDiagnosticPiece::Profile(ID);
951   for (PathPieces::const_iterator it = path.begin(),
952        et = path.end(); it != et; ++it) {
953     ID.Add(**it);
954   }
955 }
956 
Profile(llvm::FoldingSetNodeID & ID) const957 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
958   PathDiagnosticPiece::Profile(ID);
959   ID.Add(Pos);
960 }
961 
Profile(llvm::FoldingSetNodeID & ID) const962 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
963   PathDiagnosticPiece::Profile(ID);
964   for (const_iterator I = begin(), E = end(); I != E; ++I)
965     ID.Add(*I);
966 }
967 
Profile(llvm::FoldingSetNodeID & ID) const968 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
969   PathDiagnosticSpotPiece::Profile(ID);
970   for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
971        I != E; ++I)
972     ID.Add(**I);
973 }
974 
Profile(llvm::FoldingSetNodeID & ID) const975 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
976   ID.Add(getLocation());
977   ID.AddString(BugType);
978   ID.AddString(VerboseDesc);
979   ID.AddString(Category);
980 }
981 
FullProfile(llvm::FoldingSetNodeID & ID) const982 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
983   Profile(ID);
984   for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
985     ID.Add(**I);
986   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
987     ID.AddString(*I);
988 }
989 
~StackHintGenerator()990 StackHintGenerator::~StackHintGenerator() {}
991 
getMessage(const ExplodedNode * N)992 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
993   ProgramPoint P = N->getLocation();
994   CallExitEnd CExit = P.castAs<CallExitEnd>();
995 
996   // FIXME: Use CallEvent to abstract this over all calls.
997   const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
998   const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
999   if (!CE)
1000     return "";
1001 
1002   if (!N)
1003     return getMessageForSymbolNotFound();
1004 
1005   // Check if one of the parameters are set to the interesting symbol.
1006   ProgramStateRef State = N->getState();
1007   const LocationContext *LCtx = N->getLocationContext();
1008   unsigned ArgIndex = 0;
1009   for (CallExpr::const_arg_iterator I = CE->arg_begin(),
1010                                     E = CE->arg_end(); I != E; ++I, ++ArgIndex){
1011     SVal SV = State->getSVal(*I, LCtx);
1012 
1013     // Check if the variable corresponding to the symbol is passed by value.
1014     SymbolRef AS = SV.getAsLocSymbol();
1015     if (AS == Sym) {
1016       return getMessageForArg(*I, ArgIndex);
1017     }
1018 
1019     // Check if the parameter is a pointer to the symbol.
1020     if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
1021       SVal PSV = State->getSVal(Reg->getRegion());
1022       SymbolRef AS = PSV.getAsLocSymbol();
1023       if (AS == Sym) {
1024         return getMessageForArg(*I, ArgIndex);
1025       }
1026     }
1027   }
1028 
1029   // Check if we are returning the interesting symbol.
1030   SVal SV = State->getSVal(CE, LCtx);
1031   SymbolRef RetSym = SV.getAsLocSymbol();
1032   if (RetSym == Sym) {
1033     return getMessageForReturn(CE);
1034   }
1035 
1036   return getMessageForSymbolNotFound();
1037 }
1038 
getMessageForArg(const Expr * ArgE,unsigned ArgIndex)1039 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
1040                                                           unsigned ArgIndex) {
1041   // Printed parameters start at 1, not 0.
1042   ++ArgIndex;
1043 
1044   SmallString<200> buf;
1045   llvm::raw_svector_ostream os(buf);
1046 
1047   os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1048      << " parameter";
1049 
1050   return os.str();
1051 }
1052