[analyzer] Move the files in lib/StaticAnalyzer to lib/StaticAnalyzer/Core.
[clang.git] / lib / StaticAnalyzer / Core / PathDiagnostic.cpp
blobf05dec820d358e5d79bae93df887e6f64fca14fd
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.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
15 #include "clang/AST/Expr.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclObjC.h"
18 #include "clang/AST/StmtCXX.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/Support/Casting.h"
22 using namespace clang;
23 using namespace ento;
24 using llvm::dyn_cast;
25 using llvm::isa;
27 bool PathDiagnosticMacroPiece::containsEvent() const {
28 for (const_iterator I = begin(), E = end(); I!=E; ++I) {
29 if (isa<PathDiagnosticEventPiece>(*I))
30 return true;
32 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
33 if (MP->containsEvent())
34 return true;
37 return false;
40 static llvm::StringRef StripTrailingDots(llvm::StringRef s) {
41 for (llvm::StringRef::size_type i = s.size(); i != 0; --i)
42 if (s[i - 1] != '.')
43 return s.substr(0, i);
44 return "";
47 PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s,
48 Kind k, DisplayHint hint)
49 : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
51 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
52 : kind(k), Hint(hint) {}
54 PathDiagnosticPiece::~PathDiagnosticPiece() {}
55 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
56 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
58 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
59 for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
62 PathDiagnostic::PathDiagnostic() : Size(0) {}
64 PathDiagnostic::~PathDiagnostic() {
65 for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
68 void PathDiagnostic::resetPath(bool deletePieces) {
69 Size = 0;
71 if (deletePieces)
72 for (iterator I=begin(), E=end(); I!=E; ++I)
73 delete &*I;
75 path.clear();
79 PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
80 llvm::StringRef category)
81 : Size(0),
82 BugType(StripTrailingDots(bugtype)),
83 Desc(StripTrailingDots(desc)),
84 Category(StripTrailingDots(category)) {}
86 void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
87 const DiagnosticInfo &Info) {
88 // Default implementation (Warnings/errors count).
89 DiagnosticClient::HandleDiagnostic(DiagLevel, Info);
91 // Create a PathDiagnostic with a single piece.
93 PathDiagnostic* D = new PathDiagnostic();
95 const char *LevelStr;
96 switch (DiagLevel) {
97 default:
98 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
99 case Diagnostic::Note: LevelStr = "note: "; break;
100 case Diagnostic::Warning: LevelStr = "warning: "; break;
101 case Diagnostic::Error: LevelStr = "error: "; break;
102 case Diagnostic::Fatal: LevelStr = "fatal error: "; break;
105 llvm::SmallString<100> StrC;
106 StrC += LevelStr;
107 Info.FormatDiagnostic(StrC);
109 PathDiagnosticPiece *P =
110 new PathDiagnosticEventPiece(FullSourceLoc(Info.getLocation(),
111 Info.getSourceManager()),
112 StrC.str());
114 for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
115 P->addRange(Info.getRange(i).getAsRange());
116 for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
117 P->addFixItHint(Info.getFixItHint(i));
118 D->push_front(P);
120 HandlePathDiagnostic(D);
123 //===----------------------------------------------------------------------===//
124 // PathDiagnosticLocation methods.
125 //===----------------------------------------------------------------------===//
127 FullSourceLoc PathDiagnosticLocation::asLocation() const {
128 assert(isValid());
129 // Note that we want a 'switch' here so that the compiler can warn us in
130 // case we add more cases.
131 switch (K) {
132 case SingleLocK:
133 case RangeK:
134 break;
135 case StmtK:
136 return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
137 case DeclK:
138 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
141 return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
144 PathDiagnosticRange PathDiagnosticLocation::asRange() const {
145 assert(isValid());
146 // Note that we want a 'switch' here so that the compiler can warn us in
147 // case we add more cases.
148 switch (K) {
149 case SingleLocK:
150 return PathDiagnosticRange(R, true);
151 case RangeK:
152 break;
153 case StmtK: {
154 const Stmt *S = asStmt();
155 switch (S->getStmtClass()) {
156 default:
157 break;
158 case Stmt::DeclStmtClass: {
159 const DeclStmt *DS = cast<DeclStmt>(S);
160 if (DS->isSingleDecl()) {
161 // Should always be the case, but we'll be defensive.
162 return SourceRange(DS->getLocStart(),
163 DS->getSingleDecl()->getLocation());
165 break;
167 // FIXME: Provide better range information for different
168 // terminators.
169 case Stmt::IfStmtClass:
170 case Stmt::WhileStmtClass:
171 case Stmt::DoStmtClass:
172 case Stmt::ForStmtClass:
173 case Stmt::ChooseExprClass:
174 case Stmt::IndirectGotoStmtClass:
175 case Stmt::SwitchStmtClass:
176 case Stmt::ConditionalOperatorClass:
177 case Stmt::ObjCForCollectionStmtClass: {
178 SourceLocation L = S->getLocStart();
179 return SourceRange(L, L);
183 return S->getSourceRange();
185 case DeclK:
186 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
187 return MD->getSourceRange();
188 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
189 if (Stmt *Body = FD->getBody())
190 return Body->getSourceRange();
192 else {
193 SourceLocation L = D->getLocation();
194 return PathDiagnosticRange(SourceRange(L, L), true);
198 return R;
201 void PathDiagnosticLocation::flatten() {
202 if (K == StmtK) {
203 R = asRange();
204 K = RangeK;
205 S = 0;
206 D = 0;
208 else if (K == DeclK) {
209 SourceLocation L = D->getLocation();
210 R = SourceRange(L, L);
211 K = SingleLocK;
212 S = 0;
213 D = 0;
217 //===----------------------------------------------------------------------===//
218 // FoldingSet profiling methods.
219 //===----------------------------------------------------------------------===//
221 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
222 ID.AddInteger((unsigned) K);
223 switch (K) {
224 case RangeK:
225 ID.AddInteger(R.getBegin().getRawEncoding());
226 ID.AddInteger(R.getEnd().getRawEncoding());
227 break;
228 case SingleLocK:
229 ID.AddInteger(R.getBegin().getRawEncoding());
230 break;
231 case StmtK:
232 ID.Add(S);
233 break;
234 case DeclK:
235 ID.Add(D);
236 break;
238 return;
241 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
242 ID.AddInteger((unsigned) getKind());
243 ID.AddString(str);
244 // FIXME: Add profiling support for code hints.
245 ID.AddInteger((unsigned) getDisplayHint());
246 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
247 ID.AddInteger(I->getBegin().getRawEncoding());
248 ID.AddInteger(I->getEnd().getRawEncoding());
252 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
253 PathDiagnosticPiece::Profile(ID);
254 ID.Add(Pos);
257 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
258 PathDiagnosticPiece::Profile(ID);
259 for (const_iterator I = begin(), E = end(); I != E; ++I)
260 ID.Add(*I);
263 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
264 PathDiagnosticSpotPiece::Profile(ID);
265 for (const_iterator I = begin(), E = end(); I != E; ++I)
266 ID.Add(**I);
269 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
270 ID.AddInteger(Size);
271 ID.AddString(BugType);
272 ID.AddString(Desc);
273 ID.AddString(Category);
274 for (const_iterator I = begin(), E = end(); I != E; ++I)
275 ID.Add(*I);
277 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
278 ID.AddString(*I);