1 // 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_DIAGNOSTIC_DIAGNOSTIC_H_ 16 #define SRC_DIAGNOSTIC_DIAGNOSTIC_H_ 17 18 #include <string> 19 #include <utility> 20 #include <vector> 21 22 #include "src/source.h" 23 24 namespace tint { 25 namespace diag { 26 27 /// Severity is an enumerator of diagnostic severities. 28 enum class Severity { Note, Warning, Error, InternalCompilerError, Fatal }; 29 30 /// @return true iff `a` is more than, or of equal severity to `b` 31 inline bool operator>=(Severity a, Severity b) { 32 return static_cast<int>(a) >= static_cast<int>(b); 33 } 34 35 /// System is an enumerator of Tint systems that can be the originator of a 36 /// diagnostic message. 37 enum class System { 38 AST, 39 Clone, 40 Inspector, 41 Program, 42 ProgramBuilder, 43 Reader, 44 Resolver, 45 Semantic, 46 Symbol, 47 Test, 48 Transform, 49 Utils, 50 Writer, 51 }; 52 53 /// Diagnostic holds all the information for a single compiler diagnostic 54 /// message. 55 class Diagnostic { 56 public: 57 /// severity is the severity of the diagnostic message. 58 Severity severity = Severity::Error; 59 /// source is the location of the diagnostic. 60 Source source; 61 /// message is the text associated with the diagnostic. 62 std::string message; 63 /// system is the Tint system that raised the diagnostic. 64 System system; 65 /// code is the error code, for example a validation error might have the code 66 /// `"v-0001"`. 67 const char* code = nullptr; 68 }; 69 70 /// List is a container of Diagnostic messages. 71 class List { 72 public: 73 /// iterator is the type used for range based iteration. 74 using iterator = std::vector<Diagnostic>::const_iterator; 75 76 /// Constructs the list with no elements. 77 List(); 78 79 /// Copy constructor. Copies the diagnostics from `list` into this list. 80 /// @param list the list of diagnostics to copy into this list. 81 List(std::initializer_list<Diagnostic> list); 82 83 /// Copy constructor. Copies the diagnostics from `list` into this list. 84 /// @param list the list of diagnostics to copy into this list. 85 List(const List& list); 86 87 /// Move constructor. Moves the diagnostics from `list` into this list. 88 /// @param list the list of diagnostics to move into this list. 89 List(List&& list); 90 ~List(); 91 92 /// Assignment operator. Copies the diagnostics from `list` into this list. 93 /// @param list the list to copy into this list. 94 /// @return this list. 95 List& operator=(const List& list); 96 97 /// Assignment move operator. Moves the diagnostics from `list` into this 98 /// list. 99 /// @param list the list to move into this list. 100 /// @return this list. 101 List& operator=(List&& list); 102 103 /// adds a diagnostic to the end of this list. 104 /// @param diag the diagnostic to append to this list. add(Diagnostic && diag)105 void add(Diagnostic&& diag) { 106 if (diag.severity >= Severity::Error) { 107 error_count_++; 108 } 109 entries_.emplace_back(std::move(diag)); 110 } 111 112 /// adds a list of diagnostics to the end of this list. 113 /// @param list the diagnostic to append to this list. add(const List & list)114 void add(const List& list) { 115 for (auto diag : list) { 116 add(std::move(diag)); 117 } 118 } 119 120 /// adds the note message with the given Source to the end of this list. 121 /// @param system the system raising the note message 122 /// @param note_msg the note message 123 /// @param source the source of the note diagnostic add_note(System system,const std::string & note_msg,const Source & source)124 void add_note(System system, 125 const std::string& note_msg, 126 const Source& source) { 127 diag::Diagnostic note{}; 128 note.severity = diag::Severity::Note; 129 note.system = system; 130 note.source = source; 131 note.message = note_msg; 132 add(std::move(note)); 133 } 134 135 /// adds the warning message with the given Source to the end of this list. 136 /// @param system the system raising the warning message 137 /// @param warning_msg the warning message 138 /// @param source the source of the warning diagnostic add_warning(System system,const std::string & warning_msg,const Source & source)139 void add_warning(System system, 140 const std::string& warning_msg, 141 const Source& source) { 142 diag::Diagnostic warning{}; 143 warning.severity = diag::Severity::Warning; 144 warning.system = system; 145 warning.source = source; 146 warning.message = warning_msg; 147 add(std::move(warning)); 148 } 149 150 /// adds the error message without a source to the end of this list. 151 /// @param system the system raising the error message 152 /// @param err_msg the error message add_error(System system,std::string err_msg)153 void add_error(System system, std::string err_msg) { 154 diag::Diagnostic error{}; 155 error.severity = diag::Severity::Error; 156 error.system = system; 157 error.message = std::move(err_msg); 158 add(std::move(error)); 159 } 160 161 /// adds the error message with the given Source to the end of this list. 162 /// @param system the system raising the error message 163 /// @param err_msg the error message 164 /// @param source the source of the error diagnostic add_error(System system,std::string err_msg,const Source & source)165 void add_error(System system, std::string err_msg, const Source& source) { 166 diag::Diagnostic error{}; 167 error.severity = diag::Severity::Error; 168 error.system = system; 169 error.source = source; 170 error.message = std::move(err_msg); 171 add(std::move(error)); 172 } 173 174 /// adds the error message with the given code and Source to the end of this 175 /// list. 176 /// @param system the system raising the error message 177 /// @param code the error code 178 /// @param err_msg the error message 179 /// @param source the source of the error diagnostic add_error(System system,const char * code,std::string err_msg,const Source & source)180 void add_error(System system, 181 const char* code, 182 std::string err_msg, 183 const Source& source) { 184 diag::Diagnostic error{}; 185 error.code = code; 186 error.severity = diag::Severity::Error; 187 error.system = system; 188 error.source = source; 189 error.message = std::move(err_msg); 190 add(std::move(error)); 191 } 192 193 /// adds an internal compiler error message to the end of this list. 194 /// @param system the system raising the error message 195 /// @param err_msg the error message 196 /// @param source the source of the internal compiler error add_ice(System system,const std::string & err_msg,const Source & source)197 void add_ice(System system, 198 const std::string& err_msg, 199 const Source& source) { 200 diag::Diagnostic ice{}; 201 ice.severity = diag::Severity::InternalCompilerError; 202 ice.system = system; 203 ice.source = source; 204 ice.message = err_msg; 205 add(std::move(ice)); 206 } 207 208 /// @returns true iff the diagnostic list contains errors diagnostics (or of 209 /// higher severity). contains_errors()210 bool contains_errors() const { return error_count_ > 0; } 211 /// @returns the number of error diagnostics (or of higher severity). error_count()212 size_t error_count() const { return error_count_; } 213 /// @returns the number of entries in the list. count()214 size_t count() const { return entries_.size(); } 215 /// @returns the first diagnostic in the list. begin()216 iterator begin() const { return entries_.begin(); } 217 /// @returns the last diagnostic in the list. end()218 iterator end() const { return entries_.end(); } 219 220 /// @returns a formatted string of all the diagnostics in this list. 221 std::string str() const; 222 223 private: 224 std::vector<Diagnostic> entries_; 225 size_t error_count_ = 0; 226 }; 227 228 } // namespace diag 229 } // namespace tint 230 231 #endif // SRC_DIAGNOSTIC_DIAGNOSTIC_H_ 232