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