blob: cf05a7df67f342ce925729b45616ecd8f37284e1 [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)) {
Argyrios Kyrtzidis082a6252010-07-07 12:24:14 +0000184 if (Stmt *Body = FD->getBody())
185 return Body->getSourceRange();
Douglas Gregor72971342009-04-18 00:02:19 +0000186 }
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000187 else {
188 SourceLocation L = D->getLocation();
Ted Kremenek4c5fcd92009-04-22 22:26:10 +0000189 return PathDiagnosticRange(SourceRange(L, L), true);
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000190 }
Ted Kremenekbecf8882009-03-26 21:48:17 +0000191 }
Mike Stump1eb44332009-09-09 15:08:12 +0000192
Ted Kremenekbecf8882009-03-26 21:48:17 +0000193 return R;
194}
195
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000196void PathDiagnosticLocation::flatten() {
197 if (K == StmtK) {
198 R = asRange();
199 K = RangeK;
200 S = 0;
201 D = 0;
202 }
203 else if (K == DeclK) {
204 SourceLocation L = D->getLocation();
205 R = SourceRange(L, L);
206 K = SingleLocK;
207 S = 0;
208 D = 0;
209 }
210}
211
Ted Kremenekdb8338a2009-09-18 22:33:39 +0000212//===----------------------------------------------------------------------===//
213// FoldingSet profiling methods.
214//===----------------------------------------------------------------------===//
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000215
Ted Kremenekdb8338a2009-09-18 22:33:39 +0000216void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
217 ID.AddInteger((unsigned) K);
218 switch (K) {
219 case RangeK:
220 ID.AddInteger(R.getBegin().getRawEncoding());
221 ID.AddInteger(R.getEnd().getRawEncoding());
222 break;
223 case SingleLocK:
224 ID.AddInteger(R.getBegin().getRawEncoding());
225 break;
226 case StmtK:
227 ID.Add(S);
228 break;
229 case DeclK:
230 ID.Add(D);
231 break;
232 }
233 return;
234}
235
236void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
237 ID.AddInteger((unsigned) getKind());
238 ID.AddString(str);
239 // FIXME: Add profiling support for code hints.
240 ID.AddInteger((unsigned) getDisplayHint());
241 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
242 ID.AddInteger(I->getBegin().getRawEncoding());
243 ID.AddInteger(I->getEnd().getRawEncoding());
244 }
245}
246
247void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
248 PathDiagnosticPiece::Profile(ID);
249 ID.Add(Pos);
250}
251
252void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
253 PathDiagnosticPiece::Profile(ID);
254 for (const_iterator I = begin(), E = end(); I != E; ++I)
255 ID.Add(*I);
256}
257
258void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
259 PathDiagnosticSpotPiece::Profile(ID);
260 for (const_iterator I = begin(), E = end(); I != E; ++I)
261 ID.Add(**I);
262}
263
264void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
265 ID.AddInteger(Size);
266 ID.AddString(BugType);
267 ID.AddString(Desc);
268 ID.AddString(Category);
269 for (const_iterator I = begin(), E = end(); I != E; ++I)
270 ID.Add(*I);
271
272 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
273 ID.AddString(*I);
274}