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