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 
beginDiagnostic(DiagOrStoredDiag D,DiagnosticsEngine::Level Level)102   virtual void beginDiagnostic(DiagOrStoredDiag D,
103                                DiagnosticsEngine::Level Level) {}
endDiagnostic(DiagOrStoredDiag D,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:
DiagnosticNoteRenderer(const LangOptions & LangOpts,DiagnosticOptions * DiagOpts)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