blob: b56bd8d2e2b994cfc982a1084bb22830d640ef6f [file] [log] [blame]
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001// Copyright 2020 The Tint Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef SRC_TINT_DIAGNOSTIC_DIAGNOSTIC_H_
16#define SRC_TINT_DIAGNOSTIC_DIAGNOSTIC_H_
17
18#include <memory>
dan sinclair86216f52023-03-22 16:47:44 +000019#include <ostream>
Ryan Harrisondbc13af2022-02-21 15:19:07 +000020#include <string>
21#include <utility>
22#include <vector>
23
24#include "src/tint/source.h"
25
dan sinclair7bc9ba12022-04-07 17:22:26 +000026namespace tint::diag {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000027
28/// Severity is an enumerator of diagnostic severities.
29enum class Severity { Note, Warning, Error, InternalCompilerError, Fatal };
30
31/// @return true iff `a` is more than, or of equal severity to `b`
32inline bool operator>=(Severity a, Severity b) {
dan sinclair41e4d9a2022-05-01 14:40:55 +000033 return static_cast<int>(a) >= static_cast<int>(b);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000034}
35
36/// System is an enumerator of Tint systems that can be the originator of a
37/// diagnostic message.
38enum class System {
dan sinclair41e4d9a2022-05-01 14:40:55 +000039 AST,
40 Clone,
dan sinclair8626c9e2022-12-14 19:22:19 +000041 Constant,
dan sinclair41e4d9a2022-05-01 14:40:55 +000042 Inspector,
dan sinclaireee8d882022-10-28 01:22:58 +000043 IR,
dan sinclair41e4d9a2022-05-01 14:40:55 +000044 Program,
45 ProgramBuilder,
46 Reader,
47 Resolver,
48 Semantic,
49 Symbol,
50 Test,
51 Transform,
dan sinclair5f764d82022-12-08 00:32:27 +000052 Type,
dan sinclair41e4d9a2022-05-01 14:40:55 +000053 Utils,
54 Writer,
Ryan Harrisondbc13af2022-02-21 15:19:07 +000055};
56
57/// Diagnostic holds all the information for a single compiler diagnostic
58/// message.
59class Diagnostic {
dan sinclair41e4d9a2022-05-01 14:40:55 +000060 public:
61 /// Constructor
62 Diagnostic();
63 /// Copy constructor
64 Diagnostic(const Diagnostic&);
65 /// Destructor
66 ~Diagnostic();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000067
dan sinclair41e4d9a2022-05-01 14:40:55 +000068 /// Copy assignment operator
69 /// @return this diagnostic
70 Diagnostic& operator=(const Diagnostic&);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000071
dan sinclair41e4d9a2022-05-01 14:40:55 +000072 /// severity is the severity of the diagnostic message.
73 Severity severity = Severity::Error;
74 /// source is the location of the diagnostic.
75 Source source;
76 /// message is the text associated with the diagnostic.
77 std::string message;
78 /// system is the Tint system that raised the diagnostic.
79 System system;
80 /// code is the error code, for example a validation error might have the code
81 /// `"v-0001"`.
82 const char* code = nullptr;
83 /// A shared pointer to a Source::File. Only used if the diagnostic Source
84 /// points to a file that was created specifically for this diagnostic
85 /// (usually an ICE).
86 std::shared_ptr<Source::File> owned_file = nullptr;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000087};
88
89/// List is a container of Diagnostic messages.
90class List {
dan sinclair41e4d9a2022-05-01 14:40:55 +000091 public:
92 /// iterator is the type used for range based iteration.
93 using iterator = std::vector<Diagnostic>::const_iterator;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000094
dan sinclair41e4d9a2022-05-01 14:40:55 +000095 /// Constructs the list with no elements.
96 List();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000097
dan sinclair41e4d9a2022-05-01 14:40:55 +000098 /// Copy constructor. Copies the diagnostics from `list` into this list.
99 /// @param list the list of diagnostics to copy into this list.
100 List(std::initializer_list<Diagnostic> list);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000101
dan sinclair41e4d9a2022-05-01 14:40:55 +0000102 /// Copy constructor. Copies the diagnostics from `list` into this list.
103 /// @param list the list of diagnostics to copy into this list.
104 List(const List& list);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000105
dan sinclair41e4d9a2022-05-01 14:40:55 +0000106 /// Move constructor. Moves the diagnostics from `list` into this list.
107 /// @param list the list of diagnostics to move into this list.
108 List(List&& list);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000109
dan sinclair41e4d9a2022-05-01 14:40:55 +0000110 /// Destructor
111 ~List();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000112
dan sinclair41e4d9a2022-05-01 14:40:55 +0000113 /// Assignment operator. Copies the diagnostics from `list` into this list.
114 /// @param list the list to copy into this list.
115 /// @return this list.
116 List& operator=(const List& list);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000117
dan sinclair41e4d9a2022-05-01 14:40:55 +0000118 /// Assignment move operator. Moves the diagnostics from `list` into this
119 /// list.
120 /// @param list the list to move into this list.
121 /// @return this list.
122 List& operator=(List&& list);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000123
dan sinclair41e4d9a2022-05-01 14:40:55 +0000124 /// adds a diagnostic to the end of this list.
125 /// @param diag the diagnostic to append to this list.
126 void add(Diagnostic&& diag) {
127 if (diag.severity >= Severity::Error) {
128 error_count_++;
129 }
130 entries_.emplace_back(std::move(diag));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000131 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000132
dan sinclair41e4d9a2022-05-01 14:40:55 +0000133 /// adds a list of diagnostics to the end of this list.
134 /// @param list the diagnostic to append to this list.
135 void add(const List& list) {
136 for (auto diag : list) {
137 add(std::move(diag));
138 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000139 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000140
dan sinclair41e4d9a2022-05-01 14:40:55 +0000141 /// adds the note message with the given Source to the end of this list.
142 /// @param system the system raising the note message
143 /// @param note_msg the note message
144 /// @param source the source of the note diagnostic
Ben Clayton2fc56a12023-03-15 15:45:21 +0000145 void add_note(System system, std::string_view note_msg, const Source& source) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000146 diag::Diagnostic note{};
147 note.severity = diag::Severity::Note;
148 note.system = system;
149 note.source = source;
150 note.message = note_msg;
151 add(std::move(note));
152 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000153
dan sinclair41e4d9a2022-05-01 14:40:55 +0000154 /// adds the warning message with the given Source to the end of this list.
155 /// @param system the system raising the warning message
156 /// @param warning_msg the warning message
157 /// @param source the source of the warning diagnostic
Ben Clayton2fc56a12023-03-15 15:45:21 +0000158 void add_warning(System system, std::string_view warning_msg, const Source& source) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000159 diag::Diagnostic warning{};
160 warning.severity = diag::Severity::Warning;
161 warning.system = system;
162 warning.source = source;
163 warning.message = warning_msg;
164 add(std::move(warning));
165 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000166
dan sinclair41e4d9a2022-05-01 14:40:55 +0000167 /// adds the error message without a source to the end of this list.
168 /// @param system the system raising the error message
169 /// @param err_msg the error message
Ben Clayton2fc56a12023-03-15 15:45:21 +0000170 void add_error(System system, std::string_view err_msg) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000171 diag::Diagnostic error{};
172 error.severity = diag::Severity::Error;
173 error.system = system;
Ben Clayton2fc56a12023-03-15 15:45:21 +0000174 error.message = err_msg;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000175 add(std::move(error));
176 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000177
dan sinclair41e4d9a2022-05-01 14:40:55 +0000178 /// adds the error message with the given Source to the end of this list.
179 /// @param system the system raising the error message
180 /// @param err_msg the error message
181 /// @param source the source of the error diagnostic
Ben Clayton2fc56a12023-03-15 15:45:21 +0000182 void add_error(System system, std::string_view err_msg, const Source& source) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000183 diag::Diagnostic error{};
184 error.severity = diag::Severity::Error;
185 error.system = system;
186 error.source = source;
Ben Clayton2fc56a12023-03-15 15:45:21 +0000187 error.message = err_msg;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000188 add(std::move(error));
189 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000190
dan sinclair41e4d9a2022-05-01 14:40:55 +0000191 /// adds the error message with the given code and Source to the end of this
192 /// list.
193 /// @param system the system raising the error message
194 /// @param code the error code
195 /// @param err_msg the error message
196 /// @param source the source of the error diagnostic
Ben Clayton2fc56a12023-03-15 15:45:21 +0000197 void add_error(System system,
198 const char* code,
199 std::string_view err_msg,
200 const Source& source) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000201 diag::Diagnostic error{};
202 error.code = code;
203 error.severity = diag::Severity::Error;
204 error.system = system;
205 error.source = source;
Ben Clayton2fc56a12023-03-15 15:45:21 +0000206 error.message = err_msg;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000207 add(std::move(error));
208 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000209
dan sinclair41e4d9a2022-05-01 14:40:55 +0000210 /// adds an internal compiler error message to the end of this list.
211 /// @param system the system raising the error message
212 /// @param err_msg the error message
213 /// @param source the source of the internal compiler error
214 /// @param file the Source::File owned by this diagnostic
215 void add_ice(System system,
Ben Clayton2fc56a12023-03-15 15:45:21 +0000216 std::string_view err_msg,
dan sinclair41e4d9a2022-05-01 14:40:55 +0000217 const Source& source,
218 std::shared_ptr<Source::File> file) {
219 diag::Diagnostic ice{};
220 ice.severity = diag::Severity::InternalCompilerError;
221 ice.system = system;
222 ice.source = source;
223 ice.message = err_msg;
224 ice.owned_file = std::move(file);
225 add(std::move(ice));
226 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000227
dan sinclair41e4d9a2022-05-01 14:40:55 +0000228 /// @returns true iff the diagnostic list contains errors diagnostics (or of
229 /// higher severity).
230 bool contains_errors() const { return error_count_ > 0; }
231 /// @returns the number of error diagnostics (or of higher severity).
232 size_t error_count() const { return error_count_; }
233 /// @returns the number of entries in the list.
234 size_t count() const { return entries_.size(); }
dan sinclair86216f52023-03-22 16:47:44 +0000235 /// @returns true if the diagnostics list is empty
236 bool empty() const { return entries_.empty(); }
237 /// @returns the number of entrise in the diagnostics list
238 size_t size() const { return entries_.size(); }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000239 /// @returns the first diagnostic in the list.
240 iterator begin() const { return entries_.begin(); }
241 /// @returns the last diagnostic in the list.
242 iterator end() const { return entries_.end(); }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000243
dan sinclair41e4d9a2022-05-01 14:40:55 +0000244 /// @returns a formatted string of all the diagnostics in this list.
245 std::string str() const;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000246
dan sinclair41e4d9a2022-05-01 14:40:55 +0000247 private:
248 std::vector<Diagnostic> entries_;
249 size_t error_count_ = 0;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000250};
251
dan sinclair86216f52023-03-22 16:47:44 +0000252/// Write the diagnostic list to the given stream
253/// @param out the output stream
254/// @param list the list to emit
255/// @returns the output stream
256std::ostream& operator<<(std::ostream& out, const List& list);
257
dan sinclair7bc9ba12022-04-07 17:22:26 +0000258} // namespace tint::diag
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000259
260#endif // SRC_TINT_DIAGNOSTIC_DIAGNOSTIC_H_