• 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/Expr.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclObjC.h"
18 #include "clang/AST/StmtCXX.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/Support/Casting.h"
21 
22 using namespace clang;
23 using namespace ento;
24 using llvm::dyn_cast;
25 using llvm::isa;
26 
containsEvent() const27 bool PathDiagnosticMacroPiece::containsEvent() const {
28   for (const_iterator I = begin(), E = end(); I!=E; ++I) {
29     if (isa<PathDiagnosticEventPiece>(*I))
30       return true;
31 
32     if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
33       if (MP->containsEvent())
34         return true;
35   }
36 
37   return false;
38 }
39 
StripTrailingDots(llvm::StringRef s)40 static llvm::StringRef StripTrailingDots(llvm::StringRef s) {
41   for (llvm::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(llvm::StringRef s,Kind k,DisplayHint hint)47 PathDiagnosticPiece::PathDiagnosticPiece(llvm::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() {}
~PathDiagnosticControlFlowPiece()56 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
57 
~PathDiagnosticMacroPiece()58 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
59   for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
60 }
61 
PathDiagnostic()62 PathDiagnostic::PathDiagnostic() : Size(0) {}
63 
~PathDiagnostic()64 PathDiagnostic::~PathDiagnostic() {
65   for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
66 }
67 
resetPath(bool deletePieces)68 void PathDiagnostic::resetPath(bool deletePieces) {
69   Size = 0;
70 
71   if (deletePieces)
72     for (iterator I=begin(), E=end(); I!=E; ++I)
73       delete &*I;
74 
75   path.clear();
76 }
77 
78 
PathDiagnostic(llvm::StringRef bugtype,llvm::StringRef desc,llvm::StringRef category)79 PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
80                                llvm::StringRef category)
81   : Size(0),
82     BugType(StripTrailingDots(bugtype)),
83     Desc(StripTrailingDots(desc)),
84     Category(StripTrailingDots(category)) {}
85 
HandleDiagnostic(Diagnostic::Level DiagLevel,const DiagnosticInfo & Info)86 void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
87                                             const DiagnosticInfo &Info) {
88   // Default implementation (Warnings/errors count).
89   DiagnosticClient::HandleDiagnostic(DiagLevel, Info);
90 
91   // Create a PathDiagnostic with a single piece.
92 
93   PathDiagnostic* D = new PathDiagnostic();
94 
95   const char *LevelStr;
96   switch (DiagLevel) {
97   default:
98   case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
99   case Diagnostic::Note:    LevelStr = "note: "; break;
100   case Diagnostic::Warning: LevelStr = "warning: "; break;
101   case Diagnostic::Error:   LevelStr = "error: "; break;
102   case Diagnostic::Fatal:   LevelStr = "fatal error: "; break;
103   }
104 
105   llvm::SmallString<100> StrC;
106   StrC += LevelStr;
107   Info.FormatDiagnostic(StrC);
108 
109   PathDiagnosticPiece *P =
110     new PathDiagnosticEventPiece(FullSourceLoc(Info.getLocation(),
111                                                Info.getSourceManager()),
112                                  StrC.str());
113 
114   for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
115     P->addRange(Info.getRange(i).getAsRange());
116   for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
117     P->addFixItHint(Info.getFixItHint(i));
118   D->push_front(P);
119 
120   HandlePathDiagnostic(D);
121 }
122 
123 //===----------------------------------------------------------------------===//
124 // PathDiagnosticLocation methods.
125 //===----------------------------------------------------------------------===//
126 
asLocation() const127 FullSourceLoc PathDiagnosticLocation::asLocation() const {
128   assert(isValid());
129   // Note that we want a 'switch' here so that the compiler can warn us in
130   // case we add more cases.
131   switch (K) {
132     case SingleLocK:
133     case RangeK:
134       break;
135     case StmtK:
136       return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
137     case DeclK:
138       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
139   }
140 
141   return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
142 }
143 
asRange() const144 PathDiagnosticRange PathDiagnosticLocation::asRange() const {
145   assert(isValid());
146   // Note that we want a 'switch' here so that the compiler can warn us in
147   // case we add more cases.
148   switch (K) {
149     case SingleLocK:
150       return PathDiagnosticRange(R, true);
151     case RangeK:
152       break;
153     case StmtK: {
154       const Stmt *S = asStmt();
155       switch (S->getStmtClass()) {
156         default:
157           break;
158         case Stmt::DeclStmtClass: {
159           const DeclStmt *DS = cast<DeclStmt>(S);
160           if (DS->isSingleDecl()) {
161             // Should always be the case, but we'll be defensive.
162             return SourceRange(DS->getLocStart(),
163                                DS->getSingleDecl()->getLocation());
164           }
165           break;
166         }
167           // FIXME: Provide better range information for different
168           //  terminators.
169         case Stmt::IfStmtClass:
170         case Stmt::WhileStmtClass:
171         case Stmt::DoStmtClass:
172         case Stmt::ForStmtClass:
173         case Stmt::ChooseExprClass:
174         case Stmt::IndirectGotoStmtClass:
175         case Stmt::SwitchStmtClass:
176         case Stmt::BinaryConditionalOperatorClass:
177         case Stmt::ConditionalOperatorClass:
178         case Stmt::ObjCForCollectionStmtClass: {
179           SourceLocation L = S->getLocStart();
180           return SourceRange(L, L);
181         }
182       }
183 
184       return S->getSourceRange();
185     }
186     case DeclK:
187       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
188         return MD->getSourceRange();
189       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
190         if (Stmt *Body = FD->getBody())
191           return Body->getSourceRange();
192       }
193       else {
194         SourceLocation L = D->getLocation();
195         return PathDiagnosticRange(SourceRange(L, L), true);
196       }
197   }
198 
199   return R;
200 }
201 
flatten()202 void PathDiagnosticLocation::flatten() {
203   if (K == StmtK) {
204     R = asRange();
205     K = RangeK;
206     S = 0;
207     D = 0;
208   }
209   else if (K == DeclK) {
210     SourceLocation L = D->getLocation();
211     R = SourceRange(L, L);
212     K = SingleLocK;
213     S = 0;
214     D = 0;
215   }
216 }
217 
218 //===----------------------------------------------------------------------===//
219 // FoldingSet profiling methods.
220 //===----------------------------------------------------------------------===//
221 
Profile(llvm::FoldingSetNodeID & ID) const222 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
223   ID.AddInteger((unsigned) K);
224   switch (K) {
225     case RangeK:
226       ID.AddInteger(R.getBegin().getRawEncoding());
227       ID.AddInteger(R.getEnd().getRawEncoding());
228       break;
229     case SingleLocK:
230       ID.AddInteger(R.getBegin().getRawEncoding());
231       break;
232     case StmtK:
233       ID.Add(S);
234       break;
235     case DeclK:
236       ID.Add(D);
237       break;
238   }
239   return;
240 }
241 
Profile(llvm::FoldingSetNodeID & ID) const242 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
243   ID.AddInteger((unsigned) getKind());
244   ID.AddString(str);
245   // FIXME: Add profiling support for code hints.
246   ID.AddInteger((unsigned) getDisplayHint());
247   for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
248     ID.AddInteger(I->getBegin().getRawEncoding());
249     ID.AddInteger(I->getEnd().getRawEncoding());
250   }
251 }
252 
Profile(llvm::FoldingSetNodeID & ID) const253 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
254   PathDiagnosticPiece::Profile(ID);
255   ID.Add(Pos);
256 }
257 
Profile(llvm::FoldingSetNodeID & ID) const258 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
259   PathDiagnosticPiece::Profile(ID);
260   for (const_iterator I = begin(), E = end(); I != E; ++I)
261     ID.Add(*I);
262 }
263 
Profile(llvm::FoldingSetNodeID & ID) const264 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
265   PathDiagnosticSpotPiece::Profile(ID);
266   for (const_iterator I = begin(), E = end(); I != E; ++I)
267     ID.Add(**I);
268 }
269 
Profile(llvm::FoldingSetNodeID & ID) const270 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
271   ID.AddInteger(Size);
272   ID.AddString(BugType);
273   ID.AddString(Desc);
274   ID.AddString(Category);
275   for (const_iterator I = begin(), E = end(); I != E; ++I)
276     ID.Add(*I);
277 
278   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
279     ID.AddString(*I);
280 }
281