Home | History | Annotate | Download | only in BugReporter
      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/Diagnostic.h"
     18 #include "llvm/ADT/FoldingSet.h"
     19 #include "llvm/ADT/PointerUnion.h"
     20 #include <deque>
     21 #include <iterator>
     22 #include <string>
     23 #include <vector>
     24 
     25 namespace clang {
     26 
     27 class AnalysisContext;
     28 class BinaryOperator;
     29 class CompoundStmt;
     30 class Decl;
     31 class LocationContext;
     32 class MemberExpr;
     33 class ParentMap;
     34 class ProgramPoint;
     35 class SourceManager;
     36 class Stmt;
     37 
     38 namespace ento {
     39 
     40 class ExplodedNode;
     41 
     42 //===----------------------------------------------------------------------===//
     43 // High-level interface for handlers of path-sensitive diagnostics.
     44 //===----------------------------------------------------------------------===//
     45 
     46 class PathDiagnostic;
     47 
     48 class PathDiagnosticConsumer {
     49 public:
     50   PathDiagnosticConsumer() {}
     51 
     52   virtual ~PathDiagnosticConsumer() {}
     53 
     54   virtual void
     55   FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade = 0) = 0;
     56 
     57   void FlushDiagnostics(SmallVectorImpl<std::string> &FilesMade) {
     58     FlushDiagnostics(&FilesMade);
     59   }
     60 
     61   virtual StringRef getName() const = 0;
     62 
     63   void HandlePathDiagnostic(const 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 
     71 protected:
     72   /// The actual logic for handling path diagnostics, as implemented
     73   /// by subclasses of PathDiagnosticConsumer.
     74   virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D) = 0;
     75 
     76 };
     77 
     78 //===----------------------------------------------------------------------===//
     79 // Path-sensitive diagnostics.
     80 //===----------------------------------------------------------------------===//
     81 
     82 class PathDiagnosticRange : public SourceRange {
     83 public:
     84   bool isPoint;
     85 
     86   PathDiagnosticRange(const SourceRange &R, bool isP = false)
     87     : SourceRange(R), isPoint(isP) {}
     88 
     89   PathDiagnosticRange() : isPoint(false) {}
     90 };
     91 
     92 typedef llvm::PointerUnion<const LocationContext*, AnalysisContext*>
     93                                                    LocationOrAnalysisContext;
     94 
     95 class PathDiagnosticLocation {
     96 private:
     97   enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
     98   const Stmt *S;
     99   const Decl *D;
    100   const SourceManager *SM;
    101   FullSourceLoc Loc;
    102   PathDiagnosticRange Range;
    103 
    104   PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
    105                          Kind kind)
    106     : K(kind), S(0), D(0), SM(&sm),
    107       Loc(genLocation(L)), Range(genRange()) {
    108     assert(Loc.isValid());
    109     assert(Range.isValid());
    110   }
    111 
    112   FullSourceLoc
    113     genLocation(SourceLocation L = SourceLocation(),
    114                 LocationOrAnalysisContext LAC = (AnalysisContext*)0) const;
    115 
    116   PathDiagnosticRange
    117     genRange(LocationOrAnalysisContext LAC = (AnalysisContext*)0) const;
    118 
    119 public:
    120   /// Create an invalid location.
    121   PathDiagnosticLocation()
    122     : K(SingleLocK), S(0), D(0), SM(0) {}
    123 
    124   /// Create a location corresponding to the given statement.
    125   PathDiagnosticLocation(const Stmt *s,
    126                          const SourceManager &sm,
    127                          LocationOrAnalysisContext lac)
    128     : K(StmtK), S(s), D(0), SM(&sm),
    129       Loc(genLocation(SourceLocation(), lac)),
    130       Range(genRange(lac)) {
    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(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 LocationOrAnalysisContext 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 
    237 class PathDiagnosticLocationPair {
    238 private:
    239   PathDiagnosticLocation Start, End;
    240 public:
    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 
    263 class PathDiagnosticPiece {
    264 public:
    265   enum Kind { ControlFlow, Event, Macro };
    266   enum DisplayHint { Above, Below };
    267 
    268 private:
    269   const std::string str;
    270   std::vector<FixItHint> FixItHints;
    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 
    280 protected:
    281   PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
    282 
    283   PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
    284 
    285 public:
    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   void addFixItHint(const FixItHint& Hint) {
    312     FixItHints.push_back(Hint);
    313   }
    314 
    315   typedef const SourceRange* range_iterator;
    316 
    317   range_iterator ranges_begin() const {
    318     return ranges.empty() ? NULL : &ranges[0];
    319   }
    320 
    321   range_iterator ranges_end() const {
    322     return ranges_begin() + ranges.size();
    323   }
    324 
    325   typedef const FixItHint *fixit_iterator;
    326 
    327   fixit_iterator fixit_begin() const {
    328     return FixItHints.empty()? 0 : &FixItHints[0];
    329   }
    330 
    331   fixit_iterator fixit_end() const {
    332     return FixItHints.empty()? 0
    333                    : &FixItHints[0] + FixItHints.size();
    334   }
    335 
    336   static inline bool classof(const PathDiagnosticPiece *P) {
    337     return true;
    338   }
    339 
    340   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
    341 };
    342 
    343 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
    344 private:
    345   PathDiagnosticLocation Pos;
    346 public:
    347   PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
    348                           StringRef s,
    349                           PathDiagnosticPiece::Kind k,
    350                           bool addPosRange = true)
    351   : PathDiagnosticPiece(s, k), Pos(pos) {
    352     assert(Pos.isValid() && Pos.asLocation().isValid() &&
    353            "PathDiagnosticSpotPiece's must have a valid location.");
    354     if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
    355   }
    356 
    357   PathDiagnosticLocation getLocation() const { return Pos; }
    358   virtual void flattenLocations() { Pos.flatten(); }
    359 
    360   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
    361 };
    362 
    363 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
    364 
    365 public:
    366   PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
    367                            StringRef s, bool addPosRange = true)
    368     : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
    369 
    370   ~PathDiagnosticEventPiece();
    371 
    372   static inline bool classof(const PathDiagnosticPiece *P) {
    373     return P->getKind() == Event;
    374   }
    375 };
    376 
    377 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
    378   std::vector<PathDiagnosticLocationPair> LPairs;
    379 public:
    380   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
    381                                  const PathDiagnosticLocation &endPos,
    382                                  StringRef s)
    383     : PathDiagnosticPiece(s, ControlFlow) {
    384       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
    385     }
    386 
    387   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
    388                                  const PathDiagnosticLocation &endPos)
    389     : PathDiagnosticPiece(ControlFlow) {
    390       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
    391     }
    392 
    393   ~PathDiagnosticControlFlowPiece();
    394 
    395   PathDiagnosticLocation getStartLocation() const {
    396     assert(!LPairs.empty() &&
    397            "PathDiagnosticControlFlowPiece needs at least one location.");
    398     return LPairs[0].getStart();
    399   }
    400 
    401   PathDiagnosticLocation getEndLocation() const {
    402     assert(!LPairs.empty() &&
    403            "PathDiagnosticControlFlowPiece needs at least one location.");
    404     return LPairs[0].getEnd();
    405   }
    406 
    407   void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
    408 
    409   virtual PathDiagnosticLocation getLocation() const {
    410     return getStartLocation();
    411   }
    412 
    413   typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
    414   iterator begin() { return LPairs.begin(); }
    415   iterator end()   { return LPairs.end(); }
    416 
    417   virtual void flattenLocations() {
    418     for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
    419   }
    420 
    421   typedef std::vector<PathDiagnosticLocationPair>::const_iterator
    422           const_iterator;
    423   const_iterator begin() const { return LPairs.begin(); }
    424   const_iterator end() const   { return LPairs.end(); }
    425 
    426   static inline bool classof(const PathDiagnosticPiece *P) {
    427     return P->getKind() == ControlFlow;
    428   }
    429 
    430   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
    431 };
    432 
    433 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
    434   std::vector<PathDiagnosticPiece*> SubPieces;
    435 public:
    436   PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
    437     : PathDiagnosticSpotPiece(pos, "", Macro) {}
    438 
    439   ~PathDiagnosticMacroPiece();
    440 
    441   bool containsEvent() const;
    442 
    443   void push_back(PathDiagnosticPiece *P) { SubPieces.push_back(P); }
    444 
    445   typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
    446   iterator begin() { return SubPieces.begin(); }
    447   iterator end() { return SubPieces.end(); }
    448 
    449   virtual void flattenLocations() {
    450     PathDiagnosticSpotPiece::flattenLocations();
    451     for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations();
    452   }
    453 
    454   typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator;
    455   const_iterator begin() const { return SubPieces.begin(); }
    456   const_iterator end() const { return SubPieces.end(); }
    457 
    458   static inline bool classof(const PathDiagnosticPiece *P) {
    459     return P->getKind() == Macro;
    460   }
    461 
    462   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
    463 };
    464 
    465 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
    466 ///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
    467 ///  each which represent the pieces of the path.
    468 class PathDiagnostic : public llvm::FoldingSetNode {
    469   std::deque<PathDiagnosticPiece*> path;
    470   unsigned Size;
    471   std::string BugType;
    472   std::string Desc;
    473   std::string Category;
    474   std::deque<std::string> OtherDesc;
    475 
    476 public:
    477   PathDiagnostic();
    478 
    479   PathDiagnostic(StringRef bugtype, StringRef desc,
    480                  StringRef category);
    481 
    482   ~PathDiagnostic();
    483 
    484   StringRef getDescription() const { return Desc; }
    485   StringRef getBugType() const { return BugType; }
    486   StringRef getCategory() const { return Category; }
    487 
    488   typedef std::deque<std::string>::const_iterator meta_iterator;
    489   meta_iterator meta_begin() const { return OtherDesc.begin(); }
    490   meta_iterator meta_end() const { return OtherDesc.end(); }
    491   void addMeta(StringRef s) { OtherDesc.push_back(s); }
    492 
    493   PathDiagnosticLocation getLocation() const {
    494     assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
    495     return rbegin()->getLocation();
    496   }
    497 
    498   void push_front(PathDiagnosticPiece *piece) {
    499     assert(piece);
    500     path.push_front(piece);
    501     ++Size;
    502   }
    503 
    504   void push_back(PathDiagnosticPiece *piece) {
    505     assert(piece);
    506     path.push_back(piece);
    507     ++Size;
    508   }
    509 
    510   PathDiagnosticPiece *back() {
    511     return path.back();
    512   }
    513 
    514   const PathDiagnosticPiece *back() const {
    515     return path.back();
    516   }
    517 
    518   unsigned size() const { return Size; }
    519   bool empty() const { return Size == 0; }
    520 
    521   void resetPath(bool deletePieces = true);
    522 
    523   class iterator {
    524   public:
    525     typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy;
    526 
    527     typedef PathDiagnosticPiece              value_type;
    528     typedef value_type&                      reference;
    529     typedef value_type*                      pointer;
    530     typedef ptrdiff_t                        difference_type;
    531     typedef std::bidirectional_iterator_tag  iterator_category;
    532 
    533   private:
    534     ImplTy I;
    535 
    536   public:
    537     iterator(const ImplTy& i) : I(i) {}
    538 
    539     bool operator==(const iterator &X) const { return I == X.I; }
    540     bool operator!=(const iterator &X) const { return I != X.I; }
    541 
    542     PathDiagnosticPiece& operator*() const { return **I; }
    543     PathDiagnosticPiece *operator->() const { return *I; }
    544 
    545     iterator &operator++() { ++I; return *this; }
    546     iterator &operator--() { --I; return *this; }
    547   };
    548 
    549   class const_iterator {
    550   public:
    551     typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy;
    552 
    553     typedef const PathDiagnosticPiece        value_type;
    554     typedef value_type&                      reference;
    555     typedef value_type*                      pointer;
    556     typedef ptrdiff_t                        difference_type;
    557     typedef std::bidirectional_iterator_tag  iterator_category;
    558 
    559   private:
    560     ImplTy I;
    561 
    562   public:
    563     const_iterator(const ImplTy& i) : I(i) {}
    564 
    565     bool operator==(const const_iterator &X) const { return I == X.I; }
    566     bool operator!=(const const_iterator &X) const { return I != X.I; }
    567 
    568     reference operator*() const { return **I; }
    569     pointer operator->() const { return *I; }
    570 
    571     const_iterator &operator++() { ++I; return *this; }
    572     const_iterator &operator--() { --I; return *this; }
    573   };
    574 
    575   typedef std::reverse_iterator<iterator>       reverse_iterator;
    576   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
    577 
    578   // forward iterator creation methods.
    579 
    580   iterator begin() { return path.begin(); }
    581   iterator end() { return path.end(); }
    582 
    583   const_iterator begin() const { return path.begin(); }
    584   const_iterator end() const { return path.end(); }
    585 
    586   // reverse iterator creation methods.
    587   reverse_iterator rbegin()            { return reverse_iterator(end()); }
    588   const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
    589   reverse_iterator rend()              { return reverse_iterator(begin()); }
    590   const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
    591 
    592   void flattenLocations() {
    593     for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations();
    594   }
    595 
    596   void Profile(llvm::FoldingSetNodeID &ID) const;
    597 };
    598 
    599 } // end GR namespace
    600 
    601 } //end clang namespace
    602 
    603 #endif
    604