1 //===--- PathDiagnostic.h - 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 #ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
15 #define LLVM_CLANG_PATH_DIAGNOSTIC_H
17 #include "clang/Basic/Diagnostic.h"
18 #include "llvm/ADT/FoldingSet.h"
30 //===----------------------------------------------------------------------===//
31 // High-level interface for handlers of path-sensitive diagnostics.
32 //===----------------------------------------------------------------------===//
36 class PathDiagnosticClient
: public DiagnosticClient
{
38 PathDiagnosticClient() {}
40 virtual ~PathDiagnosticClient() {}
43 FlushDiagnostics(llvm::SmallVectorImpl
<std::string
> *FilesMade
= 0) = 0;
45 void FlushDiagnostics(llvm::SmallVectorImpl
<std::string
> &FilesMade
) {
46 FlushDiagnostics(&FilesMade
);
49 virtual llvm::StringRef
getName() const = 0;
51 virtual void HandleDiagnostic(Diagnostic::Level DiagLevel
,
52 const DiagnosticInfo
&Info
);
53 virtual void HandlePathDiagnostic(const PathDiagnostic
* D
) = 0;
55 enum PathGenerationScheme
{ Minimal
, Extensive
};
56 virtual PathGenerationScheme
getGenerationScheme() const { return Minimal
; }
57 virtual bool supportsLogicalOpControlFlow() const { return false; }
58 virtual bool supportsAllBlockEdges() const { return false; }
59 virtual bool useVerboseDescription() const { return true; }
62 //===----------------------------------------------------------------------===//
63 // Path-sensitive diagnostics.
64 //===----------------------------------------------------------------------===//
66 class PathDiagnosticRange
: public SourceRange
{
70 PathDiagnosticRange(const SourceRange
&R
, bool isP
= false)
71 : SourceRange(R
), isPoint(isP
) {}
74 class PathDiagnosticLocation
{
76 enum Kind
{ RangeK
, SingleLocK
, StmtK
, DeclK
} K
;
80 const SourceManager
*SM
;
82 PathDiagnosticLocation()
83 : K(SingleLocK
), S(0), D(0), SM(0) {}
85 PathDiagnosticLocation(FullSourceLoc L
)
86 : K(SingleLocK
), R(L
, L
), S(0), D(0), SM(&L
.getManager()) {}
88 PathDiagnosticLocation(const Stmt
*s
, const SourceManager
&sm
)
89 : K(StmtK
), S(s
), D(0), SM(&sm
) {}
91 PathDiagnosticLocation(SourceRange r
, const SourceManager
&sm
)
92 : K(RangeK
), R(r
), S(0), D(0), SM(&sm
) {}
94 PathDiagnosticLocation(const Decl
*d
, const SourceManager
&sm
)
95 : K(DeclK
), S(0), D(d
), SM(&sm
) {}
97 bool operator==(const PathDiagnosticLocation
&X
) const {
98 return K
== X
.K
&& R
== X
.R
&& S
== X
.S
&& D
== X
.D
;
101 bool operator!=(const PathDiagnosticLocation
&X
) const {
102 return K
!= X
.K
|| R
!= X
.R
|| S
!= X
.S
|| D
!= X
.D
;;
105 PathDiagnosticLocation
& operator=(const PathDiagnosticLocation
&X
) {
114 bool isValid() const {
118 const SourceManager
& getSourceManager() const { assert(isValid());return *SM
;}
120 FullSourceLoc
asLocation() const;
121 PathDiagnosticRange
asRange() const;
122 const Stmt
*asStmt() const { assert(isValid()); return S
; }
123 const Decl
*asDecl() const { assert(isValid()); return D
; }
125 bool hasRange() const { return K
== StmtK
|| K
== RangeK
|| K
== DeclK
; }
128 *this = PathDiagnosticLocation();
133 const SourceManager
& getManager() const { assert(isValid()); return *SM
; }
135 void Profile(llvm::FoldingSetNodeID
&ID
) const;
138 class PathDiagnosticLocationPair
{
140 PathDiagnosticLocation Start
, End
;
142 PathDiagnosticLocationPair(const PathDiagnosticLocation
&start
,
143 const PathDiagnosticLocation
&end
)
144 : Start(start
), End(end
) {}
146 const PathDiagnosticLocation
&getStart() const { return Start
; }
147 const PathDiagnosticLocation
&getEnd() const { return End
; }
154 void Profile(llvm::FoldingSetNodeID
&ID
) const {
160 //===----------------------------------------------------------------------===//
161 // Path "pieces" for path-sensitive diagnostics.
162 //===----------------------------------------------------------------------===//
164 class PathDiagnosticPiece
{
166 enum Kind
{ ControlFlow
, Event
, Macro
};
167 enum DisplayHint
{ Above
, Below
};
170 const std::string str
;
171 std::vector
<FixItHint
> FixItHints
;
173 const DisplayHint Hint
;
174 std::vector
<SourceRange
> ranges
;
177 PathDiagnosticPiece();
178 PathDiagnosticPiece(const PathDiagnosticPiece
&P
);
179 PathDiagnosticPiece
& operator=(const PathDiagnosticPiece
&P
);
182 PathDiagnosticPiece(llvm::StringRef s
, Kind k
, DisplayHint hint
= Below
);
184 PathDiagnosticPiece(Kind k
, DisplayHint hint
= Below
);
187 virtual ~PathDiagnosticPiece();
189 const std::string
& getString() const { return str
; }
191 /// getDisplayHint - Return a hint indicating where the diagnostic should
192 /// be displayed by the PathDiagnosticClient.
193 DisplayHint
getDisplayHint() const { return Hint
; }
195 virtual PathDiagnosticLocation
getLocation() const = 0;
196 virtual void flattenLocations() = 0;
198 Kind
getKind() const { return kind
; }
200 void addRange(SourceRange R
) { ranges
.push_back(R
); }
202 void addRange(SourceLocation B
, SourceLocation E
) {
203 ranges
.push_back(SourceRange(B
,E
));
206 void addFixItHint(const FixItHint
& Hint
) {
207 FixItHints
.push_back(Hint
);
210 typedef const SourceRange
* range_iterator
;
212 range_iterator
ranges_begin() const {
213 return ranges
.empty() ? NULL
: &ranges
[0];
216 range_iterator
ranges_end() const {
217 return ranges_begin() + ranges
.size();
220 typedef const FixItHint
*fixit_iterator
;
222 fixit_iterator
fixit_begin() const {
223 return FixItHints
.empty()? 0 : &FixItHints
[0];
226 fixit_iterator
fixit_end() const {
227 return FixItHints
.empty()? 0
228 : &FixItHints
[0] + FixItHints
.size();
231 static inline bool classof(const PathDiagnosticPiece
* P
) {
235 virtual void Profile(llvm::FoldingSetNodeID
&ID
) const;
238 class PathDiagnosticSpotPiece
: public PathDiagnosticPiece
{
240 PathDiagnosticLocation Pos
;
242 PathDiagnosticSpotPiece(const PathDiagnosticLocation
&pos
,
244 PathDiagnosticPiece::Kind k
,
245 bool addPosRange
= true)
246 : PathDiagnosticPiece(s
, k
), Pos(pos
) {
247 assert(Pos
.asLocation().isValid() &&
248 "PathDiagnosticSpotPiece's must have a valid location.");
249 if (addPosRange
&& Pos
.hasRange()) addRange(Pos
.asRange());
252 PathDiagnosticLocation
getLocation() const { return Pos
; }
253 virtual void flattenLocations() { Pos
.flatten(); }
255 virtual void Profile(llvm::FoldingSetNodeID
&ID
) const;
258 class PathDiagnosticEventPiece
: public PathDiagnosticSpotPiece
{
261 PathDiagnosticEventPiece(const PathDiagnosticLocation
&pos
,
262 llvm::StringRef s
, bool addPosRange
= true)
263 : PathDiagnosticSpotPiece(pos
, s
, Event
, addPosRange
) {}
265 ~PathDiagnosticEventPiece();
267 static inline bool classof(const PathDiagnosticPiece
* P
) {
268 return P
->getKind() == Event
;
272 class PathDiagnosticControlFlowPiece
: public PathDiagnosticPiece
{
273 std::vector
<PathDiagnosticLocationPair
> LPairs
;
275 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation
&startPos
,
276 const PathDiagnosticLocation
&endPos
,
278 : PathDiagnosticPiece(s
, ControlFlow
) {
279 LPairs
.push_back(PathDiagnosticLocationPair(startPos
, endPos
));
282 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation
&startPos
,
283 const PathDiagnosticLocation
&endPos
)
284 : PathDiagnosticPiece(ControlFlow
) {
285 LPairs
.push_back(PathDiagnosticLocationPair(startPos
, endPos
));
288 ~PathDiagnosticControlFlowPiece();
290 PathDiagnosticLocation
getStartLocation() const {
291 assert(!LPairs
.empty() &&
292 "PathDiagnosticControlFlowPiece needs at least one location.");
293 return LPairs
[0].getStart();
296 PathDiagnosticLocation
getEndLocation() const {
297 assert(!LPairs
.empty() &&
298 "PathDiagnosticControlFlowPiece needs at least one location.");
299 return LPairs
[0].getEnd();
302 void push_back(const PathDiagnosticLocationPair
&X
) { LPairs
.push_back(X
); }
304 virtual PathDiagnosticLocation
getLocation() const {
305 return getStartLocation();
308 typedef std::vector
<PathDiagnosticLocationPair
>::iterator iterator
;
309 iterator
begin() { return LPairs
.begin(); }
310 iterator
end() { return LPairs
.end(); }
312 virtual void flattenLocations() {
313 for (iterator I
=begin(), E
=end(); I
!=E
; ++I
) I
->flatten();
316 typedef std::vector
<PathDiagnosticLocationPair
>::const_iterator
318 const_iterator
begin() const { return LPairs
.begin(); }
319 const_iterator
end() const { return LPairs
.end(); }
321 static inline bool classof(const PathDiagnosticPiece
* P
) {
322 return P
->getKind() == ControlFlow
;
325 virtual void Profile(llvm::FoldingSetNodeID
&ID
) const;
328 class PathDiagnosticMacroPiece
: public PathDiagnosticSpotPiece
{
329 std::vector
<PathDiagnosticPiece
*> SubPieces
;
331 PathDiagnosticMacroPiece(const PathDiagnosticLocation
&pos
)
332 : PathDiagnosticSpotPiece(pos
, "", Macro
) {}
334 ~PathDiagnosticMacroPiece();
336 bool containsEvent() const;
338 void push_back(PathDiagnosticPiece
* P
) { SubPieces
.push_back(P
); }
340 typedef std::vector
<PathDiagnosticPiece
*>::iterator iterator
;
341 iterator
begin() { return SubPieces
.begin(); }
342 iterator
end() { return SubPieces
.end(); }
344 virtual void flattenLocations() {
345 PathDiagnosticSpotPiece::flattenLocations();
346 for (iterator I
=begin(), E
=end(); I
!=E
; ++I
) (*I
)->flattenLocations();
349 typedef std::vector
<PathDiagnosticPiece
*>::const_iterator const_iterator
;
350 const_iterator
begin() const { return SubPieces
.begin(); }
351 const_iterator
end() const { return SubPieces
.end(); }
353 static inline bool classof(const PathDiagnosticPiece
* P
) {
354 return P
->getKind() == Macro
;
357 virtual void Profile(llvm::FoldingSetNodeID
&ID
) const;
360 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
361 /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
362 /// each which represent the pieces of the path.
363 class PathDiagnostic
: public llvm::FoldingSetNode
{
364 std::deque
<PathDiagnosticPiece
*> path
;
368 std::string Category
;
369 std::deque
<std::string
> OtherDesc
;
374 PathDiagnostic(llvm::StringRef bugtype
, llvm::StringRef desc
,
375 llvm::StringRef category
);
379 llvm::StringRef
getDescription() const { return Desc
; }
380 llvm::StringRef
getBugType() const { return BugType
; }
381 llvm::StringRef
getCategory() const { return Category
; }
383 typedef std::deque
<std::string
>::const_iterator meta_iterator
;
384 meta_iterator
meta_begin() const { return OtherDesc
.begin(); }
385 meta_iterator
meta_end() const { return OtherDesc
.end(); }
386 void addMeta(llvm::StringRef s
) { OtherDesc
.push_back(s
); }
388 PathDiagnosticLocation
getLocation() const {
389 assert(Size
> 0 && "getLocation() requires a non-empty PathDiagnostic.");
390 return rbegin()->getLocation();
393 void push_front(PathDiagnosticPiece
* piece
) {
395 path
.push_front(piece
);
399 void push_back(PathDiagnosticPiece
* piece
) {
401 path
.push_back(piece
);
405 PathDiagnosticPiece
* back() {
409 const PathDiagnosticPiece
* back() const {
413 unsigned size() const { return Size
; }
414 bool empty() const { return Size
== 0; }
416 void resetPath(bool deletePieces
= true);
420 typedef std::deque
<PathDiagnosticPiece
*>::iterator ImplTy
;
422 typedef PathDiagnosticPiece value_type
;
423 typedef value_type
& reference
;
424 typedef value_type
* pointer
;
425 typedef ptrdiff_t difference_type
;
426 typedef std::bidirectional_iterator_tag iterator_category
;
432 iterator(const ImplTy
& i
) : I(i
) {}
434 bool operator==(const iterator
& X
) const { return I
== X
.I
; }
435 bool operator!=(const iterator
& X
) const { return I
!= X
.I
; }
437 PathDiagnosticPiece
& operator*() const { return **I
; }
438 PathDiagnosticPiece
* operator->() const { return *I
; }
440 iterator
& operator++() { ++I
; return *this; }
441 iterator
& operator--() { --I
; return *this; }
444 class const_iterator
{
446 typedef std::deque
<PathDiagnosticPiece
*>::const_iterator ImplTy
;
448 typedef const PathDiagnosticPiece value_type
;
449 typedef value_type
& reference
;
450 typedef value_type
* pointer
;
451 typedef ptrdiff_t difference_type
;
452 typedef std::bidirectional_iterator_tag iterator_category
;
458 const_iterator(const ImplTy
& i
) : I(i
) {}
460 bool operator==(const const_iterator
& X
) const { return I
== X
.I
; }
461 bool operator!=(const const_iterator
& X
) const { return I
!= X
.I
; }
463 reference
operator*() const { return **I
; }
464 pointer
operator->() const { return *I
; }
466 const_iterator
& operator++() { ++I
; return *this; }
467 const_iterator
& operator--() { --I
; return *this; }
470 typedef std::reverse_iterator
<iterator
> reverse_iterator
;
471 typedef std::reverse_iterator
<const_iterator
> const_reverse_iterator
;
473 // forward iterator creation methods.
475 iterator
begin() { return path
.begin(); }
476 iterator
end() { return path
.end(); }
478 const_iterator
begin() const { return path
.begin(); }
479 const_iterator
end() const { return path
.end(); }
481 // reverse iterator creation methods.
482 reverse_iterator
rbegin() { return reverse_iterator(end()); }
483 const_reverse_iterator
rbegin() const{ return const_reverse_iterator(end()); }
484 reverse_iterator
rend() { return reverse_iterator(begin()); }
485 const_reverse_iterator
rend() const { return const_reverse_iterator(begin());}
487 void flattenLocations() {
488 for (iterator I
= begin(), E
= end(); I
!= E
; ++I
) I
->flattenLocations();
491 void Profile(llvm::FoldingSetNodeID
&ID
) const;
493 } //end clang namespace