1 //===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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
;
27 bool PathDiagnosticMacroPiece::containsEvent() const {
28 for (const_iterator I
= begin(), E
= end(); I
!=E
; ++I
) {
29 if (isa
<PathDiagnosticEventPiece
>(*I
))
32 if (PathDiagnosticMacroPiece
*MP
= dyn_cast
<PathDiagnosticMacroPiece
>(*I
))
33 if (MP
->containsEvent())
40 static llvm::StringRef
StripTrailingDots(llvm::StringRef s
) {
41 for (llvm::StringRef::size_type i
= s
.size(); i
!= 0; --i
)
43 return s
.substr(0, i
);
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
) {
72 for (iterator I
=begin(), E
=end(); I
!=E
; ++I
)
79 PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype
, llvm::StringRef desc
,
80 llvm::StringRef category
)
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();
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
;
107 Info
.FormatDiagnostic(StrC
);
109 PathDiagnosticPiece
*P
=
110 new PathDiagnosticEventPiece(FullSourceLoc(Info
.getLocation(),
111 Info
.getSourceManager()),
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
));
120 HandlePathDiagnostic(D
);
123 //===----------------------------------------------------------------------===//
124 // PathDiagnosticLocation methods.
125 //===----------------------------------------------------------------------===//
127 FullSourceLoc
PathDiagnosticLocation::asLocation() const {
129 // Note that we want a 'switch' here so that the compiler can warn us in
130 // case we add more cases.
136 return FullSourceLoc(S
->getLocStart(), const_cast<SourceManager
&>(*SM
));
138 return FullSourceLoc(D
->getLocation(), const_cast<SourceManager
&>(*SM
));
141 return FullSourceLoc(R
.getBegin(), const_cast<SourceManager
&>(*SM
));
144 PathDiagnosticRange
PathDiagnosticLocation::asRange() const {
146 // Note that we want a 'switch' here so that the compiler can warn us in
147 // case we add more cases.
150 return PathDiagnosticRange(R
, true);
154 const Stmt
*S
= asStmt();
155 switch (S
->getStmtClass()) {
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());
167 // FIXME: Provide better range information for different
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();
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();
193 SourceLocation L
= D
->getLocation();
194 return PathDiagnosticRange(SourceRange(L
, L
), true);
201 void PathDiagnosticLocation::flatten() {
208 else if (K
== DeclK
) {
209 SourceLocation L
= D
->getLocation();
210 R
= SourceRange(L
, L
);
217 //===----------------------------------------------------------------------===//
218 // FoldingSet profiling methods.
219 //===----------------------------------------------------------------------===//
221 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID
&ID
) const {
222 ID
.AddInteger((unsigned) K
);
225 ID
.AddInteger(R
.getBegin().getRawEncoding());
226 ID
.AddInteger(R
.getEnd().getRawEncoding());
229 ID
.AddInteger(R
.getBegin().getRawEncoding());
241 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
242 ID
.AddInteger((unsigned) getKind());
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
);
257 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
258 PathDiagnosticPiece::Profile(ID
);
259 for (const_iterator I
= begin(), E
= end(); I
!= E
; ++I
)
263 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID
&ID
) const {
264 PathDiagnosticSpotPiece::Profile(ID
);
265 for (const_iterator I
= begin(), E
= end(); I
!= E
; ++I
)
269 void PathDiagnostic::Profile(llvm::FoldingSetNodeID
&ID
) const {
271 ID
.AddString(BugType
);
273 ID
.AddString(Category
);
274 for (const_iterator I
= begin(), E
= end(); I
!= E
; ++I
)
277 for (meta_iterator I
= meta_begin(), E
= meta_end(); I
!= E
; ++I
)