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