Home | History | Annotate | Download | only in Frontend
      1 //===--- DiagnosticRenderer.h - Diagnostic Pretty-Printing ------*- 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 is a utility class that provides support for pretty-printing of
     11 // diagnostics. It is used to implement the different code paths which require
     12 // such functionality in a consistent way.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #ifndef LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H
     17 #define LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H
     18 
     19 #include "clang/Basic/Diagnostic.h"
     20 #include "clang/Basic/LLVM.h"
     21 #include "clang/Basic/SourceLocation.h"
     22 #include "llvm/ADT/Optional.h"
     23 #include "llvm/ADT/PointerUnion.h"
     24 
     25 namespace clang {
     26 
     27 class DiagnosticOptions;
     28 class LangOptions;
     29 class SourceManager;
     30 
     31 typedef llvm::PointerUnion<const Diagnostic *,
     32                            const StoredDiagnostic *> DiagOrStoredDiag;
     33 
     34 /// \brief Class to encapsulate the logic for formatting a diagnostic message.
     35 ///
     36 /// Actual "printing" logic is implemented by subclasses.
     37 ///
     38 /// This class provides an interface for building and emitting
     39 /// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt
     40 /// Hints, and code snippets. In the presence of macros this involves
     41 /// a recursive process, synthesizing notes for each macro expansion.
     42 ///
     43 /// A brief worklist:
     44 /// FIXME: Sink the recursive printing of template instantiations into this
     45 /// class.
     46 class DiagnosticRenderer {
     47 protected:
     48   const LangOptions &LangOpts;
     49   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
     50 
     51   /// \brief The location of the previous diagnostic if known.
     52   ///
     53   /// This will be invalid in cases where there is no (known) previous
     54   /// diagnostic location, or that location itself is invalid or comes from
     55   /// a different source manager than SM.
     56   SourceLocation LastLoc;
     57 
     58   /// \brief The location of the last include whose stack was printed if known.
     59   ///
     60   /// Same restriction as LastLoc essentially, but tracking include stack
     61   /// root locations rather than diagnostic locations.
     62   SourceLocation LastIncludeLoc;
     63 
     64   /// \brief The level of the last diagnostic emitted.
     65   ///
     66   /// The level of the last diagnostic emitted. Used to detect level changes
     67   /// which change the amount of information displayed.
     68   DiagnosticsEngine::Level LastLevel;
     69 
     70   DiagnosticRenderer(const LangOptions &LangOpts,
     71                      DiagnosticOptions *DiagOpts);
     72 
     73   virtual ~DiagnosticRenderer();
     74 
     75   virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
     76                                      DiagnosticsEngine::Level Level,
     77                                      StringRef Message,
     78                                      ArrayRef<CharSourceRange> Ranges,
     79                                      const SourceManager *SM,
     80                                      DiagOrStoredDiag Info) = 0;
     81 
     82   virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
     83                                  DiagnosticsEngine::Level Level,
     84                                  ArrayRef<CharSourceRange> Ranges,
     85                                  const SourceManager &SM) = 0;
     86 
     87   virtual void emitCodeContext(SourceLocation Loc,
     88                                DiagnosticsEngine::Level Level,
     89                                SmallVectorImpl<CharSourceRange>& Ranges,
     90                                ArrayRef<FixItHint> Hints,
     91                                const SourceManager &SM) = 0;
     92 
     93   virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
     94                                    const SourceManager &SM) = 0;
     95   virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
     96                                   StringRef ModuleName,
     97                                   const SourceManager &SM) = 0;
     98   virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
     99                                           StringRef ModuleName,
    100                                           const SourceManager &SM) = 0;
    101 
    102   virtual void beginDiagnostic(DiagOrStoredDiag D,
    103                                DiagnosticsEngine::Level Level) {}
    104   virtual void endDiagnostic(DiagOrStoredDiag D,
    105                              DiagnosticsEngine::Level Level) {}
    106 
    107 
    108 private:
    109   void emitBasicNote(StringRef Message);
    110   void emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc,
    111                         DiagnosticsEngine::Level Level, const SourceManager &SM);
    112   void emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM);
    113   void emitImportStack(SourceLocation Loc, const SourceManager &SM);
    114   void emitImportStackRecursively(SourceLocation Loc, StringRef ModuleName,
    115                                   const SourceManager &SM);
    116   void emitModuleBuildStack(const SourceManager &SM);
    117   void emitCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
    118                  ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints,
    119                  const SourceManager &SM);
    120   void emitSingleMacroExpansion(SourceLocation Loc,
    121                                 DiagnosticsEngine::Level Level,
    122                                 ArrayRef<CharSourceRange> Ranges,
    123                                 const SourceManager &SM);
    124   void emitMacroExpansions(SourceLocation Loc,
    125                            DiagnosticsEngine::Level Level,
    126                            ArrayRef<CharSourceRange> Ranges,
    127                            ArrayRef<FixItHint> Hints,
    128                            const SourceManager &SM);
    129 public:
    130   /// \brief Emit a diagnostic.
    131   ///
    132   /// This is the primary entry point for emitting diagnostic messages.
    133   /// It handles formatting and rendering the message as well as any ancillary
    134   /// information needed based on macros whose expansions impact the
    135   /// diagnostic.
    136   ///
    137   /// \param Loc The location for this caret.
    138   /// \param Level The level of the diagnostic to be emitted.
    139   /// \param Message The diagnostic message to emit.
    140   /// \param Ranges The underlined ranges for this code snippet.
    141   /// \param FixItHints The FixIt hints active for this diagnostic.
    142   /// \param SM The SourceManager; will be null if the diagnostic came from the
    143   ///        frontend, thus \p Loc will be invalid.
    144   void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level,
    145                       StringRef Message, ArrayRef<CharSourceRange> Ranges,
    146                       ArrayRef<FixItHint> FixItHints,
    147                       const SourceManager *SM,
    148                       DiagOrStoredDiag D = (Diagnostic *)nullptr);
    149 
    150   void emitStoredDiagnostic(StoredDiagnostic &Diag);
    151 };
    152 
    153 /// Subclass of DiagnosticRender that turns all subdiagostics into explicit
    154 /// notes.  It is up to subclasses to further define the behavior.
    155 class DiagnosticNoteRenderer : public DiagnosticRenderer {
    156 public:
    157   DiagnosticNoteRenderer(const LangOptions &LangOpts,
    158                          DiagnosticOptions *DiagOpts)
    159     : DiagnosticRenderer(LangOpts, DiagOpts) {}
    160 
    161   ~DiagnosticNoteRenderer() override;
    162 
    163   void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
    164                            const SourceManager &SM) override;
    165 
    166   void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
    167                           StringRef ModuleName,
    168                           const SourceManager &SM) override;
    169 
    170   void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
    171                                   StringRef ModuleName,
    172                                   const SourceManager &SM) override;
    173 
    174   virtual void emitNote(SourceLocation Loc, StringRef Message,
    175                         const SourceManager *SM) = 0;
    176 };
    177 } // end clang namespace
    178 #endif
    179