blob: 0f0dddc6d7819fe847272024f53f8cd1ca51d6ea [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) {
Argyrios Kyrtzidisf2224d82010-11-18 20:06:46 +000087 // Default implementation (Warnings/errors count).
88 DiagnosticClient::HandleDiagnostic(DiagLevel, Info);
Mike Stump1eb44332009-09-09 15:08:12 +000089
Ted Kremenekd3abcdf2008-03-27 03:49:32 +000090 // Create a PathDiagnostic with a single piece.
Mike Stump1eb44332009-09-09 15:08:12 +000091
Ted Kremenek55851142008-04-22 16:15:03 +000092 PathDiagnostic* D = new PathDiagnostic();
Mike Stump1eb44332009-09-09 15:08:12 +000093
Chris Lattnere837f932008-11-18 04:44:58 +000094 const char *LevelStr;
Ted Kremenek120187d2008-03-27 06:16:40 +000095 switch (DiagLevel) {
Mike Stumpe87f5c12009-02-07 03:46:08 +000096 default:
Chris Lattner41327582009-02-06 03:57:44 +000097 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
Chris Lattnere837f932008-11-18 04:44:58 +000098 case Diagnostic::Note: LevelStr = "note: "; break;
99 case Diagnostic::Warning: LevelStr = "warning: "; break;
100 case Diagnostic::Error: LevelStr = "error: "; break;
Chris Lattner41327582009-02-06 03:57:44 +0000101 case Diagnostic::Fatal: LevelStr = "fatal error: "; break;
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000102 }
Ted Kremenek120187d2008-03-27 06:16:40 +0000103
Chris Lattnerf4c83962008-11-19 06:51:40 +0000104 llvm::SmallString<100> StrC;
105 StrC += LevelStr;
106 Info.FormatDiagnostic(StrC);
Mike Stump1eb44332009-09-09 15:08:12 +0000107
Chris Lattner0a14eee2008-11-18 07:04:44 +0000108 PathDiagnosticPiece *P =
Argyrios Kyrtzidis33e4e702010-11-18 20:06:41 +0000109 new PathDiagnosticEventPiece(FullSourceLoc(Info.getLocation(),
110 Info.getSourceManager()),
111 StrC.str());
Mike Stump1eb44332009-09-09 15:08:12 +0000112
Chris Lattner0a14eee2008-11-18 07:04:44 +0000113 for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
Chris Lattner0a76aae2010-06-18 22:45:06 +0000114 P->addRange(Info.getRange(i).getAsRange());
Douglas Gregor849b2432010-03-31 17:46:05 +0000115 for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
116 P->addFixItHint(Info.getFixItHint(i));
Ted Kremenek55851142008-04-22 16:15:03 +0000117 D->push_front(P);
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000118
Mike Stump1eb44332009-09-09 15:08:12 +0000119 HandlePathDiagnostic(D);
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000120}
Ted Kremenek97b40032009-03-26 21:39:39 +0000121
122//===----------------------------------------------------------------------===//
123// PathDiagnosticLocation methods.
124//===----------------------------------------------------------------------===//
125
126FullSourceLoc PathDiagnosticLocation::asLocation() const {
Ted Kremenek5fb5dfb2009-04-01 06:13:56 +0000127 assert(isValid());
Ted Kremenekb7737022009-03-26 21:42:51 +0000128 // Note that we want a 'switch' here so that the compiler can warn us in
129 // case we add more cases.
Ted Kremenek97b40032009-03-26 21:39:39 +0000130 switch (K) {
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000131 case SingleLocK:
132 case RangeK:
Ted Kremeneka5465002009-03-26 21:42:00 +0000133 break;
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000134 case StmtK:
Ted Kremenek6f002042009-03-26 23:12:02 +0000135 return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000136 case DeclK:
137 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
Ted Kremenek97b40032009-03-26 21:39:39 +0000138 }
Mike Stump1eb44332009-09-09 15:08:12 +0000139
Ted Kremenek6f002042009-03-26 23:12:02 +0000140 return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
Ted Kremenek97b40032009-03-26 21:39:39 +0000141}
Ted Kremenekbecf8882009-03-26 21:48:17 +0000142
Ted Kremenek4c5fcd92009-04-22 22:26:10 +0000143PathDiagnosticRange PathDiagnosticLocation::asRange() const {
Ted Kremenek5fb5dfb2009-04-01 06:13:56 +0000144 assert(isValid());
Ted Kremenekbecf8882009-03-26 21:48:17 +0000145 // Note that we want a 'switch' here so that the compiler can warn us in
146 // case we add more cases.
147 switch (K) {
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000148 case SingleLocK:
Ted Kremenek4c5fcd92009-04-22 22:26:10 +0000149 return PathDiagnosticRange(R, true);
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000150 case RangeK:
Ted Kremenekbecf8882009-03-26 21:48:17 +0000151 break;
Ted Kremenek8f332902009-04-22 18:03:00 +0000152 case StmtK: {
153 const Stmt *S = asStmt();
154 switch (S->getStmtClass()) {
155 default:
156 break;
Ted Kremenek1e63c292009-05-15 02:05:25 +0000157 case Stmt::DeclStmtClass: {
158 const DeclStmt *DS = cast<DeclStmt>(S);
159 if (DS->isSingleDecl()) {
160 // Should always be the case, but we'll be defensive.
161 return SourceRange(DS->getLocStart(),
Mike Stump1eb44332009-09-09 15:08:12 +0000162 DS->getSingleDecl()->getLocation());
Ted Kremenek1e63c292009-05-15 02:05:25 +0000163 }
164 break;
165 }
Ted Kremenek8f332902009-04-22 18:03:00 +0000166 // FIXME: Provide better range information for different
167 // terminators.
168 case Stmt::IfStmtClass:
169 case Stmt::WhileStmtClass:
170 case Stmt::DoStmtClass:
171 case Stmt::ForStmtClass:
172 case Stmt::ChooseExprClass:
173 case Stmt::IndirectGotoStmtClass:
174 case Stmt::SwitchStmtClass:
175 case Stmt::ConditionalOperatorClass:
176 case Stmt::ObjCForCollectionStmtClass: {
177 SourceLocation L = S->getLocStart();
178 return SourceRange(L, L);
179 }
180 }
Mike Stump1eb44332009-09-09 15:08:12 +0000181
Ted Kremenekbecf8882009-03-26 21:48:17 +0000182 return S->getSourceRange();
Ted Kremenek8f332902009-04-22 18:03:00 +0000183 }
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000184 case DeclK:
185 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
186 return MD->getSourceRange();
Douglas Gregor72971342009-04-18 00:02:19 +0000187 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidis082a6252010-07-07 12:24:14 +0000188 if (Stmt *Body = FD->getBody())
189 return Body->getSourceRange();
Douglas Gregor72971342009-04-18 00:02:19 +0000190 }
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000191 else {
192 SourceLocation L = D->getLocation();
Ted Kremenek4c5fcd92009-04-22 22:26:10 +0000193 return PathDiagnosticRange(SourceRange(L, L), true);
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000194 }
Ted Kremenekbecf8882009-03-26 21:48:17 +0000195 }
Mike Stump1eb44332009-09-09 15:08:12 +0000196
Ted Kremenekbecf8882009-03-26 21:48:17 +0000197 return R;
198}
199
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000200void PathDiagnosticLocation::flatten() {
201 if (K == StmtK) {
202 R = asRange();
203 K = RangeK;
204 S = 0;
205 D = 0;
206 }
207 else if (K == DeclK) {
208 SourceLocation L = D->getLocation();
209 R = SourceRange(L, L);
210 K = SingleLocK;
211 S = 0;
212 D = 0;
213 }
214}
215
Ted Kremenekdb8338a2009-09-18 22:33:39 +0000216//===----------------------------------------------------------------------===//
217// FoldingSet profiling methods.
218//===----------------------------------------------------------------------===//
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000219
Ted Kremenekdb8338a2009-09-18 22:33:39 +0000220void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
221 ID.AddInteger((unsigned) K);
222 switch (K) {
223 case RangeK:
224 ID.AddInteger(R.getBegin().getRawEncoding());
225 ID.AddInteger(R.getEnd().getRawEncoding());
226 break;
227 case SingleLocK:
228 ID.AddInteger(R.getBegin().getRawEncoding());
229 break;
230 case StmtK:
231 ID.Add(S);
232 break;
233 case DeclK:
234 ID.Add(D);
235 break;
236 }
237 return;
238}
239
240void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
241 ID.AddInteger((unsigned) getKind());
242 ID.AddString(str);
243 // FIXME: Add profiling support for code hints.
244 ID.AddInteger((unsigned) getDisplayHint());
245 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
246 ID.AddInteger(I->getBegin().getRawEncoding());
247 ID.AddInteger(I->getEnd().getRawEncoding());
248 }
249}
250
251void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
252 PathDiagnosticPiece::Profile(ID);
253 ID.Add(Pos);
254}
255
256void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
257 PathDiagnosticPiece::Profile(ID);
258 for (const_iterator I = begin(), E = end(); I != E; ++I)
259 ID.Add(*I);
260}
261
262void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
263 PathDiagnosticSpotPiece::Profile(ID);
264 for (const_iterator I = begin(), E = end(); I != E; ++I)
265 ID.Add(**I);
266}
267
268void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
269 ID.AddInteger(Size);
270 ID.AddString(BugType);
271 ID.AddString(Desc);
272 ID.AddString(Category);
273 for (const_iterator I = begin(), E = end(); I != E; ++I)
274 ID.Add(*I);
275
276 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
277 ID.AddString(*I);
278}