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
25namespace clang {
26
27class DiagnosticOptions;
28class LangOptions;
29class SourceManager;
30
31typedef 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.
46class DiagnosticRenderer {
47protected:
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
108private:
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);
129public:
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.
155class DiagnosticNoteRenderer : public DiagnosticRenderer {
156public:
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