summaryrefslogtreecommitdiff
path: root/include/clang/Frontend/DiagnosticRenderer.h
blob: b939ebe979e7118f2dbf07327d000376568b7959 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//===- DiagnosticRenderer.h - Diagnostic Pretty-Printing --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is a utility class that provides support for pretty-printing of
// diagnostics. It is used to implement the different code paths which require
// such functionality in a consistent way.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H
#define LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringRef.h"

namespace clang {

class LangOptions;
class SourceManager;

using DiagOrStoredDiag =
    llvm::PointerUnion<const Diagnostic *, const StoredDiagnostic *>;

/// Class to encapsulate the logic for formatting a diagnostic message.
///
/// Actual "printing" logic is implemented by subclasses.
///
/// This class provides an interface for building and emitting
/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt
/// Hints, and code snippets. In the presence of macros this involves
/// a recursive process, synthesizing notes for each macro expansion.
///
/// A brief worklist:
/// FIXME: Sink the recursive printing of template instantiations into this
/// class.
class DiagnosticRenderer {
protected:
  const LangOptions &LangOpts;
  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;

  /// The location of the previous diagnostic if known.
  ///
  /// This will be invalid in cases where there is no (known) previous
  /// diagnostic location, or that location itself is invalid or comes from
  /// a different source manager than SM.
  SourceLocation LastLoc;

  /// The location of the last include whose stack was printed if known.
  ///
  /// Same restriction as LastLoc essentially, but tracking include stack
  /// root locations rather than diagnostic locations.
  SourceLocation LastIncludeLoc;

  /// The level of the last diagnostic emitted.
  ///
  /// The level of the last diagnostic emitted. Used to detect level changes
  /// which change the amount of information displayed.
  DiagnosticsEngine::Level LastLevel = DiagnosticsEngine::Ignored;

  DiagnosticRenderer(const LangOptions &LangOpts,
                     DiagnosticOptions *DiagOpts);

  virtual ~DiagnosticRenderer();

  virtual void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
                                     DiagnosticsEngine::Level Level,
                                     StringRef Message,
                                     ArrayRef<CharSourceRange> Ranges,
                                     DiagOrStoredDiag Info) = 0;

  virtual void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
                                 DiagnosticsEngine::Level Level,
                                 ArrayRef<CharSourceRange> Ranges) = 0;

  virtual void emitCodeContext(FullSourceLoc Loc,
                               DiagnosticsEngine::Level Level,
                               SmallVectorImpl<CharSourceRange> &Ranges,
                               ArrayRef<FixItHint> Hints) = 0;

  virtual void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) = 0;
  virtual void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                                  StringRef ModuleName) = 0;
  virtual void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                                          StringRef ModuleName) = 0;

  virtual void beginDiagnostic(DiagOrStoredDiag D,
                               DiagnosticsEngine::Level Level) {}
  virtual void endDiagnostic(DiagOrStoredDiag D,
                             DiagnosticsEngine::Level Level) {}

private:
  void emitBasicNote(StringRef Message);
  void emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
                        DiagnosticsEngine::Level Level);
  void emitIncludeStackRecursively(FullSourceLoc Loc);
  void emitImportStack(FullSourceLoc Loc);
  void emitImportStackRecursively(FullSourceLoc Loc, StringRef ModuleName);
  void emitModuleBuildStack(const SourceManager &SM);
  void emitCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
                 ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints);
  void emitSingleMacroExpansion(FullSourceLoc Loc,
                                DiagnosticsEngine::Level Level,
                                ArrayRef<CharSourceRange> Ranges);
  void emitMacroExpansions(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
                           ArrayRef<CharSourceRange> Ranges,
                           ArrayRef<FixItHint> Hints);

public:
  /// Emit a diagnostic.
  ///
  /// This is the primary entry point for emitting diagnostic messages.
  /// It handles formatting and rendering the message as well as any ancillary
  /// information needed based on macros whose expansions impact the
  /// diagnostic.
  ///
  /// \param Loc The location for this caret.
  /// \param Level The level of the diagnostic to be emitted.
  /// \param Message The diagnostic message to emit.
  /// \param Ranges The underlined ranges for this code snippet.
  /// \param FixItHints The FixIt hints active for this diagnostic.
  void emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
                      StringRef Message, ArrayRef<CharSourceRange> Ranges,
                      ArrayRef<FixItHint> FixItHints,
                      DiagOrStoredDiag D = (Diagnostic *)nullptr);

  void emitStoredDiagnostic(StoredDiagnostic &Diag);
};

/// Subclass of DiagnosticRender that turns all subdiagostics into explicit
/// notes.  It is up to subclasses to further define the behavior.
class DiagnosticNoteRenderer : public DiagnosticRenderer {
public:
  DiagnosticNoteRenderer(const LangOptions &LangOpts,
                         DiagnosticOptions *DiagOpts)
      : DiagnosticRenderer(LangOpts, DiagOpts) {}

  ~DiagnosticNoteRenderer() override;

  void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override;

  void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                          StringRef ModuleName) override;

  void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                                  StringRef ModuleName) override;

  virtual void emitNote(FullSourceLoc Loc, StringRef Message) = 0;
};

} // namespace clang

#endif // LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H