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/ilist.h"
     24 #include "llvm/ADT/ilist_node.h"
     25 #include "llvm/ADT/ImmutableSet.h"
     26 #include "llvm/ADT/DenseSet.h"
     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 : public llvm::ilist_node<BugReport> {
     53 public:
     54   class NodeResolver {
     55     virtual void anchor();
     56   public:
     57     virtual ~NodeResolver() {}
     58     virtual const ExplodedNode*
     59             getOriginalNode(const ExplodedNode *N) = 0;
     60   };
     61 
     62   typedef const SourceRange *ranges_iterator;
     63   typedef SmallVector<BugReporterVisitor *, 8> VisitorList;
     64   typedef VisitorList::iterator visitor_iterator;
     65   typedef SmallVector<StringRef, 2> ExtraTextList;
     66 
     67 protected:
     68   friend class BugReporter;
     69   friend class BugReportEquivClass;
     70 
     71   BugType& BT;
     72   const Decl *DeclWithIssue;
     73   std::string ShortDescription;
     74   std::string Description;
     75   PathDiagnosticLocation Location;
     76   PathDiagnosticLocation UniqueingLocation;
     77   const ExplodedNode *ErrorNode;
     78   SmallVector<SourceRange, 4> Ranges;
     79   ExtraTextList ExtraText;
     80 
     81   typedef llvm::DenseSet<SymbolRef> Symbols;
     82   typedef llvm::DenseSet<const MemRegion *> Regions;
     83 
     84   /// A set of symbols that are registered with this report as being
     85   /// "interesting", and thus used to help decide which diagnostics
     86   /// to include when constructing the final path diagnostic.
     87   Symbols interestingSymbols;
     88 
     89   /// A set of regions that are registered with this report as being
     90   /// "interesting", and thus used to help decide which diagnostics
     91   /// to include when constructing the final path diagnostic.
     92   Regions interestingRegions;
     93 
     94   /// A set of custom visitors which generate "event" diagnostics at
     95   /// interesting points in the path.
     96   VisitorList Callbacks;
     97 
     98   /// Used for ensuring the visitors are only added once.
     99   llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
    100 
    101   /// Used for clients to tell if the report's configuration has changed
    102   /// since the last time they checked.
    103   unsigned ConfigurationChangeToken;
    104 
    105 public:
    106   BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
    107     : BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode),
    108       ConfigurationChangeToken(0) {}
    109 
    110   BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
    111             const ExplodedNode *errornode)
    112     : BT(bt), DeclWithIssue(0), ShortDescription(shortDesc), Description(desc),
    113       ErrorNode(errornode), ConfigurationChangeToken(0) {}
    114 
    115   BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l)
    116     : BT(bt), DeclWithIssue(0), Description(desc), Location(l), ErrorNode(0),
    117       ConfigurationChangeToken(0) {}
    118 
    119   /// \brief Create a BugReport with a custom uniqueing location.
    120   ///
    121   /// The reports that have the same report location, description, bug type, and
    122   /// ranges are uniqued - only one of the equivalent reports will be presented
    123   /// to the user. This method allows to rest the location which should be used
    124   /// for uniquing reports. For example, memory leaks checker, could set this to
    125   /// the allocation site, rather then the location where the bug is reported.
    126   BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode,
    127             PathDiagnosticLocation LocationToUnique)
    128     : BT(bt), DeclWithIssue(0), Description(desc),
    129       UniqueingLocation(LocationToUnique),
    130       ErrorNode(errornode), ConfigurationChangeToken(0) {}
    131 
    132   virtual ~BugReport();
    133 
    134   const BugType& getBugType() const { return BT; }
    135   BugType& getBugType() { return BT; }
    136 
    137   const ExplodedNode *getErrorNode() const { return ErrorNode; }
    138 
    139   const StringRef getDescription() const { return Description; }
    140 
    141   const StringRef getShortDescription() const {
    142     return ShortDescription.empty() ? Description : ShortDescription;
    143   }
    144 
    145   void markInteresting(SymbolRef sym);
    146   void markInteresting(const MemRegion *R);
    147   void markInteresting(SVal V);
    148 
    149   bool isInteresting(SymbolRef sym) const;
    150   bool isInteresting(const MemRegion *R) const;
    151   bool isInteresting(SVal V) const;
    152 
    153   unsigned getConfigurationChangeToken() const {
    154     return ConfigurationChangeToken;
    155   }
    156 
    157   /// Return the canonical declaration, be it a method or class, where
    158   /// this issue semantically occurred.
    159   const Decl *getDeclWithIssue() const;
    160 
    161   /// Specifically set the Decl where an issue occurred.  This isn't necessary
    162   /// for BugReports that cover a path as it will be automatically inferred.
    163   void setDeclWithIssue(const Decl *declWithIssue) {
    164     DeclWithIssue = declWithIssue;
    165   }
    166 
    167   /// \brief This allows for addition of meta data to the diagnostic.
    168   ///
    169   /// Currently, only the HTMLDiagnosticClient knows how to display it.
    170   void addExtraText(StringRef S) {
    171     ExtraText.push_back(S);
    172   }
    173 
    174   virtual const ExtraTextList &getExtraText() {
    175     return ExtraText;
    176   }
    177 
    178   /// \brief Return the "definitive" location of the reported bug.
    179   ///
    180   ///  While a bug can span an entire path, usually there is a specific
    181   ///  location that can be used to identify where the key issue occurred.
    182   ///  This location is used by clients rendering diagnostics.
    183   virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
    184 
    185   const Stmt *getStmt() const;
    186 
    187   /// \brief Add a range to a bug report.
    188   ///
    189   /// Ranges are used to highlight regions of interest in the source code.
    190   /// They should be at the same source code line as the BugReport location.
    191   /// By default, the source range of the statement corresponding to the error
    192   /// node will be used; add a single invalid range to specify absence of
    193   /// ranges.
    194   void addRange(SourceRange R) {
    195     assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
    196                            "to specify that the report does not have a range.");
    197     Ranges.push_back(R);
    198   }
    199 
    200   /// \brief Get the SourceRanges associated with the report.
    201   virtual std::pair<ranges_iterator, ranges_iterator> getRanges();
    202 
    203   /// \brief Add custom or predefined bug report visitors to this report.
    204   ///
    205   /// The visitors should be used when the default trace is not sufficient.
    206   /// For example, they allow constructing a more elaborate trace.
    207   /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(),
    208   /// registerFindLastStore(), registerNilReceiverVisitor(), and
    209   /// registerVarDeclsLastStore().
    210   void addVisitor(BugReporterVisitor *visitor);
    211 
    212 	/// Iterators through the custom diagnostic visitors.
    213   visitor_iterator visitor_begin() { return Callbacks.begin(); }
    214   visitor_iterator visitor_end() { return Callbacks.end(); }
    215 
    216   /// Profile to identify equivalent bug reports for error report coalescing.
    217   /// Reports are uniqued to ensure that we do not emit multiple diagnostics
    218   /// for each bug.
    219   virtual void Profile(llvm::FoldingSetNodeID& hash) const;
    220 };
    221 
    222 } // end ento namespace
    223 } // end clang namespace
    224 
    225 namespace llvm {
    226   template<> struct ilist_traits<clang::ento::BugReport>
    227     : public ilist_default_traits<clang::ento::BugReport> {
    228     clang::ento::BugReport *createSentinel() const {
    229       return static_cast<clang::ento::BugReport *>(&Sentinel);
    230     }
    231     void destroySentinel(clang::ento::BugReport *) const {}
    232 
    233     clang::ento::BugReport *provideInitialHead() const {
    234       return createSentinel();
    235     }
    236     clang::ento::BugReport *ensureHead(clang::ento::BugReport *) const {
    237       return createSentinel();
    238     }
    239   private:
    240     mutable ilist_half_node<clang::ento::BugReport> Sentinel;
    241   };
    242 }
    243 
    244 namespace clang {
    245 namespace ento {
    246 
    247 //===----------------------------------------------------------------------===//
    248 // BugTypes (collections of related reports).
    249 //===----------------------------------------------------------------------===//
    250 
    251 class BugReportEquivClass : public llvm::FoldingSetNode {
    252   /// List of *owned* BugReport objects.
    253   llvm::ilist<BugReport> Reports;
    254 
    255   friend class BugReporter;
    256   void AddReport(BugReport* R) { Reports.push_back(R); }
    257 public:
    258   BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
    259   ~BugReportEquivClass();
    260 
    261   void Profile(llvm::FoldingSetNodeID& ID) const {
    262     assert(!Reports.empty());
    263     Reports.front().Profile(ID);
    264   }
    265 
    266   typedef llvm::ilist<BugReport>::iterator iterator;
    267   typedef llvm::ilist<BugReport>::const_iterator const_iterator;
    268 
    269   iterator begin() { return Reports.begin(); }
    270   iterator end() { return Reports.end(); }
    271 
    272   const_iterator begin() const { return Reports.begin(); }
    273   const_iterator end() const { return Reports.end(); }
    274 };
    275 
    276 //===----------------------------------------------------------------------===//
    277 // BugReporter and friends.
    278 //===----------------------------------------------------------------------===//
    279 
    280 class BugReporterData {
    281 public:
    282   virtual ~BugReporterData();
    283   virtual DiagnosticsEngine& getDiagnostic() = 0;
    284   virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0;
    285   virtual ASTContext &getASTContext() = 0;
    286   virtual SourceManager& getSourceManager() = 0;
    287 };
    288 
    289 /// BugReporter is a utility class for generating PathDiagnostics for analysis.
    290 /// It collects the BugReports and BugTypes and knows how to generate
    291 /// and flush the corresponding diagnostics.
    292 class BugReporter {
    293 public:
    294   enum Kind { BaseBRKind, GRBugReporterKind };
    295 
    296 private:
    297   typedef llvm::ImmutableSet<BugType*> BugTypesTy;
    298   BugTypesTy::Factory F;
    299   BugTypesTy BugTypes;
    300 
    301   const Kind kind;
    302   BugReporterData& D;
    303 
    304   /// Generate and flush the diagnostics for the given bug report.
    305   void FlushReport(BugReportEquivClass& EQ);
    306 
    307   /// The set of bug reports tracked by the BugReporter.
    308   llvm::FoldingSet<BugReportEquivClass> EQClasses;
    309   /// A vector of BugReports for tracking the allocated pointers and cleanup.
    310   std::vector<BugReportEquivClass *> EQClassesVector;
    311 
    312 protected:
    313   BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
    314                                             D(d) {}
    315 
    316 public:
    317   BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
    318                                     D(d) {}
    319   virtual ~BugReporter();
    320 
    321   /// \brief Generate and flush diagnostics for all bug reports.
    322   void FlushReports();
    323 
    324   Kind getKind() const { return kind; }
    325 
    326   DiagnosticsEngine& getDiagnostic() {
    327     return D.getDiagnostic();
    328   }
    329 
    330   PathDiagnosticConsumer* getPathDiagnosticConsumer() {
    331     return D.getPathDiagnosticConsumer();
    332   }
    333 
    334   /// \brief Iterator over the set of BugTypes tracked by the BugReporter.
    335   typedef BugTypesTy::iterator iterator;
    336   iterator begin() { return BugTypes.begin(); }
    337   iterator end() { return BugTypes.end(); }
    338 
    339   /// \brief Iterator over the set of BugReports tracked by the BugReporter.
    340   typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
    341   EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
    342   EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
    343 
    344   ASTContext &getContext() { return D.getASTContext(); }
    345 
    346   SourceManager& getSourceManager() { return D.getSourceManager(); }
    347 
    348   virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
    349         SmallVectorImpl<BugReport *> &bugReports) {}
    350 
    351   void Register(BugType *BT);
    352 
    353   /// \brief Add the given report to the set of reports tracked by BugReporter.
    354   ///
    355   /// The reports are usually generated by the checkers. Further, they are
    356   /// folded based on the profile value, which is done to coalesce similar
    357   /// reports.
    358   void EmitReport(BugReport *R);
    359 
    360   void EmitBasicReport(const Decl *DeclWithIssue,
    361                        StringRef BugName, StringRef BugCategory,
    362                        StringRef BugStr, PathDiagnosticLocation Loc,
    363                        SourceRange* RangeBeg, unsigned NumRanges);
    364 
    365   void EmitBasicReport(const Decl *DeclWithIssue,
    366                        StringRef BugName, StringRef BugCategory,
    367                        StringRef BugStr, PathDiagnosticLocation Loc) {
    368     EmitBasicReport(DeclWithIssue, BugName, BugCategory, BugStr, Loc, 0, 0);
    369   }
    370 
    371   void EmitBasicReport(const Decl *DeclWithIssue,
    372                        StringRef BugName, StringRef Category,
    373                        StringRef BugStr, PathDiagnosticLocation Loc,
    374                        SourceRange R) {
    375     EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1);
    376   }
    377 
    378   static bool classof(const BugReporter* R) { return true; }
    379 
    380 private:
    381   llvm::StringMap<BugType *> StrBugTypes;
    382 
    383   /// \brief Returns a BugType that is associated with the given name and
    384   /// category.
    385   BugType *getBugTypeForName(StringRef name, StringRef category);
    386 };
    387 
    388 // FIXME: Get rid of GRBugReporter.  It's the wrong abstraction.
    389 class GRBugReporter : public BugReporter {
    390   ExprEngine& Eng;
    391 public:
    392   GRBugReporter(BugReporterData& d, ExprEngine& eng)
    393     : BugReporter(d, GRBugReporterKind), Eng(eng) {}
    394 
    395   virtual ~GRBugReporter();
    396 
    397   /// getEngine - Return the analysis engine used to analyze a given
    398   ///  function or method.
    399   ExprEngine &getEngine() { return Eng; }
    400 
    401   /// getGraph - Get the exploded graph created by the analysis engine
    402   ///  for the analyzed method or function.
    403   ExplodedGraph &getGraph();
    404 
    405   /// getStateManager - Return the state manager used by the analysis
    406   ///  engine.
    407   ProgramStateManager &getStateManager();
    408 
    409   virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
    410                      SmallVectorImpl<BugReport*> &bugReports);
    411 
    412   /// classof - Used by isa<>, cast<>, and dyn_cast<>.
    413   static bool classof(const BugReporter* R) {
    414     return R->getKind() == GRBugReporterKind;
    415   }
    416 };
    417 
    418 class BugReporterContext {
    419   virtual void anchor();
    420   GRBugReporter &BR;
    421 public:
    422   BugReporterContext(GRBugReporter& br) : BR(br) {}
    423 
    424   virtual ~BugReporterContext() {}
    425 
    426   GRBugReporter& getBugReporter() { return BR; }
    427 
    428   ExplodedGraph &getGraph() { return BR.getGraph(); }
    429 
    430   ProgramStateManager& getStateManager() {
    431     return BR.getStateManager();
    432   }
    433 
    434   SValBuilder& getSValBuilder() {
    435     return getStateManager().getSValBuilder();
    436   }
    437 
    438   ASTContext &getASTContext() {
    439     return BR.getContext();
    440   }
    441 
    442   SourceManager& getSourceManager() {
    443     return BR.getSourceManager();
    444   }
    445 
    446   virtual BugReport::NodeResolver& getNodeResolver() = 0;
    447 };
    448 
    449 } // end GR namespace
    450 
    451 } // end clang namespace
    452 
    453 #endif
    454