blob: 6e6c7496f1d2a9789b5c9682ca11c20862389b28 [file] [log] [blame]
Ted Kremenekd3abcdf2008-03-27 03:49:32 +00001//===--- 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
Ted Kremenek6b676302010-01-25 17:10:22 +000014#include "clang/Checker/BugReporter/PathDiagnostic.h"
Ted Kremenek97b40032009-03-26 21:39:39 +000015#include "clang/AST/Expr.h"
Ted Kremenekfea5f5a2009-04-06 22:33:35 +000016#include "clang/AST/Decl.h"
17#include "clang/AST/DeclObjC.h"
Sebastian Redld3a413d2009-04-26 20:35:05 +000018#include "clang/AST/StmtCXX.h"
Chris Lattnerf4c83962008-11-19 06:51:40 +000019#include "llvm/ADT/SmallString.h"
Ted Kremenek0e5c8d42009-03-10 05:16:17 +000020#include "llvm/Support/Casting.h"
Ted Kremenek11401862009-06-26 00:43:22 +000021
Ted Kremenekd3abcdf2008-03-27 03:49:32 +000022using namespace clang;
Ted Kremenek0e5c8d42009-03-10 05:16:17 +000023using llvm::dyn_cast;
24using llvm::isa;
25
26bool PathDiagnosticMacroPiece::containsEvent() const {
27 for (const_iterator I = begin(), E = end(); I!=E; ++I) {
28 if (isa<PathDiagnosticEventPiece>(*I))
29 return true;
Mike Stump1eb44332009-09-09 15:08:12 +000030
Ted Kremenek0e5c8d42009-03-10 05:16:17 +000031 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
32 if (MP->containsEvent())
33 return true;
34 }
35
36 return false;
37}
Ted Kremenek8af29752009-02-26 21:30:32 +000038
Benjamin Kramerd8e494f2009-12-11 21:09:27 +000039static llvm::StringRef StripTrailingDots(llvm::StringRef s) {
40 for (llvm::StringRef::size_type i = s.size(); i != 0; --i)
41 if (s[i - 1] != '.')
42 return s.substr(0, i);
43 return "";
Ted Kremenek8af29752009-02-26 21:30:32 +000044}
45
Benjamin Kramerd8e494f2009-12-11 21:09:27 +000046PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s,
Ted Kremeneke3ce2652009-03-02 19:39:50 +000047 Kind k, DisplayHint hint)
Benjamin Kramerd8e494f2009-12-11 21:09:27 +000048 : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
Ted Kremenek48504512009-03-06 07:53:30 +000049
Ted Kremenek1f9bd0f2009-03-26 21:21:35 +000050PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
51 : kind(k), Hint(hint) {}
Ted Kremenek082cb8d2009-03-12 18:41:53 +000052
Ted Kremenek4e063872009-03-06 22:10:49 +000053PathDiagnosticPiece::~PathDiagnosticPiece() {}
Ted Kremenek1fbfd5b2009-03-06 23:58:11 +000054PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
55PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
Ted Kremenek4e063872009-03-06 22:10:49 +000056
57PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
58 for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
59}
60
Ted Kremenek48504512009-03-06 07:53:30 +000061PathDiagnostic::PathDiagnostic() : Size(0) {}
Ted Kremenek8af29752009-02-26 21:30:32 +000062
Ted Kremenekd3abcdf2008-03-27 03:49:32 +000063PathDiagnostic::~PathDiagnostic() {
64 for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
65}
66
Ted Kremenek0e5c8d42009-03-10 05:16:17 +000067void PathDiagnostic::resetPath(bool deletePieces) {
68 Size = 0;
69
70 if (deletePieces)
71 for (iterator I=begin(), E=end(); I!=E; ++I)
72 delete &*I;
Mike Stump1eb44332009-09-09 15:08:12 +000073
Ted Kremenek0e5c8d42009-03-10 05:16:17 +000074 path.clear();
75}
76
Ted Kremeneka127cca2009-03-06 07:08:50 +000077
Benjamin Kramerd8e494f2009-12-11 21:09:27 +000078PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
79 llvm::StringRef category)
Ted Kremenek48504512009-03-06 07:53:30 +000080 : Size(0),
Benjamin Kramerd8e494f2009-12-11 21:09:27 +000081 BugType(StripTrailingDots(bugtype)),
82 Desc(StripTrailingDots(desc)),
83 Category(StripTrailingDots(category)) {}
Ted Kremeneka127cca2009-03-06 07:08:50 +000084
Chris Lattner0a14eee2008-11-18 07:04:44 +000085void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
86 const DiagnosticInfo &Info) {
Mike Stump1eb44332009-09-09 15:08:12 +000087
Ted Kremenekd3abcdf2008-03-27 03:49:32 +000088 // Create a PathDiagnostic with a single piece.
Mike Stump1eb44332009-09-09 15:08:12 +000089
Ted Kremenek55851142008-04-22 16:15:03 +000090 PathDiagnostic* D = new PathDiagnostic();
Mike Stump1eb44332009-09-09 15:08:12 +000091
Chris Lattnere837f932008-11-18 04:44:58 +000092 const char *LevelStr;
Ted Kremenek120187d2008-03-27 06:16:40 +000093 switch (DiagLevel) {
Mike Stumpe87f5c12009-02-07 03:46:08 +000094 default:
Chris Lattner41327582009-02-06 03:57:44 +000095 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
Chris Lattnere837f932008-11-18 04:44:58 +000096 case Diagnostic::Note: LevelStr = "note: "; break;
97 case Diagnostic::Warning: LevelStr = "warning: "; break;
98 case Diagnostic::Error: LevelStr = "error: "; break;
Chris Lattner41327582009-02-06 03:57:44 +000099 case Diagnostic::Fatal: LevelStr = "fatal error: "; break;
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000100 }
Ted Kremenek120187d2008-03-27 06:16:40 +0000101
Chris Lattnerf4c83962008-11-19 06:51:40 +0000102 llvm::SmallString<100> StrC;
103 StrC += LevelStr;
104 Info.FormatDiagnostic(StrC);
Mike Stump1eb44332009-09-09 15:08:12 +0000105
Chris Lattner0a14eee2008-11-18 07:04:44 +0000106 PathDiagnosticPiece *P =
Benjamin Kramerd8e494f2009-12-11 21:09:27 +0000107 new PathDiagnosticEventPiece(Info.getLocation(), StrC.str());
Mike Stump1eb44332009-09-09 15:08:12 +0000108
Chris Lattner0a14eee2008-11-18 07:04:44 +0000109 for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
Chris Lattner0a76aae2010-06-18 22:45:06 +0000110 P->addRange(Info.getRange(i).getAsRange());
Douglas Gregor849b2432010-03-31 17:46:05 +0000111 for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
112 P->addFixItHint(Info.getFixItHint(i));
Ted Kremenek55851142008-04-22 16:15:03 +0000113 D->push_front(P);
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000114
Mike Stump1eb44332009-09-09 15:08:12 +0000115 HandlePathDiagnostic(D);
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000116}
Ted Kremenek97b40032009-03-26 21:39:39 +0000117
118//===----------------------------------------------------------------------===//
119// PathDiagnosticLocation methods.
120//===----------------------------------------------------------------------===//
121
122FullSourceLoc PathDiagnosticLocation::asLocation() const {
Ted Kremenek5fb5dfb2009-04-01 06:13:56 +0000123 assert(isValid());
Ted Kremenekb7737022009-03-26 21:42:51 +0000124 // Note that we want a 'switch' here so that the compiler can warn us in
125 // case we add more cases.
Ted Kremenek97b40032009-03-26 21:39:39 +0000126 switch (K) {
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000127 case SingleLocK:
128 case RangeK:
Ted Kremeneka5465002009-03-26 21:42:00 +0000129 break;
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000130 case StmtK:
Ted Kremenek6f002042009-03-26 23:12:02 +0000131 return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000132 case DeclK:
133 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
Ted Kremenek97b40032009-03-26 21:39:39 +0000134 }
Mike Stump1eb44332009-09-09 15:08:12 +0000135
Ted Kremenek6f002042009-03-26 23:12:02 +0000136 return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
Ted Kremenek97b40032009-03-26 21:39:39 +0000137}
Ted Kremenekbecf8882009-03-26 21:48:17 +0000138
Ted Kremenek4c5fcd92009-04-22 22:26:10 +0000139PathDiagnosticRange PathDiagnosticLocation::asRange() const {
Ted Kremenek5fb5dfb2009-04-01 06:13:56 +0000140 assert(isValid());
Ted Kremenekbecf8882009-03-26 21:48:17 +0000141 // Note that we want a 'switch' here so that the compiler can warn us in
142 // case we add more cases.
143 switch (K) {
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000144 case SingleLocK:
Ted Kremenek4c5fcd92009-04-22 22:26:10 +0000145 return PathDiagnosticRange(R, true);
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000146 case RangeK:
Ted Kremenekbecf8882009-03-26 21:48:17 +0000147 break;
Ted Kremenek8f332902009-04-22 18:03:00 +0000148 case StmtK: {
149 const Stmt *S = asStmt();
150 switch (S->getStmtClass()) {
151 default:
152 break;
Ted Kremenek1e63c292009-05-15 02:05:25 +0000153 case Stmt::DeclStmtClass: {
154 const DeclStmt *DS = cast<DeclStmt>(S);
155 if (DS->isSingleDecl()) {
156 // Should always be the case, but we'll be defensive.
157 return SourceRange(DS->getLocStart(),
Mike Stump1eb44332009-09-09 15:08:12 +0000158 DS->getSingleDecl()->getLocation());
Ted Kremenek1e63c292009-05-15 02:05:25 +0000159 }
160 break;
161 }
Ted Kremenek8f332902009-04-22 18:03:00 +0000162 // FIXME: Provide better range information for different
163 // terminators.
164 case Stmt::IfStmtClass:
165 case Stmt::WhileStmtClass:
166 case Stmt::DoStmtClass:
167 case Stmt::ForStmtClass:
168 case Stmt::ChooseExprClass:
169 case Stmt::IndirectGotoStmtClass:
170 case Stmt::SwitchStmtClass:
171 case Stmt::ConditionalOperatorClass:
172 case Stmt::ObjCForCollectionStmtClass: {
173 SourceLocation L = S->getLocStart();
174 return SourceRange(L, L);
175 }
176 }
Mike Stump1eb44332009-09-09 15:08:12 +0000177
Ted Kremenekbecf8882009-03-26 21:48:17 +0000178 return S->getSourceRange();
Ted Kremenek8f332902009-04-22 18:03:00 +0000179 }
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000180 case DeclK:
181 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
182 return MD->getSourceRange();
Douglas Gregor72971342009-04-18 00:02:19 +0000183 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
184 // FIXME: We would like to always get the function body, even
185 // when it needs to be de-serialized, but getting the
186 // ASTContext here requires significant changes.
Douglas Gregoraf3280f2009-09-12 00:08:48 +0000187 if (Stmt *Body = FD->getBody()) {
Sebastian Redld3a413d2009-04-26 20:35:05 +0000188 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body))
189 return CS->getSourceRange();
190 else
191 return cast<CXXTryStmt>(Body)->getSourceRange();
192 }
Douglas Gregor72971342009-04-18 00:02:19 +0000193 }
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000194 else {
195 SourceLocation L = D->getLocation();
Ted Kremenek4c5fcd92009-04-22 22:26:10 +0000196 return PathDiagnosticRange(SourceRange(L, L), true);
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000197 }
Ted Kremenekbecf8882009-03-26 21:48:17 +0000198 }
Mike Stump1eb44332009-09-09 15:08:12 +0000199
Ted Kremenekbecf8882009-03-26 21:48:17 +0000200 return R;
201}
202
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000203void PathDiagnosticLocation::flatten() {
204 if (K == StmtK) {
205 R = asRange();
206 K = RangeK;
207 S = 0;
208 D = 0;
209 }
210 else if (K == DeclK) {
211 SourceLocation L = D->getLocation();
212 R = SourceRange(L, L);
213 K = SingleLocK;
214 S = 0;
215 D = 0;
216 }
217}
218
Ted Kremenekdb8338a2009-09-18 22:33:39 +0000219//===----------------------------------------------------------------------===//
220// FoldingSet profiling methods.
221//===----------------------------------------------------------------------===//
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000222
Ted Kremenekdb8338a2009-09-18 22:33:39 +0000223void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
224 ID.AddInteger((unsigned) K);
225 switch (K) {
226 case RangeK:
227 ID.AddInteger(R.getBegin().getRawEncoding());
228 ID.AddInteger(R.getEnd().getRawEncoding());
229 break;
230 case SingleLocK:
231 ID.AddInteger(R.getBegin().getRawEncoding());
232 break;
233 case StmtK:
234 ID.Add(S);
235 break;
236 case DeclK:
237 ID.Add(D);
238 break;
239 }
240 return;
241}
242
243void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
244 ID.AddInteger((unsigned) getKind());
245 ID.AddString(str);
246 // FIXME: Add profiling support for code hints.
247 ID.AddInteger((unsigned) getDisplayHint());
248 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
249 ID.AddInteger(I->getBegin().getRawEncoding());
250 ID.AddInteger(I->getEnd().getRawEncoding());
251 }
252}
253
254void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
255 PathDiagnosticPiece::Profile(ID);
256 ID.Add(Pos);
257}
258
259void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
260 PathDiagnosticPiece::Profile(ID);
261 for (const_iterator I = begin(), E = end(); I != E; ++I)
262 ID.Add(*I);
263}
264
265void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
266 PathDiagnosticSpotPiece::Profile(ID);
267 for (const_iterator I = begin(), E = end(); I != E; ++I)
268 ID.Add(**I);
269}
270
271void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
272 ID.AddInteger(Size);
273 ID.AddString(BugType);
274 ID.AddString(Desc);
275 ID.AddString(Category);
276 for (const_iterator I = begin(), E = end(); I != E; ++I)
277 ID.Add(*I);
278
279 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
280 ID.AddString(*I);
281}