blob: 1d00727d0a2acee2bf1e0065a31f02a3bf7b296a [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
14#include "clang/Analysis/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"
Chris Lattnerf4c83962008-11-19 06:51:40 +000018#include "llvm/ADT/SmallString.h"
Ted Kremenek0e5c8d42009-03-10 05:16:17 +000019#include "llvm/Support/Casting.h"
Ted Kremenek120187d2008-03-27 06:16:40 +000020#include <sstream>
Ted Kremenekd3abcdf2008-03-27 03:49:32 +000021using namespace clang;
Ted Kremenek0e5c8d42009-03-10 05:16:17 +000022using llvm::dyn_cast;
23using llvm::isa;
24
25bool PathDiagnosticMacroPiece::containsEvent() const {
26 for (const_iterator I = begin(), E = end(); I!=E; ++I) {
27 if (isa<PathDiagnosticEventPiece>(*I))
28 return true;
29
30 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
31 if (MP->containsEvent())
32 return true;
33 }
34
35 return false;
36}
Ted Kremenek8af29752009-02-26 21:30:32 +000037
38static size_t GetNumCharsToLastNonPeriod(const char *s) {
39 const char *start = s;
40 const char *lastNonPeriod = 0;
41
42 for ( ; *s != '\0' ; ++s)
43 if (*s != '.') lastNonPeriod = s;
Ted Kremenekd3abcdf2008-03-27 03:49:32 +000044
Ted Kremenek8af29752009-02-26 21:30:32 +000045 if (!lastNonPeriod)
46 return 0;
47
48 return (lastNonPeriod - start) + 1;
49}
50
51static inline size_t GetNumCharsToLastNonPeriod(const std::string &s) {
52 return s.empty () ? 0 : GetNumCharsToLastNonPeriod(&s[0]);
53}
54
Ted Kremenek1f9bd0f2009-03-26 21:21:35 +000055PathDiagnosticPiece::PathDiagnosticPiece(const std::string& s,
Ted Kremeneke3ce2652009-03-02 19:39:50 +000056 Kind k, DisplayHint hint)
Ted Kremenek1f9bd0f2009-03-26 21:21:35 +000057 : str(s, 0, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
Ted Kremenek8af29752009-02-26 21:30:32 +000058
Ted Kremenek1f9bd0f2009-03-26 21:21:35 +000059PathDiagnosticPiece::PathDiagnosticPiece(const char* s, Kind k,
Ted Kremenek8af29752009-02-26 21:30:32 +000060 DisplayHint hint)
Ted Kremenek1f9bd0f2009-03-26 21:21:35 +000061 : str(s, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
Ted Kremenek48504512009-03-06 07:53:30 +000062
Ted Kremenek1f9bd0f2009-03-26 21:21:35 +000063PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
64 : kind(k), Hint(hint) {}
Ted Kremenek082cb8d2009-03-12 18:41:53 +000065
Ted Kremenek4e063872009-03-06 22:10:49 +000066PathDiagnosticPiece::~PathDiagnosticPiece() {}
Ted Kremenek1fbfd5b2009-03-06 23:58:11 +000067PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
68PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
Ted Kremenek4e063872009-03-06 22:10:49 +000069
70PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
71 for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
72}
73
Ted Kremenek48504512009-03-06 07:53:30 +000074PathDiagnostic::PathDiagnostic() : Size(0) {}
Ted Kremenek8af29752009-02-26 21:30:32 +000075
Ted Kremenekd3abcdf2008-03-27 03:49:32 +000076PathDiagnostic::~PathDiagnostic() {
77 for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
78}
79
Ted Kremenek0e5c8d42009-03-10 05:16:17 +000080void PathDiagnostic::resetPath(bool deletePieces) {
81 Size = 0;
82
83 if (deletePieces)
84 for (iterator I=begin(), E=end(); I!=E; ++I)
85 delete &*I;
86
87 path.clear();
88}
89
Ted Kremeneka127cca2009-03-06 07:08:50 +000090
91PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc,
92 const char* category)
Ted Kremenek48504512009-03-06 07:53:30 +000093 : Size(0),
94 BugType(bugtype, GetNumCharsToLastNonPeriod(bugtype)),
Ted Kremeneka127cca2009-03-06 07:08:50 +000095 Desc(desc, GetNumCharsToLastNonPeriod(desc)),
96 Category(category, GetNumCharsToLastNonPeriod(category)) {}
97
98PathDiagnostic::PathDiagnostic(const std::string& bugtype,
99 const std::string& desc,
100 const std::string& category)
Ted Kremenek48504512009-03-06 07:53:30 +0000101 : Size(0),
102 BugType(bugtype, 0, GetNumCharsToLastNonPeriod(bugtype)),
Ted Kremeneka127cca2009-03-06 07:08:50 +0000103 Desc(desc, 0, GetNumCharsToLastNonPeriod(desc)),
104 Category(category, 0, GetNumCharsToLastNonPeriod(category)) {}
105
Chris Lattner0a14eee2008-11-18 07:04:44 +0000106void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
107 const DiagnosticInfo &Info) {
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000108
109 // Create a PathDiagnostic with a single piece.
110
Ted Kremenek55851142008-04-22 16:15:03 +0000111 PathDiagnostic* D = new PathDiagnostic();
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000112
Chris Lattnere837f932008-11-18 04:44:58 +0000113 const char *LevelStr;
Ted Kremenek120187d2008-03-27 06:16:40 +0000114 switch (DiagLevel) {
Mike Stumpe87f5c12009-02-07 03:46:08 +0000115 default:
Chris Lattner41327582009-02-06 03:57:44 +0000116 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
Chris Lattnere837f932008-11-18 04:44:58 +0000117 case Diagnostic::Note: LevelStr = "note: "; break;
118 case Diagnostic::Warning: LevelStr = "warning: "; break;
119 case Diagnostic::Error: LevelStr = "error: "; break;
Chris Lattner41327582009-02-06 03:57:44 +0000120 case Diagnostic::Fatal: LevelStr = "fatal error: "; break;
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000121 }
Ted Kremenek120187d2008-03-27 06:16:40 +0000122
Chris Lattnerf4c83962008-11-19 06:51:40 +0000123 llvm::SmallString<100> StrC;
124 StrC += LevelStr;
125 Info.FormatDiagnostic(StrC);
Ted Kremenek120187d2008-03-27 06:16:40 +0000126
Chris Lattner0a14eee2008-11-18 07:04:44 +0000127 PathDiagnosticPiece *P =
Ted Kremenek1fbfd5b2009-03-06 23:58:11 +0000128 new PathDiagnosticEventPiece(Info.getLocation(),
Chris Lattnerf4c83962008-11-19 06:51:40 +0000129 std::string(StrC.begin(), StrC.end()));
Ted Kremenek120187d2008-03-27 06:16:40 +0000130
Chris Lattner0a14eee2008-11-18 07:04:44 +0000131 for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
132 P->addRange(Info.getRange(i));
Douglas Gregor4b2d3f72009-02-26 21:00:50 +0000133 for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i)
134 P->addCodeModificationHint(Info.getCodeModificationHint(i));
Ted Kremenek55851142008-04-22 16:15:03 +0000135 D->push_front(P);
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000136
Ted Kremenek120187d2008-03-27 06:16:40 +0000137 HandlePathDiagnostic(D);
Ted Kremenekd3abcdf2008-03-27 03:49:32 +0000138}
Ted Kremenek97b40032009-03-26 21:39:39 +0000139
140//===----------------------------------------------------------------------===//
141// PathDiagnosticLocation methods.
142//===----------------------------------------------------------------------===//
143
144FullSourceLoc PathDiagnosticLocation::asLocation() const {
Ted Kremenek5fb5dfb2009-04-01 06:13:56 +0000145 assert(isValid());
Ted Kremenekb7737022009-03-26 21:42:51 +0000146 // Note that we want a 'switch' here so that the compiler can warn us in
147 // case we add more cases.
Ted Kremenek97b40032009-03-26 21:39:39 +0000148 switch (K) {
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000149 case SingleLocK:
150 case RangeK:
Ted Kremeneka5465002009-03-26 21:42:00 +0000151 break;
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000152 case StmtK:
Ted Kremenek6f002042009-03-26 23:12:02 +0000153 return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000154 case DeclK:
155 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
Ted Kremenek97b40032009-03-26 21:39:39 +0000156 }
Ted Kremeneka5465002009-03-26 21:42:00 +0000157
Ted Kremenek6f002042009-03-26 23:12:02 +0000158 return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
Ted Kremenek97b40032009-03-26 21:39:39 +0000159}
Ted Kremenekbecf8882009-03-26 21:48:17 +0000160
161SourceRange PathDiagnosticLocation::asRange() const {
Ted Kremenek5fb5dfb2009-04-01 06:13:56 +0000162 assert(isValid());
Ted Kremenekbecf8882009-03-26 21:48:17 +0000163 // Note that we want a 'switch' here so that the compiler can warn us in
164 // case we add more cases.
165 switch (K) {
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000166 case SingleLocK:
167 case RangeK:
Ted Kremenekbecf8882009-03-26 21:48:17 +0000168 break;
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000169 case StmtK:
Ted Kremenekbecf8882009-03-26 21:48:17 +0000170 return S->getSourceRange();
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000171 case DeclK:
172 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
173 return MD->getSourceRange();
Douglas Gregor72971342009-04-18 00:02:19 +0000174 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
175 // FIXME: We would like to always get the function body, even
176 // when it needs to be de-serialized, but getting the
177 // ASTContext here requires significant changes.
178 if (CompoundStmt *Body = FD->getBodyIfAvailable())
179 return Body->getSourceRange();
180 }
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000181 else {
182 SourceLocation L = D->getLocation();
183 return SourceRange(L, L);
184 }
Ted Kremenekbecf8882009-03-26 21:48:17 +0000185 }
186
187 return R;
188}
189
Ted Kremenekfea5f5a2009-04-06 22:33:35 +0000190void PathDiagnosticLocation::flatten() {
191 if (K == StmtK) {
192 R = asRange();
193 K = RangeK;
194 S = 0;
195 D = 0;
196 }
197 else if (K == DeclK) {
198 SourceLocation L = D->getLocation();
199 R = SourceRange(L, L);
200 K = SingleLocK;
201 S = 0;
202 D = 0;
203 }
204}
205
206