]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Core / PathDiagnostic.cpp
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/AST/Expr.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/DeclObjC.h"
19 #include "clang/AST/ParentMap.h"
20 #include "clang/AST/StmtCXX.h"
21 #include "llvm/ADT/SmallString.h"
22
23 using namespace clang;
24 using namespace ento;
25
26 bool PathDiagnosticMacroPiece::containsEvent() const {
27   for (const_iterator I = begin(), E = end(); I!=E; ++I) {
28     if (isa<PathDiagnosticEventPiece>(*I))
29       return true;
30
31     if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
32       if (MP->containsEvent())
33         return true;
34   }
35
36   return false;
37 }
38
39 static StringRef StripTrailingDots(StringRef s) {
40   for (StringRef::size_type i = s.size(); i != 0; --i)
41     if (s[i - 1] != '.')
42       return s.substr(0, i);
43   return "";
44 }
45
46 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
47                                          Kind k, DisplayHint hint)
48   : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
49
50 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
51   : kind(k), Hint(hint) {}
52
53 PathDiagnosticPiece::~PathDiagnosticPiece() {}
54 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
55 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
56
57 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
58   for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
59 }
60
61 PathDiagnostic::PathDiagnostic() : Size(0) {}
62
63 PathDiagnostic::~PathDiagnostic() {
64   for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
65 }
66
67 void PathDiagnostic::resetPath(bool deletePieces) {
68   Size = 0;
69
70   if (deletePieces)
71     for (iterator I=begin(), E=end(); I!=E; ++I)
72       delete &*I;
73
74   path.clear();
75 }
76
77
78 PathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc,
79                                StringRef category)
80   : Size(0),
81     BugType(StripTrailingDots(bugtype)),
82     Desc(StripTrailingDots(desc)),
83     Category(StripTrailingDots(category)) {}
84
85 void PathDiagnosticConsumer::HandlePathDiagnostic(const PathDiagnostic *D) {
86   // For now this simply forwards to HandlePathDiagnosticImpl.  In the future
87   // we can use this indirection to control for multi-threaded access to
88   // the PathDiagnosticConsumer from multiple bug reporters.
89   HandlePathDiagnosticImpl(D);
90 }
91
92 //===----------------------------------------------------------------------===//
93 // PathDiagnosticLocation methods.
94 //===----------------------------------------------------------------------===//
95
96 static SourceLocation getValidSourceLocation(const Stmt* S,
97                                              LocationOrAnalysisContext LAC) {
98   SourceLocation L = S->getLocStart();
99   assert(!LAC.isNull() && "A valid LocationContext or AnalysisContext should "
100                           "be passed to PathDiagnosticLocation upon creation.");
101
102   // S might be a temporary statement that does not have a location in the
103   // source code, so find an enclosing statement and use it's location.
104   if (!L.isValid()) {
105
106     ParentMap *PM = 0;
107     if (LAC.is<const LocationContext*>())
108       PM = &LAC.get<const LocationContext*>()->getParentMap();
109     else
110       PM = &LAC.get<AnalysisContext*>()->getParentMap();
111
112     while (!L.isValid()) {
113       S = PM->getParent(S);
114       L = S->getLocStart();
115     }
116   }
117
118   return L;
119 }
120
121 PathDiagnosticLocation
122   PathDiagnosticLocation::createBegin(const Decl *D,
123                                       const SourceManager &SM) {
124   return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
125 }
126
127 PathDiagnosticLocation
128   PathDiagnosticLocation::createBegin(const Stmt *S,
129                                       const SourceManager &SM,
130                                       LocationOrAnalysisContext LAC) {
131   return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
132                                 SM, SingleLocK);
133 }
134
135 PathDiagnosticLocation
136   PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
137                                             const SourceManager &SM) {
138   return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
139 }
140
141 PathDiagnosticLocation
142   PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
143                                           const SourceManager &SM) {
144   return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
145 }
146
147 PathDiagnosticLocation
148   PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
149                                            const SourceManager &SM) {
150   SourceLocation L = CS->getLBracLoc();
151   return PathDiagnosticLocation(L, SM, SingleLocK);
152 }
153
154 PathDiagnosticLocation
155   PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
156                                          const SourceManager &SM) {
157   SourceLocation L = CS->getRBracLoc();
158   return PathDiagnosticLocation(L, SM, SingleLocK);
159 }
160
161 PathDiagnosticLocation
162   PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
163                                           const SourceManager &SM) {
164   // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
165   if (const CompoundStmt *CS =
166         dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
167     if (!CS->body_empty()) {
168       SourceLocation Loc = (*CS->body_begin())->getLocStart();
169       return PathDiagnosticLocation(Loc, SM, SingleLocK);
170     }
171
172   return PathDiagnosticLocation();
173 }
174
175 PathDiagnosticLocation
176   PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
177                                         const SourceManager &SM) {
178   SourceLocation L = LC->getDecl()->getBodyRBrace();
179   return PathDiagnosticLocation(L, SM, SingleLocK);
180 }
181
182 PathDiagnosticLocation
183   PathDiagnosticLocation::create(const ProgramPoint& P,
184                                  const SourceManager &SMng) {
185
186   const Stmt* S = 0;
187   if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
188     const CFGBlock *BSrc = BE->getSrc();
189     S = BSrc->getTerminatorCondition();
190   }
191   else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
192     S = PS->getStmt();
193   }
194
195   return PathDiagnosticLocation(S, SMng, P.getLocationContext());
196
197   if (!S)
198     return PathDiagnosticLocation();
199 }
200
201 PathDiagnosticLocation
202   PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
203                                           const SourceManager &SM) {
204   assert(N && "Cannot create a location with a null node.");
205
206   const ExplodedNode *NI = N;
207
208   while (NI) {
209     ProgramPoint P = NI->getLocation();
210     const LocationContext *LC = P.getLocationContext();
211     if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
212       return PathDiagnosticLocation(PS->getStmt(), SM, LC);
213     else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
214       const Stmt *Term = BE->getSrc()->getTerminator();
215       assert(Term);
216       return PathDiagnosticLocation(Term, SM, LC);
217     }
218     NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
219   }
220
221   return createDeclEnd(N->getLocationContext(), SM);
222 }
223
224 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
225                                            const PathDiagnosticLocation &PDL) {
226   FullSourceLoc L = PDL.asLocation();
227   return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
228 }
229
230 FullSourceLoc
231   PathDiagnosticLocation::genLocation(SourceLocation L,
232                                       LocationOrAnalysisContext LAC) const {
233   assert(isValid());
234   // Note that we want a 'switch' here so that the compiler can warn us in
235   // case we add more cases.
236   switch (K) {
237     case SingleLocK:
238     case RangeK:
239       break;
240     case StmtK:
241       return FullSourceLoc(getValidSourceLocation(S, LAC),
242                            const_cast<SourceManager&>(*SM));
243     case DeclK:
244       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
245   }
246
247   return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
248 }
249
250 PathDiagnosticRange
251   PathDiagnosticLocation::genRange(LocationOrAnalysisContext LAC) const {
252   assert(isValid());
253   // Note that we want a 'switch' here so that the compiler can warn us in
254   // case we add more cases.
255   switch (K) {
256     case SingleLocK:
257       return PathDiagnosticRange(SourceRange(Loc,Loc), true);
258     case RangeK:
259       break;
260     case StmtK: {
261       const Stmt *S = asStmt();
262       switch (S->getStmtClass()) {
263         default:
264           break;
265         case Stmt::DeclStmtClass: {
266           const DeclStmt *DS = cast<DeclStmt>(S);
267           if (DS->isSingleDecl()) {
268             // Should always be the case, but we'll be defensive.
269             return SourceRange(DS->getLocStart(),
270                                DS->getSingleDecl()->getLocation());
271           }
272           break;
273         }
274           // FIXME: Provide better range information for different
275           //  terminators.
276         case Stmt::IfStmtClass:
277         case Stmt::WhileStmtClass:
278         case Stmt::DoStmtClass:
279         case Stmt::ForStmtClass:
280         case Stmt::ChooseExprClass:
281         case Stmt::IndirectGotoStmtClass:
282         case Stmt::SwitchStmtClass:
283         case Stmt::BinaryConditionalOperatorClass:
284         case Stmt::ConditionalOperatorClass:
285         case Stmt::ObjCForCollectionStmtClass: {
286           SourceLocation L = getValidSourceLocation(S, LAC);
287           return SourceRange(L, L);
288         }
289       }
290       SourceRange R = S->getSourceRange();
291       if (R.isValid())
292         return R;
293       break;  
294     }
295     case DeclK:
296       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
297         return MD->getSourceRange();
298       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
299         if (Stmt *Body = FD->getBody())
300           return Body->getSourceRange();
301       }
302       else {
303         SourceLocation L = D->getLocation();
304         return PathDiagnosticRange(SourceRange(L, L), true);
305       }
306   }
307
308   return SourceRange(Loc,Loc);
309 }
310
311 void PathDiagnosticLocation::flatten() {
312   if (K == StmtK) {
313     K = RangeK;
314     S = 0;
315     D = 0;
316   }
317   else if (K == DeclK) {
318     K = SingleLocK;
319     S = 0;
320     D = 0;
321   }
322 }
323
324 //===----------------------------------------------------------------------===//
325 // FoldingSet profiling methods.
326 //===----------------------------------------------------------------------===//
327
328 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
329   ID.AddInteger(Range.getBegin().getRawEncoding());
330   ID.AddInteger(Range.getEnd().getRawEncoding());
331   ID.AddInteger(Loc.getRawEncoding());
332   return;
333 }
334
335 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
336   ID.AddInteger((unsigned) getKind());
337   ID.AddString(str);
338   // FIXME: Add profiling support for code hints.
339   ID.AddInteger((unsigned) getDisplayHint());
340   for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
341     ID.AddInteger(I->getBegin().getRawEncoding());
342     ID.AddInteger(I->getEnd().getRawEncoding());
343   }  
344 }
345
346 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
347   PathDiagnosticPiece::Profile(ID);
348   ID.Add(Pos);
349 }
350
351 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
352   PathDiagnosticPiece::Profile(ID);
353   for (const_iterator I = begin(), E = end(); I != E; ++I)
354     ID.Add(*I);
355 }
356
357 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
358   PathDiagnosticSpotPiece::Profile(ID);
359   for (const_iterator I = begin(), E = end(); I != E; ++I)
360     ID.Add(**I);
361 }
362
363 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
364   ID.AddInteger(Size);
365   ID.AddString(BugType);
366   ID.AddString(Desc);
367   ID.AddString(Category);
368   for (const_iterator I = begin(), E = end(); I != E; ++I)
369     ID.Add(*I);
370   
371   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
372     ID.AddString(*I);
373 }