Home | History | Annotate | Download | only in BugReporter
      1 //===---  BugReporter.h - Generate PathDiagnostics --------------*- 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 BugReporter, a utility class for generating
     11 //  PathDiagnostics for analyses based on ProgramState.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_CLANG_GR_BUGREPORTER
     16 #define LLVM_CLANG_GR_BUGREPORTER
     17 
     18 #include "clang/Basic/SourceLocation.h"
     19 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
     20 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
     21 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
     22 #include "llvm/ADT/FoldingSet.h"
     23 #include "llvm/ADT/ImmutableList.h"
     24 #include "llvm/ADT/ImmutableSet.h"
     25 #include "llvm/ADT/SmallSet.h"
     26 #include <list>
     27 
     28 namespace clang {
     29 
     30 class ASTContext;
     31 class DiagnosticsEngine;
     32 class Stmt;
     33 class ParentMap;
     34 
     35 namespace ento {
     36 
     37 class PathDiagnostic;
     38 class ExplodedNode;
     39 class ExplodedGraph;
     40 class BugReport;
     41 class BugReporter;
     42 class BugReporterContext;
     43 class ExprEngine;
     44 class BugType;
     45 
     46 //===----------------------------------------------------------------------===//
     47 // Interface for individual bug reports.
     48 //===----------------------------------------------------------------------===//
     49 
     50 /// This class provides an interface through which checkers can create
     51 /// individual bug reports.
     52 class BugReport {
     53 public:
     54   class NodeResolver {
     55   public:
     56     virtual ~NodeResolver() {}
     57     virtual const ExplodedNode*
     58             getOriginalNode(const ExplodedNode *N) = 0;
     59   };
     60 
     61   typedef const SourceRange *ranges_iterator;
     62   typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
     63   typedef SmallVector<StringRef, 2> ExtraTextList;
     64 
     65 protected:
     66   friend class BugReporter;
     67   friend class BugReportEquivClass;
     68 
     69   BugType& BT;
     70   std::string ShortDescription;
     71   std::string Description;
     72   PathDiagnosticLocation Location;
     73   const ExplodedNode *ErrorNode;
     74   SmallVector<SourceRange, 4> Ranges;
     75   ExtraTextList ExtraText;
     76 
     77   // Not the most efficient data structure, but we use an ImmutableList for the
     78   // Callbacks because it is safe to make additions to list during iteration.
     79   llvm::ImmutableList<BugReporterVisitor*>::Factory F;
     80   llvm::ImmutableList<BugReporterVisitor*> Callbacks;
     81   llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
     82 
     83 public:
     84   BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
     85     : BT(bt), Description(desc), ErrorNode(errornode),
     86       Callbacks(F.getEmptyList()) {}
     87 
     88   BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
     89             const ExplodedNode *errornode)
     90     : BT(bt), ShortDescription(shortDesc), Description(desc),
     91       ErrorNode(errornode), Callbacks(F.getEmptyList()) {}
     92 
     93   BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l)
     94     : BT(bt), Description(desc), Location(l), ErrorNode(0),
     95       Callbacks(F.getEmptyList()) {}
     96 
     97   virtual ~BugReport();
     98 
     99   const BugType& getBugType() const { return BT; }
    100   BugType& getBugType() { return BT; }
    101 
    102   const ExplodedNode *getErrorNode() const { return ErrorNode; }
    103 
    104   const StringRef getDescription() const { return Description; }
    105 
    106   const StringRef getShortDescription() const {
    107     return ShortDescription.empty() ? Description : ShortDescription;
    108   }
    109 
    110   /// \brief This allows for addition of meta data to the diagnostic.
    111   ///
    112   /// Currently, only the HTMLDiagnosticClient knows how to display it.
    113   void addExtraText(StringRef S) {
    114     ExtraText.push_back(S);
    115   }
    116 
    117   virtual const ExtraTextList &getExtraText() {
    118     return ExtraText;
    119   }
    120 
    121   /// \brief Return the "definitive" location of the reported bug.
    122   ///
    123   ///  While a bug can span an entire path, usually there is a specific
    124   ///  location that can be used to identify where the key issue occurred.
    125   ///  This location is used by clients rendering diagnostics.
    126   virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
    127 
    128   const Stmt *getStmt() const;
    129 
    130   /// \brief Add a range to a bug report.
    131   ///
    132   /// Ranges are used to highlight regions of interest in the source code.
    133   /// They should be at the same source code line as the BugReport location.
    134   /// By default, the source range of the statement corresponding to the error
    135   /// node will be used; add a single invalid range to specify absence of
    136   /// ranges.
    137   void addRange(SourceRange R) {
    138     assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
    139                            "to specify that the report does not have a range.");
    140     Ranges.push_back(R);
    141   }
    142 
    143   /// \brief Get the SourceRanges associated with the report.
    144   virtual std::pair<ranges_iterator, ranges_iterator> getRanges();
    145 
    146   /// \brief Add custom or predefined bug report visitors to this report.
    147   ///
    148   /// The visitors should be used when the default trace is not sufficient.
    149   /// For example, they allow constructing a more elaborate trace.
    150   /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(),
    151   /// registerFindLastStore(), registerNilReceiverVisitor(), and
    152   /// registerVarDeclsLastStore().
    153   void addVisitor(BugReporterVisitor *visitor);
    154 
    155 	/// Iterators through the custom diagnostic visitors.
    156   visitor_iterator visitor_begin() { return Callbacks.begin(); }
    157   visitor_iterator visitor_end() { return Callbacks.end(); }
    158 
    159   /// Profile to identify equivalent bug reports for error report coalescing.
    160   /// Reports are uniqued to ensure that we do not emit multiple diagnostics
    161   /// for each bug.
    162   virtual void Profile(llvm::FoldingSetNodeID& hash) const;
    163 };
    164 
    165 //===----------------------------------------------------------------------===//
    166 // BugTypes (collections of related reports).
    167 //===----------------------------------------------------------------------===//
    168 
    169 class BugReportEquivClass : public llvm::FoldingSetNode {
    170   /// List of *owned* BugReport objects.
    171   std::list<BugReport*> Reports;
    172 
    173   friend class BugReporter;
    174   void AddReport(BugReport* R) { Reports.push_back(R); }
    175 public:
    176   BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
    177   ~BugReportEquivClass();
    178 
    179   void Profile(llvm::FoldingSetNodeID& ID) const {
    180     assert(!Reports.empty());
    181     (*Reports.begin())->Profile(ID);
    182   }
    183 
    184   class iterator {
    185     std::list<BugReport*>::iterator impl;
    186   public:
    187     iterator(std::list<BugReport*>::iterator i) : impl(i) {}
    188     iterator &operator++() { ++impl; return *this; }
    189     bool operator==(const iterator &I) const { return I.impl == impl; }
    190     bool operator!=(const iterator &I) const { return I.impl != impl; }
    191     BugReport* operator*() const { return *impl; }
    192     BugReport* operator->() const { return *impl; }
    193   };
    194 
    195   class const_iterator {
    196     std::list<BugReport*>::const_iterator impl;
    197   public:
    198     const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
    199     const_iterator &operator++() { ++impl; return *this; }
    200     bool operator==(const const_iterator &I) const { return I.impl == impl; }
    201     bool operator!=(const const_iterator &I) const { return I.impl != impl; }
    202     const BugReport* operator*() const { return *impl; }
    203     const BugReport* operator->() const { return *impl; }
    204   };
    205 
    206   iterator begin() { return iterator(Reports.begin()); }
    207   iterator end() { return iterator(Reports.end()); }
    208 
    209   const_iterator begin() const { return const_iterator(Reports.begin()); }
    210   const_iterator end() const { return const_iterator(Reports.end()); }
    211 };
    212 
    213 //===----------------------------------------------------------------------===//
    214 // BugReporter and friends.
    215 //===----------------------------------------------------------------------===//
    216 
    217 class BugReporterData {
    218 public:
    219   virtual ~BugReporterData();
    220   virtual DiagnosticsEngine& getDiagnostic() = 0;
    221   virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0;
    222   virtual ASTContext &getASTContext() = 0;
    223   virtual SourceManager& getSourceManager() = 0;
    224 };
    225 
    226 /// BugReporter is a utility class for generating PathDiagnostics for analysis.
    227 /// It collects the BugReports and BugTypes and knows how to generate
    228 /// and flush the corresponding diagnostics.
    229 class BugReporter {
    230 public:
    231   enum Kind { BaseBRKind, GRBugReporterKind };
    232 
    233 private:
    234   typedef llvm::ImmutableSet<BugType*> BugTypesTy;
    235   BugTypesTy::Factory F;
    236   BugTypesTy BugTypes;
    237 
    238   const Kind kind;
    239   BugReporterData& D;
    240 
    241   /// Generate and flush the diagnostics for the given bug report.
    242   void FlushReport(BugReportEquivClass& EQ);
    243 
    244   /// The set of bug reports tracked by the BugReporter.
    245   llvm::FoldingSet<BugReportEquivClass> EQClasses;
    246   /// A vector of BugReports for tracking the allocated pointers and cleanup.
    247   std::vector<BugReportEquivClass *> EQClassesVector;
    248 
    249 protected:
    250   BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
    251                                             D(d) {}
    252 
    253 public:
    254   BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
    255                                     D(d) {}
    256   virtual ~BugReporter();
    257 
    258   /// \brief Generate and flush diagnostics for all bug reports.
    259   void FlushReports();
    260 
    261   Kind getKind() const { return kind; }
    262 
    263   DiagnosticsEngine& getDiagnostic() {
    264     return D.getDiagnostic();
    265   }
    266 
    267   PathDiagnosticConsumer* getPathDiagnosticConsumer() {
    268     return D.getPathDiagnosticConsumer();
    269   }
    270 
    271   /// \brief Iterator over the set of BugTypes tracked by the BugReporter.
    272   typedef BugTypesTy::iterator iterator;
    273   iterator begin() { return BugTypes.begin(); }
    274   iterator end() { return BugTypes.end(); }
    275 
    276   /// \brief Iterator over the set of BugReports tracked by the BugReporter.
    277   typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
    278   EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
    279   EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
    280 
    281   ASTContext &getContext() { return D.getASTContext(); }
    282 
    283   SourceManager& getSourceManager() { return D.getSourceManager(); }
    284 
    285   virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
    286         SmallVectorImpl<BugReport *> &bugReports) {}
    287 
    288   void Register(BugType *BT);
    289 
    290   /// \brief Add the given report to the set of reports tracked by BugReporter.
    291   ///
    292   /// The reports are usually generated by the checkers. Further, they are
    293   /// folded based on the profile value, which is done to coalesce similar
    294   /// reports.
    295   void EmitReport(BugReport *R);
    296 
    297   void EmitBasicReport(StringRef BugName, StringRef BugStr,
    298                        PathDiagnosticLocation Loc,
    299                        SourceRange* RangeBeg, unsigned NumRanges);
    300 
    301   void EmitBasicReport(StringRef BugName, StringRef BugCategory,
    302                        StringRef BugStr, PathDiagnosticLocation Loc,
    303                        SourceRange* RangeBeg, unsigned NumRanges);
    304 
    305 
    306   void EmitBasicReport(StringRef BugName, StringRef BugStr,
    307                        PathDiagnosticLocation Loc) {
    308     EmitBasicReport(BugName, BugStr, Loc, 0, 0);
    309   }
    310 
    311   void EmitBasicReport(StringRef BugName, StringRef BugCategory,
    312                        StringRef BugStr, PathDiagnosticLocation Loc) {
    313     EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
    314   }
    315 
    316   void EmitBasicReport(StringRef BugName, StringRef BugStr,
    317                        PathDiagnosticLocation Loc, SourceRange R) {
    318     EmitBasicReport(BugName, BugStr, Loc, &R, 1);
    319   }
    320 
    321   void EmitBasicReport(StringRef BugName, StringRef Category,
    322                        StringRef BugStr, PathDiagnosticLocation Loc,
    323                        SourceRange R) {
    324     EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
    325   }
    326 
    327   static bool classof(const BugReporter* R) { return true; }
    328 
    329 private:
    330   llvm::StringMap<BugType *> StrBugTypes;
    331 
    332   /// \brief Returns a BugType that is associated with the given name and
    333   /// category.
    334   BugType *getBugTypeForName(StringRef name, StringRef category);
    335 };
    336 
    337 // FIXME: Get rid of GRBugReporter.  It's the wrong abstraction.
    338 class GRBugReporter : public BugReporter {
    339   ExprEngine& Eng;
    340   llvm::SmallSet<SymbolRef, 10> NotableSymbols;
    341 public:
    342   GRBugReporter(BugReporterData& d, ExprEngine& eng)
    343     : BugReporter(d, GRBugReporterKind), Eng(eng) {}
    344 
    345   virtual ~GRBugReporter();
    346 
    347   /// getEngine - Return the analysis engine used to analyze a given
    348   ///  function or method.
    349   ExprEngine &getEngine() { return Eng; }
    350 
    351   /// getGraph - Get the exploded graph created by the analysis engine
    352   ///  for the analyzed method or function.
    353   ExplodedGraph &getGraph();
    354 
    355   /// getStateManager - Return the state manager used by the analysis
    356   ///  engine.
    357   ProgramStateManager &getStateManager();
    358 
    359   virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
    360                      SmallVectorImpl<BugReport*> &bugReports);
    361 
    362   void addNotableSymbol(SymbolRef Sym) {
    363     NotableSymbols.insert(Sym);
    364   }
    365 
    366   bool isNotable(SymbolRef Sym) const {
    367     return (bool) NotableSymbols.count(Sym);
    368   }
    369 
    370   /// classof - Used by isa<>, cast<>, and dyn_cast<>.
    371   static bool classof(const BugReporter* R) {
    372     return R->getKind() == GRBugReporterKind;
    373   }
    374 };
    375 
    376 class BugReporterContext {
    377   GRBugReporter &BR;
    378 public:
    379   BugReporterContext(GRBugReporter& br) : BR(br) {}
    380 
    381   virtual ~BugReporterContext() {}
    382 
    383   GRBugReporter& getBugReporter() { return BR; }
    384 
    385   ExplodedGraph &getGraph() { return BR.getGraph(); }
    386 
    387   void addNotableSymbol(SymbolRef Sym) {
    388     // FIXME: For now forward to GRBugReporter.
    389     BR.addNotableSymbol(Sym);
    390   }
    391 
    392   bool isNotable(SymbolRef Sym) const {
    393     // FIXME: For now forward to GRBugReporter.
    394     return BR.isNotable(Sym);
    395   }
    396 
    397   ProgramStateManager& getStateManager() {
    398     return BR.getStateManager();
    399   }
    400 
    401   SValBuilder& getSValBuilder() {
    402     return getStateManager().getSValBuilder();
    403   }
    404 
    405   ASTContext &getASTContext() {
    406     return BR.getContext();
    407   }
    408 
    409   SourceManager& getSourceManager() {
    410     return BR.getSourceManager();
    411   }
    412 
    413   virtual BugReport::NodeResolver& getNodeResolver() = 0;
    414 };
    415 
    416 } // end GR namespace
    417 
    418 } // end clang namespace
    419 
    420 #endif
    421