• 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/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/AST/Expr.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/DeclCXX.h"
20 #include "clang/AST/DeclObjC.h"
21 #include "clang/AST/ParentMap.h"
22 #include "clang/AST/StmtCXX.h"
23 #include "llvm/ADT/SmallString.h"
24 
25 using namespace clang;
26 using namespace ento;
27 
containsEvent() const28 bool PathDiagnosticMacroPiece::containsEvent() const {
29   for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
30        I!=E; ++I) {
31     if (isa<PathDiagnosticEventPiece>(*I))
32       return true;
33     if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
34       if (MP->containsEvent())
35         return true;
36   }
37   return false;
38 }
39 
StripTrailingDots(StringRef s)40 static StringRef StripTrailingDots(StringRef s) {
41   for (StringRef::size_type i = s.size(); i != 0; --i)
42     if (s[i - 1] != '.')
43       return s.substr(0, i);
44   return "";
45 }
46 
PathDiagnosticPiece(StringRef s,Kind k,DisplayHint hint)47 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
48                                          Kind k, DisplayHint hint)
49   : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
50 
PathDiagnosticPiece(Kind k,DisplayHint hint)51 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
52   : kind(k), Hint(hint) {}
53 
~PathDiagnosticPiece()54 PathDiagnosticPiece::~PathDiagnosticPiece() {}
~PathDiagnosticEventPiece()55 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
~PathDiagnosticCallPiece()56 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
~PathDiagnosticControlFlowPiece()57 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
~PathDiagnosticMacroPiece()58 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
59 
60 
~PathPieces()61 PathPieces::~PathPieces() {}
62 
flattenTo(PathPieces & Primary,PathPieces & Current,bool ShouldFlattenMacros) const63 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
64                            bool ShouldFlattenMacros) const {
65   for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
66     PathDiagnosticPiece *Piece = I->getPtr();
67 
68     switch (Piece->getKind()) {
69     case PathDiagnosticPiece::Call: {
70       PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
71       IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
72         Call->getCallEnterEvent();
73       if (CallEnter)
74         Current.push_back(CallEnter);
75       Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
76       IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
77         Call->getCallExitEvent();
78       if (callExit)
79         Current.push_back(callExit);
80       break;
81     }
82     case PathDiagnosticPiece::Macro: {
83       PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
84       if (ShouldFlattenMacros) {
85         Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
86       } else {
87         Current.push_back(Piece);
88         PathPieces NewPath;
89         Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
90         // FIXME: This probably shouldn't mutate the original path piece.
91         Macro->subPieces = NewPath;
92       }
93       break;
94     }
95     case PathDiagnosticPiece::Event:
96     case PathDiagnosticPiece::ControlFlow:
97       Current.push_back(Piece);
98       break;
99     }
100   }
101 }
102 
103 
~PathDiagnostic()104 PathDiagnostic::~PathDiagnostic() {}
105 
PathDiagnostic(const Decl * declWithIssue,StringRef bugtype,StringRef verboseDesc,StringRef shortDesc,StringRef category)106 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
107                                StringRef bugtype, StringRef verboseDesc,
108                                StringRef shortDesc, StringRef category)
109   : DeclWithIssue(declWithIssue),
110     BugType(StripTrailingDots(bugtype)),
111     VerboseDesc(StripTrailingDots(verboseDesc)),
112     ShortDesc(StripTrailingDots(shortDesc)),
113     Category(StripTrailingDots(category)),
114     path(pathImpl) {}
115 
anchor()116 void PathDiagnosticConsumer::anchor() { }
117 
~PathDiagnosticConsumer()118 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
119   // Delete the contents of the FoldingSet if it isn't empty already.
120   for (llvm::FoldingSet<PathDiagnostic>::iterator it =
121        Diags.begin(), et = Diags.end() ; it != et ; ++it) {
122     delete &*it;
123   }
124 }
125 
HandlePathDiagnostic(PathDiagnostic * D)126 void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
127   llvm::OwningPtr<PathDiagnostic> OwningD(D);
128 
129   if (!D || D->path.empty())
130     return;
131 
132   // We need to flatten the locations (convert Stmt* to locations) because
133   // the referenced statements may be freed by the time the diagnostics
134   // are emitted.
135   D->flattenLocations();
136 
137   // If the PathDiagnosticConsumer does not support diagnostics that
138   // cross file boundaries, prune out such diagnostics now.
139   if (!supportsCrossFileDiagnostics()) {
140     // Verify that the entire path is from the same FileID.
141     FileID FID;
142     const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
143     llvm::SmallVector<const PathPieces *, 5> WorkList;
144     WorkList.push_back(&D->path);
145 
146     while (!WorkList.empty()) {
147       const PathPieces &path = *WorkList.back();
148       WorkList.pop_back();
149 
150       for (PathPieces::const_iterator I = path.begin(), E = path.end();
151            I != E; ++I) {
152         const PathDiagnosticPiece *piece = I->getPtr();
153         FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
154 
155         if (FID.isInvalid()) {
156           FID = SMgr.getFileID(L);
157         } else if (SMgr.getFileID(L) != FID)
158           return; // FIXME: Emit a warning?
159 
160         // Check the source ranges.
161         ArrayRef<SourceRange> Ranges = piece->getRanges();
162         for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
163                                              E = Ranges.end(); I != E; ++I) {
164           SourceLocation L = SMgr.getExpansionLoc(I->getBegin());
165           if (!L.isFileID() || SMgr.getFileID(L) != FID)
166             return; // FIXME: Emit a warning?
167           L = SMgr.getExpansionLoc(I->getEnd());
168           if (!L.isFileID() || SMgr.getFileID(L) != FID)
169             return; // FIXME: Emit a warning?
170         }
171 
172         if (const PathDiagnosticCallPiece *call =
173             dyn_cast<PathDiagnosticCallPiece>(piece)) {
174           WorkList.push_back(&call->path);
175         }
176         else if (const PathDiagnosticMacroPiece *macro =
177                  dyn_cast<PathDiagnosticMacroPiece>(piece)) {
178           WorkList.push_back(&macro->subPieces);
179         }
180       }
181     }
182 
183     if (FID.isInvalid())
184       return; // FIXME: Emit a warning?
185   }
186 
187   // Profile the node to see if we already have something matching it
188   llvm::FoldingSetNodeID profile;
189   D->Profile(profile);
190   void *InsertPos = 0;
191 
192   if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
193     // Keep the PathDiagnostic with the shorter path.
194     // Note, the enclosing routine is called in deterministic order, so the
195     // results will be consistent between runs (no reason to break ties if the
196     // size is the same).
197     const unsigned orig_size = orig->full_size();
198     const unsigned new_size = D->full_size();
199     if (orig_size <= new_size)
200       return;
201 
202     assert(orig != D);
203     Diags.RemoveNode(orig);
204     delete orig;
205   }
206 
207   Diags.InsertNode(OwningD.take());
208 }
209 
210 static llvm::Optional<bool> comparePath(const PathPieces &X,
211                                         const PathPieces &Y);
212 static llvm::Optional<bool>
compareControlFlow(const PathDiagnosticControlFlowPiece & X,const PathDiagnosticControlFlowPiece & Y)213 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
214                    const PathDiagnosticControlFlowPiece &Y) {
215   FullSourceLoc XSL = X.getStartLocation().asLocation();
216   FullSourceLoc YSL = Y.getStartLocation().asLocation();
217   if (XSL != YSL)
218     return XSL.isBeforeInTranslationUnitThan(YSL);
219   FullSourceLoc XEL = X.getEndLocation().asLocation();
220   FullSourceLoc YEL = Y.getEndLocation().asLocation();
221   if (XEL != YEL)
222     return XEL.isBeforeInTranslationUnitThan(YEL);
223   return llvm::Optional<bool>();
224 }
225 
226 static llvm::Optional<bool>
compareMacro(const PathDiagnosticMacroPiece & X,const PathDiagnosticMacroPiece & Y)227 compareMacro(const PathDiagnosticMacroPiece &X,
228              const PathDiagnosticMacroPiece &Y) {
229   return comparePath(X.subPieces, Y.subPieces);
230 }
231 
232 static llvm::Optional<bool>
compareCall(const PathDiagnosticCallPiece & X,const PathDiagnosticCallPiece & Y)233 compareCall(const PathDiagnosticCallPiece &X,
234             const PathDiagnosticCallPiece &Y) {
235   FullSourceLoc X_CEL = X.callEnter.asLocation();
236   FullSourceLoc Y_CEL = Y.callEnter.asLocation();
237   if (X_CEL != Y_CEL)
238     return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
239   FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
240   FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
241   if (X_CEWL != Y_CEWL)
242     return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
243   FullSourceLoc X_CRL = X.callReturn.asLocation();
244   FullSourceLoc Y_CRL = Y.callReturn.asLocation();
245   if (X_CRL != Y_CRL)
246     return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
247   return comparePath(X.path, Y.path);
248 }
249 
comparePiece(const PathDiagnosticPiece & X,const PathDiagnosticPiece & Y)250 static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
251                                          const PathDiagnosticPiece &Y) {
252   if (X.getKind() != Y.getKind())
253     return X.getKind() < Y.getKind();
254 
255   FullSourceLoc XL = X.getLocation().asLocation();
256   FullSourceLoc YL = Y.getLocation().asLocation();
257   if (XL != YL)
258     return XL.isBeforeInTranslationUnitThan(YL);
259 
260   if (X.getString() != Y.getString())
261     return X.getString() < Y.getString();
262 
263   if (X.getRanges().size() != Y.getRanges().size())
264     return X.getRanges().size() < Y.getRanges().size();
265 
266   const SourceManager &SM = XL.getManager();
267 
268   for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
269     SourceRange XR = X.getRanges()[i];
270     SourceRange YR = Y.getRanges()[i];
271     if (XR != YR) {
272       if (XR.getBegin() != YR.getBegin())
273         return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
274       return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
275     }
276   }
277 
278   switch (X.getKind()) {
279     case clang::ento::PathDiagnosticPiece::ControlFlow:
280       return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
281                                 cast<PathDiagnosticControlFlowPiece>(Y));
282     case clang::ento::PathDiagnosticPiece::Event:
283       return llvm::Optional<bool>();
284     case clang::ento::PathDiagnosticPiece::Macro:
285       return compareMacro(cast<PathDiagnosticMacroPiece>(X),
286                           cast<PathDiagnosticMacroPiece>(Y));
287     case clang::ento::PathDiagnosticPiece::Call:
288       return compareCall(cast<PathDiagnosticCallPiece>(X),
289                          cast<PathDiagnosticCallPiece>(Y));
290   }
291   llvm_unreachable("all cases handled");
292 }
293 
comparePath(const PathPieces & X,const PathPieces & Y)294 static llvm::Optional<bool> comparePath(const PathPieces &X,
295                                         const PathPieces &Y) {
296   if (X.size() != Y.size())
297     return X.size() < Y.size();
298   for (unsigned i = 0, n = X.size(); i != n; ++i) {
299     llvm::Optional<bool> b = comparePiece(*X[i], *Y[i]);
300     if (b.hasValue())
301       return b.getValue();
302   }
303   return llvm::Optional<bool>();
304 }
305 
compare(const PathDiagnostic & X,const PathDiagnostic & Y)306 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
307   FullSourceLoc XL = X.getLocation().asLocation();
308   FullSourceLoc YL = Y.getLocation().asLocation();
309   if (XL != YL)
310     return XL.isBeforeInTranslationUnitThan(YL);
311   if (X.getBugType() != Y.getBugType())
312     return X.getBugType() < Y.getBugType();
313   if (X.getCategory() != Y.getCategory())
314     return X.getCategory() < Y.getCategory();
315   if (X.getVerboseDescription() != Y.getVerboseDescription())
316     return X.getVerboseDescription() < Y.getVerboseDescription();
317   if (X.getShortDescription() != Y.getShortDescription())
318     return X.getShortDescription() < Y.getShortDescription();
319   if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
320     const Decl *XD = X.getDeclWithIssue();
321     if (!XD)
322       return true;
323     const Decl *YD = Y.getDeclWithIssue();
324     if (!YD)
325       return false;
326     SourceLocation XDL = XD->getLocation();
327     SourceLocation YDL = YD->getLocation();
328     if (XDL != YDL) {
329       const SourceManager &SM = XL.getManager();
330       return SM.isBeforeInTranslationUnit(XDL, YDL);
331     }
332   }
333   PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
334   PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
335   if (XE - XI != YE - YI)
336     return (XE - XI) < (YE - YI);
337   for ( ; XI != XE ; ++XI, ++YI) {
338     if (*XI != *YI)
339       return (*XI) < (*YI);
340   }
341   llvm::Optional<bool> b = comparePath(X.path, Y.path);
342   assert(b.hasValue());
343   return b.getValue();
344 }
345 
346 namespace {
347 struct CompareDiagnostics {
348   // Compare if 'X' is "<" than 'Y'.
operator ()__anon25adf5090111::CompareDiagnostics349   bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
350     if (X == Y)
351       return false;
352     return compare(*X, *Y);
353   }
354 };
355 }
356 
FlushDiagnostics(PathDiagnosticConsumer::FilesMade * Files)357 void PathDiagnosticConsumer::FlushDiagnostics(
358                                      PathDiagnosticConsumer::FilesMade *Files) {
359   if (flushed)
360     return;
361 
362   flushed = true;
363 
364   std::vector<const PathDiagnostic *> BatchDiags;
365   for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
366        et = Diags.end(); it != et; ++it) {
367     const PathDiagnostic *D = &*it;
368     BatchDiags.push_back(D);
369   }
370 
371   // Sort the diagnostics so that they are always emitted in a deterministic
372   // order.
373   if (!BatchDiags.empty())
374     std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
375 
376   FlushDiagnosticsImpl(BatchDiags, Files);
377 
378   // Delete the flushed diagnostics.
379   for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
380        et = BatchDiags.end(); it != et; ++it) {
381     const PathDiagnostic *D = *it;
382     delete D;
383   }
384 
385   // Clear out the FoldingSet.
386   Diags.clear();
387 }
388 
addDiagnostic(const PathDiagnostic & PD,StringRef ConsumerName,StringRef FileName)389 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
390                                                       StringRef ConsumerName,
391                                                       StringRef FileName) {
392   llvm::FoldingSetNodeID NodeID;
393   NodeID.Add(PD);
394   void *InsertPos;
395   PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
396   if (!Entry) {
397     Entry = Alloc.Allocate<PDFileEntry>();
398     Entry = new (Entry) PDFileEntry(NodeID);
399     InsertNode(Entry, InsertPos);
400   }
401 
402   // Allocate persistent storage for the file name.
403   char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
404   memcpy(FileName_cstr, FileName.data(), FileName.size());
405 
406   Entry->files.push_back(std::make_pair(ConsumerName,
407                                         StringRef(FileName_cstr,
408                                                   FileName.size())));
409 }
410 
411 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
getFiles(const PathDiagnostic & PD)412 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
413   llvm::FoldingSetNodeID NodeID;
414   NodeID.Add(PD);
415   void *InsertPos;
416   PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
417   if (!Entry)
418     return 0;
419   return &Entry->files;
420 }
421 
422 //===----------------------------------------------------------------------===//
423 // PathDiagnosticLocation methods.
424 //===----------------------------------------------------------------------===//
425 
getValidSourceLocation(const Stmt * S,LocationOrAnalysisDeclContext LAC,bool UseEnd=false)426 static SourceLocation getValidSourceLocation(const Stmt* S,
427                                              LocationOrAnalysisDeclContext LAC,
428                                              bool UseEnd = false) {
429   SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
430   assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
431                           "be passed to PathDiagnosticLocation upon creation.");
432 
433   // S might be a temporary statement that does not have a location in the
434   // source code, so find an enclosing statement and use its location.
435   if (!L.isValid()) {
436 
437     AnalysisDeclContext *ADC;
438     if (LAC.is<const LocationContext*>())
439       ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
440     else
441       ADC = LAC.get<AnalysisDeclContext*>();
442 
443     ParentMap &PM = ADC->getParentMap();
444 
445     const Stmt *Parent = S;
446     do {
447       Parent = PM.getParent(Parent);
448 
449       // In rare cases, we have implicit top-level expressions,
450       // such as arguments for implicit member initializers.
451       // In this case, fall back to the start of the body (even if we were
452       // asked for the statement end location).
453       if (!Parent) {
454         const Stmt *Body = ADC->getBody();
455         if (Body)
456           L = Body->getLocStart();
457         else
458           L = ADC->getDecl()->getLocEnd();
459         break;
460       }
461 
462       L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
463     } while (!L.isValid());
464   }
465 
466   return L;
467 }
468 
469 static PathDiagnosticLocation
getLocationForCaller(const StackFrameContext * SFC,const LocationContext * CallerCtx,const SourceManager & SM)470 getLocationForCaller(const StackFrameContext *SFC,
471                      const LocationContext *CallerCtx,
472                      const SourceManager &SM) {
473   const CFGBlock &Block = *SFC->getCallSiteBlock();
474   CFGElement Source = Block[SFC->getIndex()];
475 
476   switch (Source.getKind()) {
477   case CFGElement::Invalid:
478     llvm_unreachable("Invalid CFGElement");
479   case CFGElement::Statement:
480     return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(),
481                                   SM, CallerCtx);
482   case CFGElement::Initializer: {
483     const CFGInitializer &Init = cast<CFGInitializer>(Source);
484     return PathDiagnosticLocation(Init.getInitializer()->getInit(),
485                                   SM, CallerCtx);
486   }
487   case CFGElement::AutomaticObjectDtor: {
488     const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source);
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 (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
585     const CFGBlock *BSrc = BE->getSrc();
586     S = BSrc->getTerminatorCondition();
587   }
588   else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
589     S = PS->getStmt();
590   }
591   else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) {
592     return PathDiagnosticLocation(PIE->getLocation(), SMng);
593   }
594   else if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
595     return getLocationForCaller(CE->getCalleeContext(),
596                                 CE->getLocationContext(),
597                                 SMng);
598   }
599   else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P)) {
600     return getLocationForCaller(CEE->getCalleeContext(),
601                                 CEE->getLocationContext(),
602                                 SMng);
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 
615   while (NI) {
616     ProgramPoint P = NI->getLocation();
617     const LocationContext *LC = P.getLocationContext();
618     if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
619       return PathDiagnosticLocation(PS->getStmt(), SM, LC);
620     else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
621       const Stmt *Term = BE->getSrc()->getTerminator();
622       if (Term) {
623         return PathDiagnosticLocation(Term, SM, LC);
624       }
625     }
626     NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
627   }
628 
629   return createDeclEnd(N->getLocationContext(), SM);
630 }
631 
createSingleLocation(const PathDiagnosticLocation & PDL)632 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
633                                            const PathDiagnosticLocation &PDL) {
634   FullSourceLoc L = PDL.asLocation();
635   return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
636 }
637 
638 FullSourceLoc
genLocation(SourceLocation L,LocationOrAnalysisDeclContext LAC) const639   PathDiagnosticLocation::genLocation(SourceLocation L,
640                                       LocationOrAnalysisDeclContext LAC) const {
641   assert(isValid());
642   // Note that we want a 'switch' here so that the compiler can warn us in
643   // case we add more cases.
644   switch (K) {
645     case SingleLocK:
646     case RangeK:
647       break;
648     case StmtK:
649       // Defensive checking.
650       if (!S)
651         break;
652       return FullSourceLoc(getValidSourceLocation(S, LAC),
653                            const_cast<SourceManager&>(*SM));
654     case DeclK:
655       // Defensive checking.
656       if (!D)
657         break;
658       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
659   }
660 
661   return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
662 }
663 
664 PathDiagnosticRange
genRange(LocationOrAnalysisDeclContext LAC) const665   PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
666   assert(isValid());
667   // Note that we want a 'switch' here so that the compiler can warn us in
668   // case we add more cases.
669   switch (K) {
670     case SingleLocK:
671       return PathDiagnosticRange(SourceRange(Loc,Loc), true);
672     case RangeK:
673       break;
674     case StmtK: {
675       const Stmt *S = asStmt();
676       switch (S->getStmtClass()) {
677         default:
678           break;
679         case Stmt::DeclStmtClass: {
680           const DeclStmt *DS = cast<DeclStmt>(S);
681           if (DS->isSingleDecl()) {
682             // Should always be the case, but we'll be defensive.
683             return SourceRange(DS->getLocStart(),
684                                DS->getSingleDecl()->getLocation());
685           }
686           break;
687         }
688           // FIXME: Provide better range information for different
689           //  terminators.
690         case Stmt::IfStmtClass:
691         case Stmt::WhileStmtClass:
692         case Stmt::DoStmtClass:
693         case Stmt::ForStmtClass:
694         case Stmt::ChooseExprClass:
695         case Stmt::IndirectGotoStmtClass:
696         case Stmt::SwitchStmtClass:
697         case Stmt::BinaryConditionalOperatorClass:
698         case Stmt::ConditionalOperatorClass:
699         case Stmt::ObjCForCollectionStmtClass: {
700           SourceLocation L = getValidSourceLocation(S, LAC);
701           return SourceRange(L, L);
702         }
703       }
704       SourceRange R = S->getSourceRange();
705       if (R.isValid())
706         return R;
707       break;
708     }
709     case DeclK:
710       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
711         return MD->getSourceRange();
712       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
713         if (Stmt *Body = FD->getBody())
714           return Body->getSourceRange();
715       }
716       else {
717         SourceLocation L = D->getLocation();
718         return PathDiagnosticRange(SourceRange(L, L), true);
719       }
720   }
721 
722   return SourceRange(Loc,Loc);
723 }
724 
flatten()725 void PathDiagnosticLocation::flatten() {
726   if (K == StmtK) {
727     K = RangeK;
728     S = 0;
729     D = 0;
730   }
731   else if (K == DeclK) {
732     K = SingleLocK;
733     S = 0;
734     D = 0;
735   }
736 }
737 
738 //===----------------------------------------------------------------------===//
739 // Manipulation of PathDiagnosticCallPieces.
740 //===----------------------------------------------------------------------===//
741 
742 PathDiagnosticCallPiece *
construct(const ExplodedNode * N,const CallExitEnd & CE,const SourceManager & SM)743 PathDiagnosticCallPiece::construct(const ExplodedNode *N,
744                                    const CallExitEnd &CE,
745                                    const SourceManager &SM) {
746   const Decl *caller = CE.getLocationContext()->getDecl();
747   PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
748                                                     CE.getLocationContext(),
749                                                     SM);
750   return new PathDiagnosticCallPiece(caller, pos);
751 }
752 
753 PathDiagnosticCallPiece *
construct(PathPieces & path,const Decl * caller)754 PathDiagnosticCallPiece::construct(PathPieces &path,
755                                    const Decl *caller) {
756   PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
757   path.clear();
758   path.push_front(C);
759   return C;
760 }
761 
setCallee(const CallEnter & CE,const SourceManager & SM)762 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
763                                         const SourceManager &SM) {
764   const StackFrameContext *CalleeCtx = CE.getCalleeContext();
765   Callee = CalleeCtx->getDecl();
766 
767   callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
768   callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
769 }
770 
771 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallEnterEvent() const772 PathDiagnosticCallPiece::getCallEnterEvent() const {
773   if (!Callee)
774     return 0;
775   SmallString<256> buf;
776   llvm::raw_svector_ostream Out(buf);
777   if (isa<BlockDecl>(Callee))
778     Out << "Calling anonymous block";
779   else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
780     Out << "Calling '" << *ND << "'";
781   StringRef msg = Out.str();
782   if (msg.empty())
783     return 0;
784   return new PathDiagnosticEventPiece(callEnter, msg);
785 }
786 
787 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallEnterWithinCallerEvent() const788 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
789   SmallString<256> buf;
790   llvm::raw_svector_ostream Out(buf);
791   if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
792     Out << "Entered call from '" << *ND << "'";
793   else
794     Out << "Entered call";
795   StringRef msg = Out.str();
796   if (msg.empty())
797     return 0;
798   return new PathDiagnosticEventPiece(callEnterWithin, msg);
799 }
800 
801 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallExitEvent() const802 PathDiagnosticCallPiece::getCallExitEvent() const {
803   if (NoExit)
804     return 0;
805   SmallString<256> buf;
806   llvm::raw_svector_ostream Out(buf);
807   if (!CallStackMessage.empty())
808     Out << CallStackMessage;
809   else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
810     Out << "Returning from '" << *ND << "'";
811   else
812     Out << "Returning to caller";
813   return new PathDiagnosticEventPiece(callReturn, Out.str());
814 }
815 
compute_path_size(const PathPieces & pieces,unsigned & size)816 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
817   for (PathPieces::const_iterator it = pieces.begin(),
818                                   et = pieces.end(); it != et; ++it) {
819     const PathDiagnosticPiece *piece = it->getPtr();
820     if (const PathDiagnosticCallPiece *cp =
821         dyn_cast<PathDiagnosticCallPiece>(piece)) {
822       compute_path_size(cp->path, size);
823     }
824     else
825       ++size;
826   }
827 }
828 
full_size()829 unsigned PathDiagnostic::full_size() {
830   unsigned size = 0;
831   compute_path_size(path, size);
832   return size;
833 }
834 
835 //===----------------------------------------------------------------------===//
836 // FoldingSet profiling methods.
837 //===----------------------------------------------------------------------===//
838 
Profile(llvm::FoldingSetNodeID & ID) const839 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
840   ID.AddInteger(Range.getBegin().getRawEncoding());
841   ID.AddInteger(Range.getEnd().getRawEncoding());
842   ID.AddInteger(Loc.getRawEncoding());
843   return;
844 }
845 
Profile(llvm::FoldingSetNodeID & ID) const846 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
847   ID.AddInteger((unsigned) getKind());
848   ID.AddString(str);
849   // FIXME: Add profiling support for code hints.
850   ID.AddInteger((unsigned) getDisplayHint());
851   ArrayRef<SourceRange> Ranges = getRanges();
852   for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
853                                         I != E; ++I) {
854     ID.AddInteger(I->getBegin().getRawEncoding());
855     ID.AddInteger(I->getEnd().getRawEncoding());
856   }
857 }
858 
Profile(llvm::FoldingSetNodeID & ID) const859 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
860   PathDiagnosticPiece::Profile(ID);
861   for (PathPieces::const_iterator it = path.begin(),
862        et = path.end(); it != et; ++it) {
863     ID.Add(**it);
864   }
865 }
866 
Profile(llvm::FoldingSetNodeID & ID) const867 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
868   PathDiagnosticPiece::Profile(ID);
869   ID.Add(Pos);
870 }
871 
Profile(llvm::FoldingSetNodeID & ID) const872 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
873   PathDiagnosticPiece::Profile(ID);
874   for (const_iterator I = begin(), E = end(); I != E; ++I)
875     ID.Add(*I);
876 }
877 
Profile(llvm::FoldingSetNodeID & ID) const878 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
879   PathDiagnosticSpotPiece::Profile(ID);
880   for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
881        I != E; ++I)
882     ID.Add(**I);
883 }
884 
Profile(llvm::FoldingSetNodeID & ID) const885 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
886   ID.Add(getLocation());
887   ID.AddString(BugType);
888   ID.AddString(VerboseDesc);
889   ID.AddString(Category);
890 }
891 
FullProfile(llvm::FoldingSetNodeID & ID) const892 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
893   Profile(ID);
894   for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
895     ID.Add(**I);
896   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
897     ID.AddString(*I);
898 }
899 
~StackHintGenerator()900 StackHintGenerator::~StackHintGenerator() {}
901 
getMessage(const ExplodedNode * N)902 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
903   ProgramPoint P = N->getLocation();
904   const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P);
905   assert(CExit && "Stack Hints should be constructed at CallExitEnd points.");
906 
907   // FIXME: Use CallEvent to abstract this over all calls.
908   const Stmt *CallSite = CExit->getCalleeContext()->getCallSite();
909   const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
910   if (!CE)
911     return "";
912 
913   if (!N)
914     return getMessageForSymbolNotFound();
915 
916   // Check if one of the parameters are set to the interesting symbol.
917   ProgramStateRef State = N->getState();
918   const LocationContext *LCtx = N->getLocationContext();
919   unsigned ArgIndex = 0;
920   for (CallExpr::const_arg_iterator I = CE->arg_begin(),
921                                     E = CE->arg_end(); I != E; ++I, ++ArgIndex){
922     SVal SV = State->getSVal(*I, LCtx);
923 
924     // Check if the variable corresponding to the symbol is passed by value.
925     SymbolRef AS = SV.getAsLocSymbol();
926     if (AS == Sym) {
927       return getMessageForArg(*I, ArgIndex);
928     }
929 
930     // Check if the parameter is a pointer to the symbol.
931     if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
932       SVal PSV = State->getSVal(Reg->getRegion());
933       SymbolRef AS = PSV.getAsLocSymbol();
934       if (AS == Sym) {
935         return getMessageForArg(*I, ArgIndex);
936       }
937     }
938   }
939 
940   // Check if we are returning the interesting symbol.
941   SVal SV = State->getSVal(CE, LCtx);
942   SymbolRef RetSym = SV.getAsLocSymbol();
943   if (RetSym == Sym) {
944     return getMessageForReturn(CE);
945   }
946 
947   return getMessageForSymbolNotFound();
948 }
949 
950 /// TODO: This is copied from clang diagnostics. Maybe we could just move it to
951 /// some common place. (Same as HandleOrdinalModifier.)
printOrdinal(unsigned ValNo,llvm::raw_svector_ostream & Out)952 void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
953                                                llvm::raw_svector_ostream &Out) {
954   assert(ValNo != 0 && "ValNo must be strictly positive!");
955 
956   // We could use text forms for the first N ordinals, but the numeric
957   // forms are actually nicer in diagnostics because they stand out.
958   Out << ValNo;
959 
960   // It is critically important that we do this perfectly for
961   // user-written sequences with over 100 elements.
962   switch (ValNo % 100) {
963   case 11:
964   case 12:
965   case 13:
966     Out << "th"; return;
967   default:
968     switch (ValNo % 10) {
969     case 1: Out << "st"; return;
970     case 2: Out << "nd"; return;
971     case 3: Out << "rd"; return;
972     default: Out << "th"; return;
973     }
974   }
975 }
976 
getMessageForArg(const Expr * ArgE,unsigned ArgIndex)977 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
978                                                         unsigned ArgIndex) {
979   SmallString<200> buf;
980   llvm::raw_svector_ostream os(buf);
981 
982   os << Msg << " via ";
983   // Printed parameters start at 1, not 0.
984   printOrdinal(++ArgIndex, os);
985   os << " parameter";
986 
987   return os.str();
988 }
989