PathDiagnostic.h revision c93dc7889644293e318e19d82830ea2acc45b678
1//===--- PathDiagnostic.h - 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#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
15#define LLVM_CLANG_PATH_DIAGNOSTIC_H
16
17#include "clang/Basic/SourceLocation.h"
18#include "llvm/ADT/FoldingSet.h"
19#include "llvm/ADT/IntrusiveRefCntPtr.h"
20#include "llvm/ADT/PointerUnion.h"
21#include <deque>
22#include <iterator>
23#include <string>
24#include <vector>
25
26namespace clang {
27
28class AnalysisDeclContext;
29class BinaryOperator;
30class CompoundStmt;
31class Decl;
32class LocationContext;
33class MemberExpr;
34class ParentMap;
35class ProgramPoint;
36class SourceManager;
37class Stmt;
38
39namespace ento {
40
41class ExplodedNode;
42
43//===----------------------------------------------------------------------===//
44// High-level interface for handlers of path-sensitive diagnostics.
45//===----------------------------------------------------------------------===//
46
47class PathDiagnostic;
48
49class PathDiagnosticConsumer {
50  virtual void anchor();
51public:
52  PathDiagnosticConsumer() : flushed(false) {}
53  virtual ~PathDiagnosticConsumer();
54
55  void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
56
57  virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
58                                    SmallVectorImpl<std::string> *FilesMade)
59                                    = 0;
60
61  virtual StringRef getName() const = 0;
62
63  void HandlePathDiagnostic(PathDiagnostic *D);
64
65  enum PathGenerationScheme { Minimal, Extensive };
66  virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
67  virtual bool supportsLogicalOpControlFlow() const { return false; }
68  virtual bool supportsAllBlockEdges() const { return false; }
69  virtual bool useVerboseDescription() const { return true; }
70
71protected:
72  bool flushed;
73  llvm::FoldingSet<PathDiagnostic> Diags;
74};
75
76//===----------------------------------------------------------------------===//
77// Path-sensitive diagnostics.
78//===----------------------------------------------------------------------===//
79
80class PathDiagnosticRange : public SourceRange {
81public:
82  bool isPoint;
83
84  PathDiagnosticRange(const SourceRange &R, bool isP = false)
85    : SourceRange(R), isPoint(isP) {}
86
87  PathDiagnosticRange() : isPoint(false) {}
88};
89
90typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*>
91                                                   LocationOrAnalysisDeclContext;
92
93class PathDiagnosticLocation {
94private:
95  enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
96  const Stmt *S;
97  const Decl *D;
98  const SourceManager *SM;
99  FullSourceLoc Loc;
100  PathDiagnosticRange Range;
101
102  PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
103                         Kind kind)
104    : K(kind), S(0), D(0), SM(&sm),
105      Loc(genLocation(L)), Range(genRange()) {
106    assert(Loc.isValid());
107    assert(Range.isValid());
108  }
109
110  FullSourceLoc
111    genLocation(SourceLocation L = SourceLocation(),
112                LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
113
114  PathDiagnosticRange
115    genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
116
117public:
118  /// Create an invalid location.
119  PathDiagnosticLocation()
120    : K(SingleLocK), S(0), D(0), SM(0) {}
121
122  /// Create a location corresponding to the given statement.
123  PathDiagnosticLocation(const Stmt *s,
124                         const SourceManager &sm,
125                         LocationOrAnalysisDeclContext lac)
126    : K(StmtK), S(s), D(0), SM(&sm),
127      Loc(genLocation(SourceLocation(), lac)),
128      Range(genRange(lac)) {
129    assert(S);
130    assert(Loc.isValid());
131    assert(Range.isValid());
132  }
133
134  /// Create a location corresponding to the given declaration.
135  PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
136    : K(DeclK), S(0), D(d), SM(&sm),
137      Loc(genLocation()), Range(genRange()) {
138    assert(D);
139    assert(Loc.isValid());
140    assert(Range.isValid());
141  }
142
143  /// Create a location corresponding to the given declaration.
144  static PathDiagnosticLocation create(const Decl *D,
145                                       const SourceManager &SM) {
146    return PathDiagnosticLocation(D, SM);
147  }
148
149  /// Create a location for the beginning of the declaration.
150  static PathDiagnosticLocation createBegin(const Decl *D,
151                                            const SourceManager &SM);
152
153  /// Create a location for the beginning of the statement.
154  static PathDiagnosticLocation createBegin(const Stmt *S,
155                                            const SourceManager &SM,
156                                            const LocationOrAnalysisDeclContext LAC);
157
158  /// Create the location for the operator of the binary expression.
159  /// Assumes the statement has a valid location.
160  static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
161                                                  const SourceManager &SM);
162
163  /// For member expressions, return the location of the '.' or '->'.
164  /// Assumes the statement has a valid location.
165  static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
166                                                const SourceManager &SM);
167
168  /// Create a location for the beginning of the compound statement.
169  /// Assumes the statement has a valid location.
170  static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
171                                                 const SourceManager &SM);
172
173  /// Create a location for the end of the compound statement.
174  /// Assumes the statement has a valid location.
175  static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
176                                               const SourceManager &SM);
177
178  /// Create a location for the beginning of the enclosing declaration body.
179  /// Defaults to the beginning of the first statement in the declaration body.
180  static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
181                                                const SourceManager &SM);
182
183  /// Constructs a location for the end of the enclosing declaration body.
184  /// Defaults to the end of brace.
185  static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
186                                                   const SourceManager &SM);
187
188  /// Create a location corresponding to the given valid ExplodedNode.
189  static PathDiagnosticLocation create(const ProgramPoint& P,
190                                       const SourceManager &SMng);
191
192  /// Create a location corresponding to the next valid ExplodedNode as end
193  /// of path location.
194  static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
195                                                const SourceManager &SM);
196
197  /// Convert the given location into a single kind location.
198  static PathDiagnosticLocation createSingleLocation(
199                                             const PathDiagnosticLocation &PDL);
200
201  bool operator==(const PathDiagnosticLocation &X) const {
202    return K == X.K && Loc == X.Loc && Range == X.Range;
203  }
204
205  bool operator!=(const PathDiagnosticLocation &X) const {
206    return !(*this == X);
207  }
208
209  bool isValid() const {
210    return SM != 0;
211  }
212
213  FullSourceLoc asLocation() const {
214    return Loc;
215  }
216
217  PathDiagnosticRange asRange() const {
218    return Range;
219  }
220
221  const Stmt *asStmt() const { assert(isValid()); return S; }
222  const Decl *asDecl() const { assert(isValid()); return D; }
223
224  bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
225
226  void invalidate() {
227    *this = PathDiagnosticLocation();
228  }
229
230  void flatten();
231
232  const SourceManager& getManager() const { assert(isValid()); return *SM; }
233
234  void Profile(llvm::FoldingSetNodeID &ID) const;
235};
236
237class PathDiagnosticLocationPair {
238private:
239  PathDiagnosticLocation Start, End;
240public:
241  PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
242                             const PathDiagnosticLocation &end)
243    : Start(start), End(end) {}
244
245  const PathDiagnosticLocation &getStart() const { return Start; }
246  const PathDiagnosticLocation &getEnd() const { return End; }
247
248  void flatten() {
249    Start.flatten();
250    End.flatten();
251  }
252
253  void Profile(llvm::FoldingSetNodeID &ID) const {
254    Start.Profile(ID);
255    End.Profile(ID);
256  }
257};
258
259//===----------------------------------------------------------------------===//
260// Path "pieces" for path-sensitive diagnostics.
261//===----------------------------------------------------------------------===//
262
263class PathDiagnosticPiece : public RefCountedBaseVPTR {
264public:
265  enum Kind { ControlFlow, Event, Macro, CallEnter, CallExit };
266  enum DisplayHint { Above, Below };
267
268private:
269  const std::string str;
270  const Kind kind;
271  const DisplayHint Hint;
272  std::vector<SourceRange> ranges;
273
274  // Do not implement:
275  PathDiagnosticPiece();
276  PathDiagnosticPiece(const PathDiagnosticPiece &P);
277  PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
278
279protected:
280  PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
281
282  PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
283
284public:
285  virtual ~PathDiagnosticPiece();
286
287  const std::string& getString() const { return str; }
288
289  /// getDisplayHint - Return a hint indicating where the diagnostic should
290  ///  be displayed by the PathDiagnosticConsumer.
291  DisplayHint getDisplayHint() const { return Hint; }
292
293  virtual PathDiagnosticLocation getLocation() const = 0;
294  virtual void flattenLocations() = 0;
295
296  Kind getKind() const { return kind; }
297
298  void addRange(SourceRange R) {
299    if (!R.isValid())
300      return;
301    ranges.push_back(R);
302  }
303
304  void addRange(SourceLocation B, SourceLocation E) {
305    if (!B.isValid() || !E.isValid())
306      return;
307    ranges.push_back(SourceRange(B,E));
308  }
309
310  typedef const SourceRange* range_iterator;
311
312  range_iterator ranges_begin() const {
313    return ranges.empty() ? NULL : &ranges[0];
314  }
315
316  range_iterator ranges_end() const {
317    return ranges_begin() + ranges.size();
318  }
319
320  static inline bool classof(const PathDiagnosticPiece *P) {
321    return true;
322  }
323
324  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
325};
326
327
328class PathPieces :
329  public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
330public:
331  ~PathPieces();
332};
333
334class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
335private:
336  PathDiagnosticLocation Pos;
337public:
338  PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
339                          StringRef s,
340                          PathDiagnosticPiece::Kind k,
341                          bool addPosRange = true)
342  : PathDiagnosticPiece(s, k), Pos(pos) {
343    assert(Pos.isValid() && Pos.asLocation().isValid() &&
344           "PathDiagnosticSpotPiece's must have a valid location.");
345    if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
346  }
347
348  PathDiagnosticLocation getLocation() const { return Pos; }
349  virtual void flattenLocations() { Pos.flatten(); }
350
351  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
352};
353
354class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
355
356public:
357  PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
358                           StringRef s, bool addPosRange = true)
359    : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
360
361  ~PathDiagnosticEventPiece();
362
363  static inline bool classof(const PathDiagnosticPiece *P) {
364    return P->getKind() == Event;
365  }
366};
367
368class PathDiagnosticCallEnterPiece : public PathDiagnosticSpotPiece {
369public:
370  PathDiagnosticCallEnterPiece(const PathDiagnosticLocation &pos,
371                              StringRef s)
372    : PathDiagnosticSpotPiece(pos, s, CallEnter, false) {}
373
374  ~PathDiagnosticCallEnterPiece();
375
376  static inline bool classof(const PathDiagnosticPiece *P) {
377    return P->getKind() == CallEnter;
378  }
379};
380
381class PathDiagnosticCallExitPiece : public PathDiagnosticSpotPiece {
382public:
383  PathDiagnosticCallExitPiece(const PathDiagnosticLocation &pos,
384                             StringRef s)
385  : PathDiagnosticSpotPiece(pos, s, CallExit, false) {}
386
387  ~PathDiagnosticCallExitPiece();
388
389  static inline bool classof(const PathDiagnosticPiece *P) {
390    return P->getKind() == CallExit;
391  }
392};
393
394class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
395  std::vector<PathDiagnosticLocationPair> LPairs;
396public:
397  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
398                                 const PathDiagnosticLocation &endPos,
399                                 StringRef s)
400    : PathDiagnosticPiece(s, ControlFlow) {
401      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
402    }
403
404  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
405                                 const PathDiagnosticLocation &endPos)
406    : PathDiagnosticPiece(ControlFlow) {
407      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
408    }
409
410  ~PathDiagnosticControlFlowPiece();
411
412  PathDiagnosticLocation getStartLocation() const {
413    assert(!LPairs.empty() &&
414           "PathDiagnosticControlFlowPiece needs at least one location.");
415    return LPairs[0].getStart();
416  }
417
418  PathDiagnosticLocation getEndLocation() const {
419    assert(!LPairs.empty() &&
420           "PathDiagnosticControlFlowPiece needs at least one location.");
421    return LPairs[0].getEnd();
422  }
423
424  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
425
426  virtual PathDiagnosticLocation getLocation() const {
427    return getStartLocation();
428  }
429
430  typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
431  iterator begin() { return LPairs.begin(); }
432  iterator end()   { return LPairs.end(); }
433
434  virtual void flattenLocations() {
435    for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
436  }
437
438  typedef std::vector<PathDiagnosticLocationPair>::const_iterator
439          const_iterator;
440  const_iterator begin() const { return LPairs.begin(); }
441  const_iterator end() const   { return LPairs.end(); }
442
443  static inline bool classof(const PathDiagnosticPiece *P) {
444    return P->getKind() == ControlFlow;
445  }
446
447  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
448};
449
450class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
451public:
452  PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
453    : PathDiagnosticSpotPiece(pos, "", Macro) {}
454
455  ~PathDiagnosticMacroPiece();
456
457  PathPieces subPieces;
458
459  bool containsEvent() const;
460
461  virtual void flattenLocations() {
462    PathDiagnosticSpotPiece::flattenLocations();
463    for (PathPieces::iterator I = subPieces.begin(),
464         E = subPieces.end(); I != E; ++I) (*I)->flattenLocations();
465  }
466
467  static inline bool classof(const PathDiagnosticPiece *P) {
468    return P->getKind() == Macro;
469  }
470
471  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
472};
473
474/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
475///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
476///  each which represent the pieces of the path.
477class PathDiagnostic : public llvm::FoldingSetNode {
478  std::string BugType;
479  std::string Desc;
480  std::string Category;
481  std::deque<std::string> OtherDesc;
482public:
483  PathPieces path;
484
485  PathDiagnostic();
486  PathDiagnostic(StringRef bugtype, StringRef desc,
487                 StringRef category);
488
489  ~PathDiagnostic();
490
491  StringRef getDescription() const { return Desc; }
492  StringRef getBugType() const { return BugType; }
493  StringRef getCategory() const { return Category; }
494
495
496  typedef std::deque<std::string>::const_iterator meta_iterator;
497  meta_iterator meta_begin() const { return OtherDesc.begin(); }
498  meta_iterator meta_end() const { return OtherDesc.end(); }
499  void addMeta(StringRef s) { OtherDesc.push_back(s); }
500
501  PathDiagnosticLocation getLocation() const {
502    assert(path.size() > 0 &&
503           "getLocation() requires a non-empty PathDiagnostic.");
504    return (*path.rbegin())->getLocation();
505  }
506
507  void flattenLocations() {
508    for (PathPieces::iterator I = path.begin(), E = path.end();
509         I != E; ++I) (*I)->flattenLocations();
510  }
511
512  void Profile(llvm::FoldingSetNodeID &ID) const;
513
514  void FullProfile(llvm::FoldingSetNodeID &ID) const;
515};
516
517} // end GR namespace
518
519} //end clang namespace
520
521#endif
522