nixd
Loading...
Searching...
No Matches
Diagnostic.h
Go to the documentation of this file.
1/// Diagnostic.h, diagnostic types and definitions
2///
3/// Diagnostics are structures with a main message,
4/// and optionally some additional information (body).
5///
6/// For diagnostics with a body,
7/// they may need a special overrided function to format the message.
8///
9#pragma once
10
11#include "Range.h"
12
13#include <cassert>
14#include <optional>
15#include <string>
16#include <utility>
17#include <vector>
18
19namespace nixf {
20
21/// Remove the text at `OldRange`, and replace it as `NewText`
22/// Special cases:
23/// 1. Insertions: special `OldRange` that `Begin` == `End`.
24/// 2. Removals: empty `NewText`.
25class TextEdit {
26 LexerCursorRange OldRange;
27 std::string NewText;
28
29public:
30 TextEdit(LexerCursorRange OldRange, std::string NewText)
31 : OldRange(OldRange), NewText(std::move(NewText)) {
32 assert(OldRange.lCur() != OldRange.rCur() || !this->NewText.empty());
33 }
34
35 static TextEdit mkInsertion(LexerCursor P, std::string NewText) {
36 return {{P, P}, std::move(NewText)};
37 }
38
39 static TextEdit mkRemoval(LexerCursorRange RemovingRange) {
40 return {RemovingRange, ""};
41 }
42
43 [[nodiscard]] bool isReplace() const {
44 return !isRemoval() && !isInsertion();
45 }
46
47 [[nodiscard]] bool isRemoval() const { return NewText.empty(); }
48
49 [[nodiscard]] bool isInsertion() const {
50 return OldRange.lCur() == OldRange.rCur();
51 }
52
53 [[nodiscard]] LexerCursorRange oldRange() const { return OldRange; }
54 [[nodiscard]] std::string_view newText() const { return NewText; }
55};
56
57class Fix {
58 std::vector<TextEdit> Edits;
59 std::string Message;
60
61public:
62 Fix(std::vector<TextEdit> Edits, std::string Message)
63 : Edits(std::move(Edits)), Message(std::move(Message)) {}
64
65 Fix &edit(TextEdit Edit) {
66 Edits.emplace_back(std::move(Edit));
67 return *this;
68 }
69
70 [[nodiscard]] const std::vector<TextEdit> &edits() const { return Edits; }
71 [[nodiscard]] const std::string &message() const { return Message; }
72};
73
74enum class DiagnosticTag {
75 Faded,
76 Striked,
77};
78
80public:
81 [[nodiscard]] virtual const char *message() const = 0;
82
83 virtual ~PartialDiagnostic() = default;
84
85 PartialDiagnostic &operator<<(std::string Var) {
86 Args.emplace_back(std::move(Var));
87 return *this;
88 }
89
90 [[nodiscard]] std::string format() const;
91
92 [[nodiscard]] const std::vector<std::string> &args() const { return Args; }
93
94 std::vector<std::string> &args() { return Args; }
95
96 void tag(DiagnosticTag Tag) { Tags.push_back(Tag); }
97
98 [[nodiscard]] const std::vector<DiagnosticTag> &tags() const { return Tags; }
99
100 [[nodiscard]] LexerCursorRange range() const { return Range; }
101
102protected:
103 PartialDiagnostic() = default;
104
105 PartialDiagnostic(LexerCursorRange Range) : Range(Range) {}
106
107private:
108 std::vector<DiagnosticTag> Tags;
109 std::vector<std::string> Args;
110 /// Location of this diagnostic
111 LexerCursorRange Range;
112};
113
114class Note : public PartialDiagnostic {
115public:
116 /// Internal kind
117 enum NoteKind {
118#define DIAG_NOTE(SNAME, CNAME, MESSAGE) NK_##CNAME,
119#include "NoteKinds.inc"
120#undef DIAG_NOTE
121 };
122
124 : PartialDiagnostic(Range), Kind(Kind) {}
125
126 template <class T> PartialDiagnostic &operator<<(const T &Var) {
127 args().push_back(Var);
128 return *this;
129 }
130
131 [[nodiscard]] static const char *sname(NoteKind Kind);
132
133 [[nodiscard]] virtual const char *sname() const { return sname(kind()); }
134
135 [[nodiscard]] NoteKind kind() const { return Kind; }
136
137 [[nodiscard]] static const char *message(NoteKind Kind);
138
139 [[nodiscard]] const char *message() const override { return message(kind()); }
140
141private:
142 NoteKind Kind;
143};
144
145/// The super class for all diagnostics.
146/// concret diagnostic types are defined in Diagnostic*.inc
148public:
149 /// Each diagnostic contains a severity field,
150 /// should be "Fatal", "Error" or "Warning"
151 /// this will affect the eval process.
152 ///
153 /// "Warning" -- just a warning.
154 enum Severity {
155 /// shouldn't eval the code, e.g. parsing error.
157 /// trigger an error in nix, but we can recover & eval the code.
159 /// A warning.
161 /// An information.
163
164 /// A hint. Hints are usually not rendered directly in some editor GUI
165 /// So this is suitable for liveness analysis results.
166 /// For example, "unused xxx"
168 };
169
170 /// Internal kind
171#include "DiagnosticEnum.h"
172
173 Diagnostic(DiagnosticKind Kind, LexerCursorRange Range)
174 : PartialDiagnostic(Range), Kind(Kind) {}
175
176 [[nodiscard]] DiagnosticKind kind() const { return Kind; };
177
178 [[nodiscard]] static Severity severity(DiagnosticKind Kind);
179
180 [[nodiscard]] static const char *message(DiagnosticKind Kind);
181
182 [[nodiscard]] const char *message() const override { return message(kind()); }
183
184 /// Short name, switch name.
185 /// There might be a human readable short name that controls the diagnostic
186 /// For example, one may pass -Wno-dup-formal to suppress duplicated formals.
187 /// A special case for parsing errors, generated from bison
188 /// have the sname "bison"
189 [[nodiscard]] static const char *sname(DiagnosticKind Kind);
190
191 /// \brief Parse diagnostic "cname" to diagnostic id
192 [[nodiscard]] static std::optional<Diagnostic::DiagnosticKind>
193 parseKind(std::string_view SName);
194
195 [[nodiscard]] virtual const char *sname() const { return sname(kind()); }
196
198 return Notes.emplace_back(Kind, Range);
199 }
200
201 [[nodiscard]] const std::vector<Note> &notes() const { return Notes; }
202
203 Fix &fix(std::string Message) {
204 return Fixes.emplace_back(Fix{{}, std::move(Message)});
205 }
206
207 [[nodiscard]] const std::vector<Fix> &fixes() const { return Fixes; }
208
209private:
210 DiagnosticKind Kind;
211
212 std::vector<Note> Notes;
213 std::vector<Fix> Fixes;
214};
215
216} // namespace nixf
static std::optional< Diagnostic::DiagnosticKind > parseKind(std::string_view SName)
Parse diagnostic "cname" to diagnostic id.
@ DS_Warning
A warning.
Definition Diagnostic.h:160
@ DS_Fatal
shouldn't eval the code, e.g. parsing error.
Definition Diagnostic.h:156
@ DS_Info
An information.
Definition Diagnostic.h:162
@ DS_Error
trigger an error in nix, but we can recover & eval the code.
Definition Diagnostic.h:158
Diagnostic(DiagnosticKind Kind, LexerCursorRange Range)
Internal kind.
Definition Diagnostic.h:173
Note & note(Note::NoteKind Kind, LexerCursorRange Range)
Definition Diagnostic.h:197
virtual const char * sname() const
Definition Diagnostic.h:195
static const char * message(DiagnosticKind Kind)
DiagnosticKind kind() const
Definition Diagnostic.h:176
Fix & fix(std::string Message)
Definition Diagnostic.h:203
const char * message() const override
Definition Diagnostic.h:182
static const char * sname(DiagnosticKind Kind)
const std::vector< Fix > & fixes() const
Definition Diagnostic.h:207
const std::vector< Note > & notes() const
Definition Diagnostic.h:201
static Severity severity(DiagnosticKind Kind)
Fix(std::vector< TextEdit > Edits, std::string Message)
Definition Diagnostic.h:62
const std::vector< TextEdit > & edits() const
Definition Diagnostic.h:70
const std::string & message() const
Definition Diagnostic.h:71
Fix & edit(TextEdit Edit)
Definition Diagnostic.h:65
LexerCursor lCur() const
Definition Range.h:116
LexerCursor rCur() const
Definition Range.h:117
A point in the source file.
Definition Range.h:57
const char * message() const override
Definition Diagnostic.h:139
NoteKind kind() const
Definition Diagnostic.h:135
PartialDiagnostic & operator<<(const T &Var)
Definition Diagnostic.h:126
Note(NoteKind Kind, LexerCursorRange Range)
Definition Diagnostic.h:123
virtual const char * sname() const
Definition Diagnostic.h:133
NoteKind
Internal kind.
Definition Diagnostic.h:117
void tag(DiagnosticTag Tag)
Definition Diagnostic.h:96
PartialDiagnostic(LexerCursorRange Range)
Definition Diagnostic.h:105
std::vector< std::string > & args()
Definition Diagnostic.h:94
virtual const char * message() const =0
virtual ~PartialDiagnostic()=default
const std::vector< std::string > & args() const
Definition Diagnostic.h:92
const std::vector< DiagnosticTag > & tags() const
Definition Diagnostic.h:98
std::string format() const
PartialDiagnostic & operator<<(std::string Var)
Definition Diagnostic.h:85
LexerCursorRange range() const
Definition Diagnostic.h:100
std::string_view newText() const
Definition Diagnostic.h:54
bool isInsertion() const
Definition Diagnostic.h:49
LexerCursorRange oldRange() const
Definition Diagnostic.h:53
static TextEdit mkRemoval(LexerCursorRange RemovingRange)
Definition Diagnostic.h:39
static TextEdit mkInsertion(LexerCursor P, std::string NewText)
Definition Diagnostic.h:35
bool isReplace() const
Definition Diagnostic.h:43
bool isRemoval() const
Definition Diagnostic.h:47
TextEdit(LexerCursorRange OldRange, std::string NewText)
Definition Diagnostic.h:30
DiagnosticTag
Definition Diagnostic.h:74