diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index bf9fa3f3ba..9a14d8a12b 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -230,6 +230,8 @@ libtint_source_set("libtint_core_all_src") { "ast/depth_multisampled_texture.h", "ast/depth_texture.cc", "ast/depth_texture.h", + "ast/diagnostic_control.cc", + "ast/diagnostic_control.h", "ast/disable_validation_attribute.cc", "ast/disable_validation_attribute.h", "ast/discard_statement.cc", @@ -1178,6 +1180,7 @@ if (tint_build_unittests) { "ast/case_statement_test.cc", "ast/compound_assignment_statement_test.cc", "ast/continue_statement_test.cc", + "ast/diagnostic_control_test.cc", "ast/discard_statement_test.cc", "ast/enable_test.cc", "ast/extension_test.cc", diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index 83f3888581..438ab859c8 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -125,6 +125,8 @@ list(APPEND TINT_LIB_SRCS ast/depth_multisampled_texture.h ast/depth_texture.cc ast/depth_texture.h + ast/diagnostic_control.cc + ast/diagnostic_control.h ast/disable_validation_attribute.cc ast/disable_validation_attribute.h ast/discard_statement.cc @@ -569,6 +571,7 @@ list(APPEND TINT_LIB_SRCS ) tint_generated(ast/builtin_value BENCH TEST) +tint_generated(ast/diagnostic_control BENCH TEST) tint_generated(ast/extension BENCH TEST) tint_generated(ast/interpolate_attribute BENCH TEST) tint_generated(resolver/init_conv_intrinsic) @@ -829,6 +832,7 @@ if(TINT_BUILD_TESTS) ast/continue_statement_test.cc ast/depth_multisampled_texture_test.cc ast/depth_texture_test.cc + ast/diagnostic_control_test.cc ast/discard_statement_test.cc ast/enable_test.cc ast/external_texture_test.cc diff --git a/src/tint/ast/diagnostic_control.cc b/src/tint/ast/diagnostic_control.cc new file mode 100644 index 0000000000..d83e9c2bac --- /dev/null +++ b/src/tint/ast/diagnostic_control.cc @@ -0,0 +1,76 @@ +// Copyright 2023 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//////////////////////////////////////////////////////////////////////////////// +// File generated by tools/src/cmd/gen +// using the template: +// src/tint/ast/diagnostic_control.cc.tmpl +// +// Do not modify this file directly +//////////////////////////////////////////////////////////////////////////////// + +#include "src/tint/ast/diagnostic_control.h" + +#include + +#include "src/tint/program_builder.h" + +TINT_INSTANTIATE_TYPEINFO(tint::ast::DiagnosticControl); + +namespace tint::ast { + +DiagnosticControl::~DiagnosticControl() = default; + +const DiagnosticControl* DiagnosticControl::Clone(CloneContext* ctx) const { + auto src = ctx->Clone(source); + auto rule = ctx->Clone(rule_name); + return ctx->dst->create(src, severity, rule); +} + +/// ParseDiagnosticSeverity parses a DiagnosticSeverity from a string. +/// @param str the string to parse +/// @returns the parsed enum, or DiagnosticSeverity::kUndefined if the string could not be parsed. +DiagnosticSeverity ParseDiagnosticSeverity(std::string_view str) { + if (str == "error") { + return DiagnosticSeverity::kError; + } + if (str == "info") { + return DiagnosticSeverity::kInfo; + } + if (str == "off") { + return DiagnosticSeverity::kOff; + } + if (str == "warning") { + return DiagnosticSeverity::kWarning; + } + return DiagnosticSeverity::kUndefined; +} + +std::ostream& operator<<(std::ostream& out, DiagnosticSeverity value) { + switch (value) { + case DiagnosticSeverity::kUndefined: + return out << "undefined"; + case DiagnosticSeverity::kError: + return out << "error"; + case DiagnosticSeverity::kInfo: + return out << "info"; + case DiagnosticSeverity::kOff: + return out << "off"; + case DiagnosticSeverity::kWarning: + return out << "warning"; + } + return out << ""; +} + +} // namespace tint::ast diff --git a/src/tint/ast/diagnostic_control.cc.tmpl b/src/tint/ast/diagnostic_control.cc.tmpl new file mode 100644 index 0000000000..c5d1a73d1e --- /dev/null +++ b/src/tint/ast/diagnostic_control.cc.tmpl @@ -0,0 +1,35 @@ +{{- /* +-------------------------------------------------------------------------------- +Template file for use with tools/src/cmd/gen to generate diagnostic_control.cc + +See: +* tools/src/cmd/gen for structures used by this template +* https://golang.org/pkg/text/template/ for documentation on the template syntax +-------------------------------------------------------------------------------- +*/ -}} + +{{- Import "src/tint/templates/enums.tmpl.inc" -}} + +#include "src/tint/ast/diagnostic_control.h" + +#include + +#include "src/tint/program_builder.h" + +TINT_INSTANTIATE_TYPEINFO(tint::ast::DiagnosticControl); + +namespace tint::ast { + +DiagnosticControl::~DiagnosticControl() = default; + +const DiagnosticControl* DiagnosticControl::Clone(CloneContext* ctx) const { + auto src = ctx->Clone(source); + auto rule = ctx->Clone(rule_name); + return ctx->dst->create(src, severity, rule); +} + +{{ Eval "ParseEnum" (Sem.Enum "diagnostic_severity")}} + +{{ Eval "EnumOStream" (Sem.Enum "diagnostic_severity")}} + +} // namespace tint::ast diff --git a/src/tint/ast/diagnostic_control.h b/src/tint/ast/diagnostic_control.h new file mode 100644 index 0000000000..f127c1fe48 --- /dev/null +++ b/src/tint/ast/diagnostic_control.h @@ -0,0 +1,96 @@ +// Copyright 2023 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//////////////////////////////////////////////////////////////////////////////// +// File generated by tools/src/cmd/gen +// using the template: +// src/tint/ast/diagnostic_control.h.tmpl +// +// Do not modify this file directly +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_ +#define SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_ + +#include +#include + +#include "src/tint/ast/node.h" + +// Forward declarations +namespace tint::ast { +class IdentifierExpression; +} // namespace tint::ast + +namespace tint::ast { + +/// The diagnostic severity control. +enum class DiagnosticSeverity { + kUndefined, + kError, + kInfo, + kOff, + kWarning, +}; + +/// @param out the std::ostream to write to +/// @param value the DiagnosticSeverity +/// @returns `out` so calls can be chained +std::ostream& operator<<(std::ostream& out, DiagnosticSeverity value); + +/// ParseDiagnosticSeverity parses a DiagnosticSeverity from a string. +/// @param str the string to parse +/// @returns the parsed enum, or DiagnosticSeverity::kUndefined if the string could not be parsed. +DiagnosticSeverity ParseDiagnosticSeverity(std::string_view str); + +constexpr const char* kDiagnosticSeverityStrings[] = { + "error", + "info", + "off", + "warning", +}; + +/// A diagnostic control used for diagnostic directives and attributes. +class DiagnosticControl : public Castable { + public: + /// Constructor + /// @param pid the identifier of the program that owns this node + /// @param nid the unique node identifier + /// @param src the source of this node + /// @param sev the diagnostic severity + /// @param rule the diagnostic rule name + DiagnosticControl(ProgramID pid, + NodeID nid, + const Source& src, + DiagnosticSeverity sev, + const IdentifierExpression* rule) + : Base(pid, nid, src), severity(sev), rule_name(rule) {} + + ~DiagnosticControl() override; + + /// Clones this node and all transitive child nodes using the `CloneContext` `ctx`. + /// @param ctx the clone context + /// @return the newly cloned node + const DiagnosticControl* Clone(CloneContext* ctx) const override; + + /// The diagnostic severity control. + DiagnosticSeverity severity; + + /// The diagnostic rule name. + const IdentifierExpression* rule_name; +}; + +} // namespace tint::ast + +#endif // SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_ diff --git a/src/tint/ast/diagnostic_control.h.tmpl b/src/tint/ast/diagnostic_control.h.tmpl new file mode 100644 index 0000000000..5ddbc6df2f --- /dev/null +++ b/src/tint/ast/diagnostic_control.h.tmpl @@ -0,0 +1,63 @@ +{{- /* +-------------------------------------------------------------------------------- +Template file for use with tools/src/cmd/gen to generate diagnostic_control.h + +See: +* tools/src/cmd/gen for structures used by this template +* https://golang.org/pkg/text/template/ for documentation on the template syntax +-------------------------------------------------------------------------------- +*/ -}} + +{{- Import "src/tint/templates/enums.tmpl.inc" -}} + +#ifndef SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_ +#define SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_ + +#include +#include + +#include "src/tint/ast/node.h" + +// Forward declarations +namespace tint::ast { +class IdentifierExpression; +} // namespace tint::ast + +namespace tint::ast { + +/// The diagnostic severity control. +{{ Eval "DeclareEnum" (Sem.Enum "diagnostic_severity") }} + +/// A diagnostic control used for diagnostic directives and attributes. +class DiagnosticControl : public Castable { + public: + /// Constructor + /// @param pid the identifier of the program that owns this node + /// @param nid the unique node identifier + /// @param src the source of this node + /// @param sev the diagnostic severity + /// @param rule the diagnostic rule name + DiagnosticControl(ProgramID pid, + NodeID nid, + const Source& src, + DiagnosticSeverity sev, + const IdentifierExpression* rule) + : Base(pid, nid, src), severity(sev), rule_name(rule) {} + + ~DiagnosticControl() override; + + /// Clones this node and all transitive child nodes using the `CloneContext` `ctx`. + /// @param ctx the clone context + /// @return the newly cloned node + const DiagnosticControl* Clone(CloneContext* ctx) const override; + + /// The diagnostic severity control. + DiagnosticSeverity severity; + + /// The diagnostic rule name. + const IdentifierExpression* rule_name; +}; + +} // namespace tint::ast + +#endif // SRC_TINT_AST_DIAGNOSTIC_CONTROL_H_ diff --git a/src/tint/ast/diagnostic_control_bench.cc b/src/tint/ast/diagnostic_control_bench.cc new file mode 100644 index 0000000000..d96f93b8cb --- /dev/null +++ b/src/tint/ast/diagnostic_control_bench.cc @@ -0,0 +1,50 @@ +// Copyright 2023 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//////////////////////////////////////////////////////////////////////////////// +// File generated by tools/src/cmd/gen +// using the template: +// src/tint/ast/diagnostic_control_bench.cc.tmpl +// +// Do not modify this file directly +//////////////////////////////////////////////////////////////////////////////// + +#include "src/tint/ast/diagnostic_control.h" + +#include + +#include "benchmark/benchmark.h" + +namespace tint::ast { +namespace { + +void DiagnosticSeverityParser(::benchmark::State& state) { + std::array kStrings{ + "erccr", "3o", "eVror", "error", "erro1", "qqrJr", "errll7r", + "ppqnfH", "c", "iGf", "info", "invii", "inWWo", "Mxxo", + "ogg", "X", "3ff", "off", "oEf", "oPTT", "dxxf", + "w44rning", "waSSniVVg", "RarR22g", "warning", "wFni9g", "waring", "VOORRHng", + }; + for (auto _ : state) { + for (auto& str : kStrings) { + auto result = ParseDiagnosticSeverity(str); + benchmark::DoNotOptimize(result); + } + } +} + +BENCHMARK(DiagnosticSeverityParser); + +} // namespace +} // namespace tint::ast diff --git a/src/tint/ast/diagnostic_control_bench.cc.tmpl b/src/tint/ast/diagnostic_control_bench.cc.tmpl new file mode 100644 index 0000000000..48058cabd7 --- /dev/null +++ b/src/tint/ast/diagnostic_control_bench.cc.tmpl @@ -0,0 +1,25 @@ +{{- /* +-------------------------------------------------------------------------------- +Template file for use with tools/src/cmd/gen to generate diagnostic_control_bench.cc + +See: +* tools/src/cmd/gen for structures used by this template +* https://golang.org/pkg/text/template/ for documentation on the template syntax +-------------------------------------------------------------------------------- +*/ -}} + +{{- Import "src/tint/templates/enums.tmpl.inc" -}} + +#include "src/tint/ast/diagnostic_control.h" + +#include + +#include "benchmark/benchmark.h" + +namespace tint::ast { +namespace { + +{{ Eval "BenchmarkParseEnum" (Sem.Enum "diagnostic_severity")}} + +} // namespace +} // namespace tint::ast diff --git a/src/tint/ast/diagnostic_control_test.cc b/src/tint/ast/diagnostic_control_test.cc new file mode 100644 index 0000000000..2dbd13952f --- /dev/null +++ b/src/tint/ast/diagnostic_control_test.cc @@ -0,0 +1,104 @@ +// Copyright 2023 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//////////////////////////////////////////////////////////////////////////////// +// File generated by tools/src/cmd/gen +// using the template: +// src/tint/ast/diagnostic_control_test.cc.tmpl +// +// Do not modify this file directly +//////////////////////////////////////////////////////////////////////////////// + +#include + +#include "src/tint/ast/diagnostic_control.h" +#include "src/tint/ast/test_helper.h" + +namespace tint::ast { +namespace { + +using DiagnosticControlTest = TestHelper; + +TEST_F(DiagnosticControlTest, Creation) { + auto* name = Expr("foo"); + Source source; + source.range.begin = Source::Location{20, 2}; + source.range.end = Source::Location{20, 5}; + auto* control = create(source, DiagnosticSeverity::kWarning, name); + EXPECT_EQ(control->source.range.begin.line, 20u); + EXPECT_EQ(control->source.range.begin.column, 2u); + EXPECT_EQ(control->source.range.end.line, 20u); + EXPECT_EQ(control->source.range.end.column, 5u); + EXPECT_EQ(control->severity, DiagnosticSeverity::kWarning); + EXPECT_EQ(control->rule_name, name); +} + +namespace diagnostic_severity_tests { + +namespace parse_print_tests { + +struct Case { + const char* string; + DiagnosticSeverity value; +}; + +inline std::ostream& operator<<(std::ostream& out, Case c) { + return out << "'" << std::string(c.string) << "'"; +} + +static constexpr Case kValidCases[] = { + {"error", DiagnosticSeverity::kError}, + {"info", DiagnosticSeverity::kInfo}, + {"off", DiagnosticSeverity::kOff}, + {"warning", DiagnosticSeverity::kWarning}, +}; + +static constexpr Case kInvalidCases[] = { + {"erccr", DiagnosticSeverity::kUndefined}, {"3o", DiagnosticSeverity::kUndefined}, + {"eVror", DiagnosticSeverity::kUndefined}, {"1nfo", DiagnosticSeverity::kUndefined}, + {"iqfJ", DiagnosticSeverity::kUndefined}, {"illf77", DiagnosticSeverity::kUndefined}, + {"oppqH", DiagnosticSeverity::kUndefined}, {"", DiagnosticSeverity::kUndefined}, + {"Gb", DiagnosticSeverity::kUndefined}, {"warniivg", DiagnosticSeverity::kUndefined}, + {"8WWrning", DiagnosticSeverity::kUndefined}, {"wxxning", DiagnosticSeverity::kUndefined}, +}; + +using DiagnosticSeverityParseTest = testing::TestWithParam; + +TEST_P(DiagnosticSeverityParseTest, Parse) { + const char* string = GetParam().string; + DiagnosticSeverity expect = GetParam().value; + EXPECT_EQ(expect, ParseDiagnosticSeverity(string)); +} + +INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticSeverityParseTest, testing::ValuesIn(kValidCases)); +INSTANTIATE_TEST_SUITE_P(InvalidCases, + DiagnosticSeverityParseTest, + testing::ValuesIn(kInvalidCases)); + +using DiagnosticSeverityPrintTest = testing::TestWithParam; + +TEST_P(DiagnosticSeverityPrintTest, Print) { + DiagnosticSeverity value = GetParam().value; + const char* expect = GetParam().string; + EXPECT_EQ(expect, utils::ToString(value)); +} + +INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticSeverityPrintTest, testing::ValuesIn(kValidCases)); + +} // namespace parse_print_tests + +} // namespace diagnostic_severity_tests + +} // namespace +} // namespace tint::ast diff --git a/src/tint/ast/diagnostic_control_test.cc.tmpl b/src/tint/ast/diagnostic_control_test.cc.tmpl new file mode 100644 index 0000000000..a078cceaed --- /dev/null +++ b/src/tint/ast/diagnostic_control_test.cc.tmpl @@ -0,0 +1,45 @@ +{{- /* +-------------------------------------------------------------------------------- +Template file for use with tools/src/cmd/gen to generate diagnostic_control_test.cc + +See: +* tools/src/cmd/gen for structures used by this template +* https://golang.org/pkg/text/template/ for documentation on the template syntax +-------------------------------------------------------------------------------- +*/ -}} + +{{- Import "src/tint/templates/enums.tmpl.inc" -}} + +#include + +#include "src/tint/ast/diagnostic_control.h" +#include "src/tint/ast/test_helper.h" + +namespace tint::ast { +namespace { + +using DiagnosticControlTest = TestHelper; + +TEST_F(DiagnosticControlTest, Creation) { + auto* name = Expr("foo"); + Source source; + source.range.begin = Source::Location{20, 2}; + source.range.end = Source::Location{20, 5}; + auto* control = create(source, + DiagnosticSeverity::kWarning, name); + EXPECT_EQ(control->source.range.begin.line, 20u); + EXPECT_EQ(control->source.range.begin.column, 2u); + EXPECT_EQ(control->source.range.end.line, 20u); + EXPECT_EQ(control->source.range.end.column, 5u); + EXPECT_EQ(control->severity, DiagnosticSeverity::kWarning); + EXPECT_EQ(control->rule_name, name); +} + +namespace diagnostic_severity_tests { + +{{ Eval "TestParsePrintEnum" (Sem.Enum "diagnostic_severity")}} + +} // namespace diagnostic_severity_tests + +} // namespace +} // namespace tint::ast diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def index 08dc366c73..05fe8c9b0a 100644 --- a/src/tint/intrinsics.def +++ b/src/tint/intrinsics.def @@ -40,6 +40,14 @@ enum builtin_value { @internal point_size } +// https://gpuweb.github.io/gpuweb/wgsl/#syntax-severity_control_name +enum diagnostic_severity { + error + warning + info + off +} + // https://gpuweb.github.io/gpuweb/wgsl/#extension enum extension { // WGSL Extension "f16" diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h index 7c24a5ba68..4e760de40e 100644 --- a/src/tint/program_builder.h +++ b/src/tint/program_builder.h @@ -40,6 +40,7 @@ #include "src/tint/ast/continue_statement.h" #include "src/tint/ast/depth_multisampled_texture.h" #include "src/tint/ast/depth_texture.h" +#include "src/tint/ast/diagnostic_control.h" #include "src/tint/ast/disable_validation_attribute.h" #include "src/tint/ast/discard_statement.h" #include "src/tint/ast/enable.h" @@ -3220,6 +3221,26 @@ class ProgramBuilder { validation); } + /// Creates an ast::DiagnosticControl + /// @param source the source information + /// @param severity the diagnostic severity control + /// @param rule_name the diagnostic rule name + /// @returns the diagnostic control pointer + const ast::DiagnosticControl* DiagnosticControl(const Source& source, + ast::DiagnosticSeverity severity, + const ast::IdentifierExpression* rule_name) { + return create(source, severity, rule_name); + } + + /// Creates an ast::DiagnosticControl + /// @param severity the diagnostic severity control + /// @param rule_name the diagnostic rule name + /// @returns the diagnostic control pointer + const ast::DiagnosticControl* DiagnosticControl(ast::DiagnosticSeverity severity, + const ast::IdentifierExpression* rule_name) { + return create(source_, severity, rule_name); + } + /// Sets the current builder source to `src` /// @param src the Source used for future create() calls void SetSource(const Source& src) {