PathDiagnostic.h revision 9373937945e1e075dfa08169eaccc1ad0b31f699
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, const Decl *caller)
395    : PathDiagnosticPiece(Call), Caller(caller), Callee(0),
396      NoExit(true), path(oldPath) {}
397
398  const Decl *Caller;
399  const Decl *Callee;
400
401  // Flag signifying that this diagnostic has only call enter and no matching
402  // call exit.
403  bool NoExit;
404
405public:
406  PathDiagnosticLocation callEnter;
407  PathDiagnosticLocation callEnterWithin;
408  PathDiagnosticLocation callReturn;
409  PathPieces path;
410
411  virtual ~PathDiagnosticCallPiece();
412
413  const Decl *getCaller() const { return Caller; }
414
415  const Decl *getCallee() const { return Callee; }
416  void setCallee(const CallEnter &CE, const SourceManager &SM);
417
418  virtual PathDiagnosticLocation getLocation() const {
419    return callEnter;
420  }
421
422  IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const;
423  IntrusiveRefCntPtr<PathDiagnosticEventPiece>
424    getCallEnterWithinCallerEvent() const;
425  IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const;
426
427  virtual void flattenLocations() {
428    callEnter.flatten();
429    callReturn.flatten();
430    for (PathPieces::iterator I = path.begin(),
431         E = path.end(); I != E; ++I) (*I)->flattenLocations();
432  }
433
434  static PathDiagnosticCallPiece *construct(const ExplodedNode *N,
435                                            const CallExit &CE,
436                                            const SourceManager &SM);
437
438  static PathDiagnosticCallPiece *construct(PathPieces &pieces,
439                                            const Decl *caller);
440
441  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
442
443  static inline bool classof(const PathDiagnosticPiece *P) {
444    return P->getKind() == Call;
445  }
446};
447
448class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
449  std::vector<PathDiagnosticLocationPair> LPairs;
450public:
451  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
452                                 const PathDiagnosticLocation &endPos,
453                                 StringRef s)
454    : PathDiagnosticPiece(s, ControlFlow) {
455      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
456    }
457
458  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
459                                 const PathDiagnosticLocation &endPos)
460    : PathDiagnosticPiece(ControlFlow) {
461      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
462    }
463
464  ~PathDiagnosticControlFlowPiece();
465
466  PathDiagnosticLocation getStartLocation() const {
467    assert(!LPairs.empty() &&
468           "PathDiagnosticControlFlowPiece needs at least one location.");
469    return LPairs[0].getStart();
470  }
471
472  PathDiagnosticLocation getEndLocation() const {
473    assert(!LPairs.empty() &&
474           "PathDiagnosticControlFlowPiece needs at least one location.");
475    return LPairs[0].getEnd();
476  }
477
478  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
479
480  virtual PathDiagnosticLocation getLocation() const {
481    return getStartLocation();
482  }
483
484  typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
485  iterator begin() { return LPairs.begin(); }
486  iterator end()   { return LPairs.end(); }
487
488  virtual void flattenLocations() {
489    for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
490  }
491
492  typedef std::vector<PathDiagnosticLocationPair>::const_iterator
493          const_iterator;
494  const_iterator begin() const { return LPairs.begin(); }
495  const_iterator end() const   { return LPairs.end(); }
496
497  static inline bool classof(const PathDiagnosticPiece *P) {
498    return P->getKind() == ControlFlow;
499  }
500
501  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
502};
503
504class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
505public:
506  PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
507    : PathDiagnosticSpotPiece(pos, "", Macro) {}
508
509  ~PathDiagnosticMacroPiece();
510
511  PathPieces subPieces;
512
513  bool containsEvent() const;
514
515  virtual void flattenLocations() {
516    PathDiagnosticSpotPiece::flattenLocations();
517    for (PathPieces::iterator I = subPieces.begin(),
518         E = subPieces.end(); I != E; ++I) (*I)->flattenLocations();
519  }
520
521  static inline bool classof(const PathDiagnosticPiece *P) {
522    return P->getKind() == Macro;
523  }
524
525  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
526};
527
528/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
529///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
530///  each which represent the pieces of the path.
531class PathDiagnostic : public llvm::FoldingSetNode {
532  std::string BugType;
533  std::string Desc;
534  std::string Category;
535  std::deque<std::string> OtherDesc;
536  PathPieces pathImpl;
537  llvm::SmallVector<PathPieces *, 3> pathStack;
538public:
539  const PathPieces &path;
540
541  /// Return the path currently used by builders for constructing the
542  /// PathDiagnostic.
543  PathPieces &getActivePath() {
544    if (pathStack.empty())
545      return pathImpl;
546    return *pathStack.back();
547  }
548
549  /// Return a mutable version of 'path'.
550  PathPieces &getMutablePieces() {
551    return pathImpl;
552  }
553
554  /// Return the unrolled size of the path.
555  unsigned full_size();
556
557  void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
558  void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
559
560  PathDiagnostic();
561  PathDiagnostic(StringRef bugtype, StringRef desc,
562                 StringRef category);
563
564  ~PathDiagnostic();
565
566  StringRef getDescription() const { return Desc; }
567  StringRef getBugType() const { return BugType; }
568  StringRef getCategory() const { return Category; }
569
570
571  typedef std::deque<std::string>::const_iterator meta_iterator;
572  meta_iterator meta_begin() const { return OtherDesc.begin(); }
573  meta_iterator meta_end() const { return OtherDesc.end(); }
574  void addMeta(StringRef s) { OtherDesc.push_back(s); }
575
576  PathDiagnosticLocation getLocation() const;
577
578  void flattenLocations() {
579    for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end();
580         I != E; ++I) (*I)->flattenLocations();
581  }
582
583  void Profile(llvm::FoldingSetNodeID &ID) const;
584
585  void FullProfile(llvm::FoldingSetNodeID &ID) const;
586};
587
588} // end GR namespace
589
590} //end clang namespace
591
592#endif
593