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