1 /**
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
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
16 #include "diagnostic.h"
17 #include <memory>
18 #include <vector>
19 #include "generated/diagnostic.h"
20 #include "lexer/token/sourceLocation.h"
21 #include "parser/program/program.h"
22 #include "checker/types/type.h"
23 #include "checker/types/signature.h"
24
25 namespace ark::es2panda::util {
26
Format(const DiagnosticMessageElement & elem)27 std::string Format(const DiagnosticMessageElement &elem)
28 {
29 if (std::holds_alternative<std::string>(elem)) {
30 return std::get<std::string>(elem);
31 }
32 if (std::holds_alternative<std::string_view>(elem)) {
33 return std::string(std::get<std::string_view>(elem));
34 }
35 if (std::holds_alternative<const char *const>(elem)) {
36 return std::get<const char *const>(elem);
37 }
38 if (std::holds_alternative<StringView>(elem)) {
39 return std::string(std::get<StringView>(elem));
40 }
41 if (std::holds_alternative<size_t>(elem)) {
42 return std::to_string(std::get<size_t>(elem));
43 }
44 if (std::holds_alternative<lexer::TokenType>(elem)) {
45 return TokenToString(std::get<lexer::TokenType>(elem));
46 }
47 if (std::holds_alternative<AsSrc>(elem)) {
48 std::stringstream ss;
49 std::get<AsSrc>(elem).GetType()->ToStringAsSrc(ss);
50 return ss.str();
51 }
52 if (std::holds_alternative<const checker::Type *const>(elem)) {
53 std::stringstream ss;
54 std::get<const checker::Type *const>(elem)->ToString(ss);
55 return ss.str();
56 }
57 if (std::holds_alternative<const checker::Signature *const>(elem)) {
58 std::stringstream ss;
59 std::get<const checker::Signature *const>(elem)->ToString(ss, nullptr, true);
60 return ss.str();
61 }
62 ES2PANDA_UNREACHABLE();
63 }
Format(const DiagnosticMessageParams & list)64 std::string Format(const DiagnosticMessageParams &list)
65 {
66 std::stringstream ss;
67 for (const auto &it : list) {
68 ss << Format(it);
69 }
70 return ss.str();
71 }
72
FormatParams(const DiagnosticMessageParams & list)73 std::vector<std::string> FormatParams(const DiagnosticMessageParams &list)
74 {
75 std::vector<std::string> params;
76 params.reserve(list.size());
77 for (const auto &it : list) {
78 std::stringstream ss;
79 ss << Format(it);
80 params.push_back(ss.str());
81 }
82 return params;
83 }
84
Format(std::string_view formatString,const std::vector<std::string> & params)85 std::string Format(std::string_view formatString, const std::vector<std::string> ¶ms)
86 {
87 std::string result;
88 size_t pos = 0;
89 size_t paramIndex = 0;
90 while (pos < formatString.size()) {
91 auto nextPos = formatString.find("{}", pos);
92 if (nextPos == std::string::npos) {
93 break;
94 }
95 result.append(formatString.substr(pos, nextPos - pos));
96 ASSERT_PRINT(paramIndex < params.size(),
97 "Too few params (" + std::to_string(params.size()) + ") given for " + std::string(formatString));
98 result.append(params.at(paramIndex++));
99 pos = nextPos + 2U;
100 }
101 ASSERT_PRINT(paramIndex == params.size(), "Placeholder and param count mismatch in " + std::string(formatString));
102 result.append(formatString.substr(pos));
103 return result;
104 }
105
operator <(const DiagnosticBase & rhs) const106 bool DiagnosticBase::operator<(const DiagnosticBase &rhs) const
107 {
108 if (File() != rhs.File()) {
109 return File() < rhs.File();
110 }
111 if (Line() != rhs.Line()) {
112 return Line() < rhs.Line();
113 }
114 if (Offset() != rhs.Offset()) {
115 return Offset() < rhs.Offset();
116 }
117 if (Type() != rhs.Type()) {
118 return Type() < rhs.Type();
119 }
120 return false;
121 }
122
operator ==(const DiagnosticBase & rhs) const123 bool DiagnosticBase::operator==(const DiagnosticBase &rhs) const
124 {
125 if (File() != rhs.File()) {
126 return false;
127 }
128 if (Line() != rhs.Line()) {
129 return false;
130 }
131 if (Offset() != rhs.Offset()) {
132 return false;
133 }
134 if (Type() != rhs.Type()) {
135 return false;
136 }
137 return Message() == rhs.Message();
138 }
139
Type() const140 DiagnosticType Diagnostic::Type() const
141 {
142 return diagnosticKind_->Type();
143 }
144
Message() const145 std::string Diagnostic::Message() const
146 {
147 return Format(diagnosticKind_->Message(), diagnosticParams_);
148 }
149
DiagnosticTypeToString(DiagnosticType type)150 const char *DiagnosticTypeToString(DiagnosticType type)
151 {
152 switch (type) {
153 case DiagnosticType::FATAL:
154 return "Fatal error";
155 case DiagnosticType::SYNTAX:
156 return "SyntaxError";
157 case DiagnosticType::SEMANTIC:
158 return "TypeError";
159 case DiagnosticType::WARNING:
160 return "Warning";
161 case DiagnosticType::PLUGIN_WARNING:
162 return "Plugin warning";
163 case DiagnosticType::PLUGIN_ERROR:
164 return "Plugin error";
165 case DiagnosticType::DECLGEN_ETS2TS_ERROR:
166 return "Declgen ets2ts error";
167 case DiagnosticType::DECLGEN_ETS2TS_WARNING:
168 return "Declgen ets2ts warning";
169 case DiagnosticType::ARKTS_CONFIG_ERROR:
170 return "ArkTS config error";
171 case DiagnosticType::SUGGESTION:
172 return "SUGGESTION";
173 case DiagnosticType::ISOLATED_DECLGEN:
174 return "Isolated declgen error";
175 default:
176 ES2PANDA_UNREACHABLE();
177 }
178 }
179
DiagnosticBase(const lexer::SourcePosition & pos)180 DiagnosticBase::DiagnosticBase(const lexer::SourcePosition &pos)
181 {
182 if (pos.Program() != nullptr) {
183 lexer::SourceLocation loc = pos.ToLocation();
184 file_ = pos.Program()->SourceFilePath().Utf8();
185 line_ = loc.line;
186 offset_ = loc.col;
187 }
188 }
189
DiagnosticBase(const lexer::SourceLocation & loc)190 DiagnosticBase::DiagnosticBase(const lexer::SourceLocation &loc)
191 {
192 if (loc.Program() != nullptr) {
193 file_ = loc.Program()->SourceFilePath().Utf8();
194 line_ = loc.line;
195 offset_ = loc.col;
196 }
197 }
198
ThrowableDiagnostic(DiagnosticType type,const DiagnosticMessageParams & params,const lexer::SourceLocation & loc)199 ThrowableDiagnostic::ThrowableDiagnostic(DiagnosticType type, const DiagnosticMessageParams ¶ms,
200 const lexer::SourceLocation &loc)
201 : DiagnosticBase(loc), type_(type), message_(Format(params))
202 {
203 }
204
ThrowableDiagnostic(DiagnosticType type,const DiagnosticMessageParams & params,const lexer::SourcePosition & pos)205 ThrowableDiagnostic::ThrowableDiagnostic(DiagnosticType type, const DiagnosticMessageParams ¶ms,
206 const lexer::SourcePosition &pos)
207 : DiagnosticBase(pos), type_(type), message_(Format(params))
208 {
209 }
210
ThrowableDiagnostic(DiagnosticType type,const DiagnosticMessageParams & params,std::string_view file,size_t line,size_t offset)211 ThrowableDiagnostic::ThrowableDiagnostic(DiagnosticType type, const DiagnosticMessageParams ¶ms,
212 std::string_view file, size_t line, size_t offset)
213 : DiagnosticBase(file, line, offset), type_(type), message_(Format(params))
214 {
215 }
216
ThrowableDiagnostic(const DiagnosticType type,const diagnostic::DiagnosticKind & diagnosticKind,const util::DiagnosticMessageParams & diagnosticParams,const lexer::SourcePosition & pos)217 ThrowableDiagnostic::ThrowableDiagnostic(const DiagnosticType type, const diagnostic::DiagnosticKind &diagnosticKind,
218 const util::DiagnosticMessageParams &diagnosticParams,
219 const lexer::SourcePosition &pos)
220 : DiagnosticBase(pos), type_(type), message_(Format(diagnosticKind.Message(), FormatParams(diagnosticParams)))
221 {
222 }
223
Suggestion(const diagnostic::DiagnosticKind * kind,std::vector<std::string> & params,const char * substitutionCode,const lexer::SourceRange * range)224 Suggestion::Suggestion(const diagnostic::DiagnosticKind *kind, std::vector<std::string> ¶ms,
225 const char *substitutionCode, const lexer::SourceRange *range)
226 : kind_(kind), substitutionCode_(substitutionCode), message_(Format(kind->Message(), params)), range_(range)
227 {
228 }
229
Type() const230 DiagnosticType Suggestion::Type() const
231 {
232 return kind_->Type();
233 }
234
Diagnostic(const diagnostic::DiagnosticKind & diagnosticKind,const util::DiagnosticMessageParams & diagnosticParams,const lexer::SourcePosition & pos,std::initializer_list<class Suggestion * > suggestions)235 Diagnostic::Diagnostic(const diagnostic::DiagnosticKind &diagnosticKind,
236 const util::DiagnosticMessageParams &diagnosticParams, const lexer::SourcePosition &pos,
237 std::initializer_list<class Suggestion *> suggestions)
238 : DiagnosticBase(pos), diagnosticKind_(&diagnosticKind), diagnosticParams_(FormatParams(diagnosticParams))
239 {
240 if (suggestions.size() != 0) {
241 suggestions_ = std::make_unique<std::vector<class Suggestion *>>();
242 for (auto suggestion : suggestions) {
243 suggestions_->emplace_back(suggestion);
244 }
245 }
246 }
247
Diagnostic(const diagnostic::DiagnosticKind & diagnosticKind,const util::DiagnosticMessageParams & diagnosticParams)248 Diagnostic::Diagnostic(const diagnostic::DiagnosticKind &diagnosticKind,
249 const util::DiagnosticMessageParams &diagnosticParams)
250 : Diagnostic(diagnosticKind, diagnosticParams, lexer::SourcePosition(), {})
251 {
252 }
253
Diagnostic(const diagnostic::DiagnosticKind & diagnosticKind,const util::DiagnosticMessageParams & diagnosticParams,const lexer::SourcePosition & pos,class Suggestion * suggestion)254 Diagnostic::Diagnostic(const diagnostic::DiagnosticKind &diagnosticKind,
255 const util::DiagnosticMessageParams &diagnosticParams, const lexer::SourcePosition &pos,
256 class Suggestion *suggestion)
257 : Diagnostic(diagnosticKind, diagnosticParams, pos, {suggestion})
258 {
259 }
260
Diagnostic(const diagnostic::DiagnosticKind & diagnosticKind,const util::DiagnosticMessageParams & diagnosticParams,const lexer::SourcePosition & pos)261 Diagnostic::Diagnostic(const diagnostic::DiagnosticKind &diagnosticKind,
262 const util::DiagnosticMessageParams &diagnosticParams, const lexer::SourcePosition &pos)
263 : Diagnostic(diagnosticKind, diagnosticParams, pos, {})
264 {
265 }
266
267 } // namespace ark::es2panda::util
268