tint: Add two-token form for diagnostics rule names.

Fixed: tint:1891
Change-Id: Ia3737c29b111d7b6e6b00fbd68da7f85a5a49bca
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/128301
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton 2023-04-20 23:51:53 +00:00 committed by Dawn LUCI CQ
parent 6cb055b6aa
commit 7883a0cb8d
41 changed files with 849 additions and 250 deletions

View File

@ -472,6 +472,7 @@ libtint_source_set("libtint_ast_hdrs") {
"ast/diagnostic_attribute.h",
"ast/diagnostic_control.h",
"ast/diagnostic_directive.h",
"ast/diagnostic_rule_name.h",
"ast/disable_validation_attribute.h",
"ast/discard_statement.h",
"ast/enable.h",
@ -559,6 +560,7 @@ libtint_source_set("libtint_ast_src") {
"ast/diagnostic_attribute.cc",
"ast/diagnostic_control.cc",
"ast/diagnostic_directive.cc",
"ast/diagnostic_rule_name.cc",
"ast/disable_validation_attribute.cc",
"ast/discard_statement.cc",
"ast/enable.cc",
@ -1291,6 +1293,7 @@ if (tint_build_unittests) {
"ast/diagnostic_attribute_test.cc",
"ast/diagnostic_control_test.cc",
"ast/diagnostic_directive_test.cc",
"ast/diagnostic_rule_name_test.cc",
"ast/discard_statement_test.cc",
"ast/enable_test.cc",
"ast/float_literal_expression_test.cc",

View File

@ -126,6 +126,8 @@ list(APPEND TINT_LIB_SRCS
ast/diagnostic_control.h
ast/diagnostic_directive.cc
ast/diagnostic_directive.h
ast/diagnostic_rule_name.cc
ast/diagnostic_rule_name.h
ast/disable_validation_attribute.cc
ast/disable_validation_attribute.h
ast/discard_statement.cc
@ -845,6 +847,7 @@ if(TINT_BUILD_TESTS)
ast/diagnostic_attribute_test.cc
ast/diagnostic_control_test.cc
ast/diagnostic_directive_test.cc
ast/diagnostic_rule_name_test.cc
ast/discard_statement_test.cc
ast/enable_test.cc
ast/float_literal_expression_test.cc

View File

@ -20,12 +20,20 @@ namespace {
using namespace tint::number_suffixes; // NOLINT
using DiagnosticAttributeTest = TestHelper;
TEST_F(DiagnosticAttributeTest, Creation) {
auto* name = Ident("foo");
auto* d = DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, name);
TEST_F(DiagnosticAttributeTest, Name) {
auto* d = DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "foo");
EXPECT_EQ(d->Name(), "diagnostic");
EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kWarning);
EXPECT_EQ(d->control.rule_name, name);
EXPECT_EQ(d->control.rule_name->category, nullptr);
CheckIdentifier(d->control.rule_name->name, "foo");
}
TEST_F(DiagnosticAttributeTest, CategoryAndName) {
auto* d = DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "foo", "bar");
EXPECT_EQ(d->Name(), "diagnostic");
EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kWarning);
CheckIdentifier(d->control.rule_name->category, "foo");
CheckIdentifier(d->control.rule_name->name, "bar");
}
} // namespace

View File

@ -24,13 +24,10 @@ namespace tint::ast {
DiagnosticControl::DiagnosticControl() = default;
DiagnosticControl::DiagnosticControl(builtin::DiagnosticSeverity sev, const Identifier* rule)
DiagnosticControl::DiagnosticControl(builtin::DiagnosticSeverity sev,
const DiagnosticRuleName* rule)
: severity(sev), rule_name(rule) {
TINT_ASSERT(AST, rule != nullptr);
if (rule) {
// It is invalid for a diagnostic rule name to be templated
TINT_ASSERT(AST, !rule->Is<TemplatedIdentifier>());
}
}
DiagnosticControl::DiagnosticControl(DiagnosticControl&&) = default;

View File

@ -23,7 +23,7 @@
// Forward declarations
namespace tint::ast {
class Identifier;
class DiagnosticRuleName;
} // namespace tint::ast
namespace tint::ast {
@ -37,16 +37,16 @@ struct DiagnosticControl {
/// Constructor
/// @param sev the diagnostic severity
/// @param rule the diagnostic rule name
DiagnosticControl(builtin::DiagnosticSeverity sev, const Identifier* rule);
DiagnosticControl(builtin::DiagnosticSeverity sev, const DiagnosticRuleName* rule);
/// Move constructor
DiagnosticControl(DiagnosticControl&&);
/// The diagnostic severity control.
builtin::DiagnosticSeverity severity;
builtin::DiagnosticSeverity severity = builtin::DiagnosticSeverity::kUndefined;
/// The diagnostic rule name.
const Identifier* rule_name;
const DiagnosticRuleName* rule_name = nullptr;
};
} // namespace tint::ast

View File

@ -24,12 +24,11 @@ namespace {
using DiagnosticControlTest = TestHelper;
TEST_F(DiagnosticControlTest, Assert_RuleNotTemplated) {
TEST_F(DiagnosticControlTest, Assert_RuleNotNull) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
DiagnosticControl control(builtin::DiagnosticSeverity::kWarning,
b.Ident("name", "a", "b", "c"));
DiagnosticControl control(builtin::DiagnosticSeverity::kWarning, nullptr);
},
"internal compiler error");
}

View File

@ -34,4 +34,5 @@ const DiagnosticDirective* DiagnosticDirective::Clone(CloneContext* ctx) const {
DiagnosticControl dc(control.severity, rule);
return ctx->dst->create<DiagnosticDirective>(src, std::move(dc));
}
} // namespace tint::ast

View File

@ -21,15 +21,28 @@ namespace {
using DiagnosticDirectiveTest = TestHelper;
TEST_F(DiagnosticDirectiveTest, Creation) {
auto* diag = DiagnosticDirective(Source{{{10, 5}, {10, 15}}},
builtin::DiagnosticSeverity::kWarning, "foo");
EXPECT_EQ(diag->source.range.begin.line, 10u);
EXPECT_EQ(diag->source.range.begin.column, 5u);
EXPECT_EQ(diag->source.range.end.line, 10u);
EXPECT_EQ(diag->source.range.end.column, 15u);
EXPECT_EQ(diag->control.severity, builtin::DiagnosticSeverity::kWarning);
CheckIdentifier(diag->control.rule_name, "foo");
TEST_F(DiagnosticDirectiveTest, Name) {
auto* d = DiagnosticDirective(Source{{{10, 5}, {10, 15}}},
builtin::DiagnosticSeverity::kWarning, "foo");
EXPECT_EQ(d->source.range.begin.line, 10u);
EXPECT_EQ(d->source.range.begin.column, 5u);
EXPECT_EQ(d->source.range.end.line, 10u);
EXPECT_EQ(d->source.range.end.column, 15u);
EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kWarning);
EXPECT_EQ(d->control.rule_name->category, nullptr);
CheckIdentifier(d->control.rule_name->name, "foo");
}
TEST_F(DiagnosticDirectiveTest, CategoryAndName) {
auto* d = DiagnosticDirective(Source{{{10, 5}, {10, 15}}},
builtin::DiagnosticSeverity::kWarning, "foo", "bar");
EXPECT_EQ(d->source.range.begin.line, 10u);
EXPECT_EQ(d->source.range.begin.column, 5u);
EXPECT_EQ(d->source.range.end.line, 10u);
EXPECT_EQ(d->source.range.end.column, 15u);
EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kWarning);
CheckIdentifier(d->control.rule_name->category, "foo");
CheckIdentifier(d->control.rule_name->name, "bar");
}
} // namespace

View File

@ -0,0 +1,74 @@
// 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.
#include "src/tint/ast/diagnostic_rule_name.h"
#include <string>
#include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::DiagnosticRuleName);
namespace tint::ast {
DiagnosticRuleName::DiagnosticRuleName(ProgramID pid,
NodeID nid,
const Source& src,
const Identifier* n)
: Base(pid, nid, src), name(n) {
TINT_ASSERT(AST, name != nullptr);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
if (name) {
// It is invalid for a diagnostic rule name to be templated
TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
}
}
DiagnosticRuleName::DiagnosticRuleName(ProgramID pid,
NodeID nid,
const Source& src,
const Identifier* c,
const Identifier* n)
: Base(pid, nid, src), category(c), name(n) {
TINT_ASSERT(AST, name != nullptr);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
if (name) {
// It is invalid for a diagnostic rule name to be templated
TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
}
if (category) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, category, program_id);
// It is invalid for a diagnostic rule category to be templated
TINT_ASSERT(AST, !category->Is<TemplatedIdentifier>());
}
}
const DiagnosticRuleName* DiagnosticRuleName::Clone(CloneContext* ctx) const {
auto src = ctx->Clone(source);
auto n = ctx->Clone(name);
if (auto c = ctx->Clone(category)) {
return ctx->dst->create<DiagnosticRuleName>(src, c, n);
}
return ctx->dst->create<DiagnosticRuleName>(src, n);
}
std::string DiagnosticRuleName::String() const {
if (category) {
return category->symbol.Name() + "." + name->symbol.Name();
} else {
return name->symbol.Name();
}
}
} // namespace tint::ast

View File

@ -0,0 +1,68 @@
// 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.
#ifndef SRC_TINT_AST_DIAGNOSTIC_RULE_NAME_H_
#define SRC_TINT_AST_DIAGNOSTIC_RULE_NAME_H_
#include <string>
#include "src/tint/ast/node.h"
// Forward declarations
namespace tint::ast {
class Identifier;
} // namespace tint::ast
namespace tint::ast {
/// A diagnostic rule name used for diagnostic directives and attributes.
class DiagnosticRuleName final : public utils::Castable<DiagnosticRuleName, Node> {
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 name the rule name
DiagnosticRuleName(ProgramID pid, NodeID nid, const Source& src, const Identifier* name);
/// 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 category the rule category.
/// @param name the rule name
DiagnosticRuleName(ProgramID pid,
NodeID nid,
const Source& src,
const Identifier* category,
const Identifier* name);
/// Clones this node and all transitive child nodes using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned node
const DiagnosticRuleName* Clone(CloneContext* ctx) const override;
/// @return the full name of this diagnostic rule, either as `name` or `category.name`.
std::string String() const;
/// The diagnostic rule category (category.name)
Identifier const* const category = nullptr;
/// The diagnostic rule name.
Identifier const* const name;
};
} // namespace tint::ast
#endif // SRC_TINT_AST_DIAGNOSTIC_RULE_NAME_H_

View File

@ -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.
#include <string>
#include "gtest/gtest-spi.h"
#include "src/tint/ast/diagnostic_rule_name.h"
#include "src/tint/ast/test_helper.h"
namespace tint::ast {
namespace {
using DiagnosticRuleNameTest = TestHelper;
TEST_F(DiagnosticRuleNameTest, String) {
EXPECT_EQ(DiagnosticRuleName("name")->String(), "name");
EXPECT_EQ(DiagnosticRuleName("category", "name")->String(), "category.name");
}
TEST_F(DiagnosticRuleNameTest, Assert_NameNotTemplated) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
b.create<ast::DiagnosticRuleName>(b.Ident("name", "a", "b", "c"));
},
"internal compiler error");
}
TEST_F(DiagnosticRuleNameTest, Assert_CategoryNotTemplated) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
b.create<ast::DiagnosticRuleName>(b.Ident("name"), b.Ident("category", "a", "b", "c"));
},
"internal compiler error");
}
} // namespace
} // namespace tint::ast

View File

@ -25,7 +25,7 @@ TEST(ModuleCloneTest, Clone) {
// Shader that exercises the bulk of the AST nodes and types.
// See also fuzzers/tint_ast_clone_fuzzer.cc for further coverage of cloning.
Source::File file("test.wgsl", R"(enable f16;
diagnostic(off, chromium_unreachable_code);
diagnostic(off, chromium.unreachable_code);
struct S0 {
@size(4)
@ -65,7 +65,7 @@ fn f0(p0 : bool) -> f32 {
return 0.0;
}
@diagnostic(warning, chromium_unreachable_code)
@diagnostic(warning, chromium.unreachable_code)
fn f1(p0 : f32, p1 : i32) -> f32 {
var l0 : i32 = 3;
var l1 : f32 = 8.0;

View File

@ -28,29 +28,45 @@
namespace tint::builtin {
/// ParseDiagnosticRule parses a DiagnosticRule from a string.
/// ParseCoreDiagnosticRule parses a CoreDiagnosticRule from a string.
/// @param str the string to parse
/// @returns the parsed enum, or DiagnosticRule::kUndefined if the string could not be parsed.
DiagnosticRule ParseDiagnosticRule(std::string_view str) {
if (str == "chromium_unreachable_code") {
return DiagnosticRule::kChromiumUnreachableCode;
}
/// @returns the parsed enum, or CoreDiagnosticRule::kUndefined if the string could not be parsed.
CoreDiagnosticRule ParseCoreDiagnosticRule(std::string_view str) {
if (str == "derivative_uniformity") {
return DiagnosticRule::kDerivativeUniformity;
return CoreDiagnosticRule::kDerivativeUniformity;
}
return DiagnosticRule::kUndefined;
return CoreDiagnosticRule::kUndefined;
}
utils::StringStream& operator<<(utils::StringStream& out, DiagnosticRule value) {
utils::StringStream& operator<<(utils::StringStream& out, CoreDiagnosticRule value) {
switch (value) {
case DiagnosticRule::kUndefined:
case CoreDiagnosticRule::kUndefined:
return out << "undefined";
case DiagnosticRule::kChromiumUnreachableCode:
return out << "chromium_unreachable_code";
case DiagnosticRule::kDerivativeUniformity:
case CoreDiagnosticRule::kDerivativeUniformity:
return out << "derivative_uniformity";
}
return out << "<unknown>";
}
/// ParseChromiumDiagnosticRule parses a ChromiumDiagnosticRule from a string.
/// @param str the string to parse
/// @returns the parsed enum, or ChromiumDiagnosticRule::kUndefined if the string could not be
/// parsed.
ChromiumDiagnosticRule ParseChromiumDiagnosticRule(std::string_view str) {
if (str == "unreachable_code") {
return ChromiumDiagnosticRule::kUnreachableCode;
}
return ChromiumDiagnosticRule::kUndefined;
}
utils::StringStream& operator<<(utils::StringStream& out, ChromiumDiagnosticRule value) {
switch (value) {
case ChromiumDiagnosticRule::kUndefined:
return out << "undefined";
case ChromiumDiagnosticRule::kUnreachableCode:
return out << "unreachable_code";
}
return out << "<unknown>";
}
} // namespace tint::builtin

View File

@ -18,8 +18,12 @@ See:
namespace tint::builtin {
{{ Eval "ParseEnum" (Sem.Enum "diagnostic_rule")}}
{{ Eval "ParseEnum" (Sem.Enum "core_diagnostic_rule")}}
{{ Eval "EnumOStream" (Sem.Enum "diagnostic_rule")}}
{{ Eval "EnumOStream" (Sem.Enum "core_diagnostic_rule")}}
{{ Eval "ParseEnum" (Sem.Enum "chromium_diagnostic_rule")}}
{{ Eval "EnumOStream" (Sem.Enum "chromium_diagnostic_rule")}}
} // namespace tint::builtin

View File

@ -24,33 +24,56 @@
#define SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
#include <string>
#include <variant>
#include "src/tint/utils/string_stream.h"
namespace tint::builtin {
/// The diagnostic rule.
enum class DiagnosticRule {
/// WGSL core diagnostic rules.
enum class CoreDiagnosticRule {
kUndefined,
kChromiumUnreachableCode,
kDerivativeUniformity,
};
/// @param out the stream to write to
/// @param value the DiagnosticRule
/// @param value the CoreDiagnosticRule
/// @returns `out` so calls can be chained
utils::StringStream& operator<<(utils::StringStream& out, DiagnosticRule value);
utils::StringStream& operator<<(utils::StringStream& out, CoreDiagnosticRule value);
/// ParseDiagnosticRule parses a DiagnosticRule from a string.
/// ParseCoreDiagnosticRule parses a CoreDiagnosticRule from a string.
/// @param str the string to parse
/// @returns the parsed enum, or DiagnosticRule::kUndefined if the string could not be parsed.
DiagnosticRule ParseDiagnosticRule(std::string_view str);
/// @returns the parsed enum, or CoreDiagnosticRule::kUndefined if the string could not be parsed.
CoreDiagnosticRule ParseCoreDiagnosticRule(std::string_view str);
constexpr const char* kDiagnosticRuleStrings[] = {
"chromium_unreachable_code",
constexpr const char* kCoreDiagnosticRuleStrings[] = {
"derivative_uniformity",
};
/// Chromium-specific diagnostic rules.
enum class ChromiumDiagnosticRule {
kUndefined,
kUnreachableCode,
};
/// @param out the stream to write to
/// @param value the ChromiumDiagnosticRule
/// @returns `out` so calls can be chained
utils::StringStream& operator<<(utils::StringStream& out, ChromiumDiagnosticRule value);
/// ParseChromiumDiagnosticRule parses a ChromiumDiagnosticRule from a string.
/// @param str the string to parse
/// @returns the parsed enum, or ChromiumDiagnosticRule::kUndefined if the string could not be
/// parsed.
ChromiumDiagnosticRule ParseChromiumDiagnosticRule(std::string_view str);
constexpr const char* kChromiumDiagnosticRuleStrings[] = {
"unreachable_code",
};
/// All diagnostic rules understood by Tint.
using DiagnosticRule = std::variant<CoreDiagnosticRule, ChromiumDiagnosticRule>;
} // namespace tint::builtin
#endif // SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_

View File

@ -14,13 +14,20 @@ See:
#define SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
#include <string>
#include <variant>
#include "src/tint/utils/string_stream.h"
namespace tint::builtin {
/// The diagnostic rule.
{{ Eval "DeclareEnum" (Sem.Enum "diagnostic_rule") }}
/// WGSL core diagnostic rules.
{{ Eval "DeclareEnum" (Sem.Enum "core_diagnostic_rule") }}
/// Chromium-specific diagnostic rules.
{{ Eval "DeclareEnum" (Sem.Enum "chromium_diagnostic_rule") }}
/// All diagnostic rules understood by Tint.
using DiagnosticRule = std::variant<CoreDiagnosticRule, ChromiumDiagnosticRule>;
} // namespace tint::builtin

View File

@ -29,23 +29,36 @@
namespace tint::builtin {
namespace {
void DiagnosticRuleParser(::benchmark::State& state) {
void CoreDiagnosticRuleParser(::benchmark::State& state) {
const char* kStrings[] = {
"chromium_unrachaccle_code", "clromium_unreachab3_oe", "chromium_unreachable_Vode",
"chromium_unreachable_code", "chro1ium_unreachable_code", "chromium_unreJchableqqcde",
"chromium77unreallhable_code", "dqqrvatiHHe_uniforppity", "deriatcv_nvformity",
"derivatbe_unGformity", "derivative_uniformity", "derivative_iinifvrmity",
"derivat8WWe_uniformity", "drivaxxive_uniformity",
"deriative_unccformity", "dlivative_3iformiy", "derivative_uniforVity",
"derivative_uniformity", "derivative_uniform1ty", "derivativeJunifqrmity",
"derivative_unifllrmit77",
};
for (auto _ : state) {
for (auto* str : kStrings) {
auto result = ParseDiagnosticRule(str);
auto result = ParseCoreDiagnosticRule(str);
benchmark::DoNotOptimize(result);
}
}
}
BENCHMARK(DiagnosticRuleParser);
BENCHMARK(CoreDiagnosticRuleParser);
void ChromiumDiagnosticRuleParser(::benchmark::State& state) {
const char* kStrings[] = {
"pqnreachableHHcode", "unrechcbe_cov", "unreachGblecode", "unreachable_code",
"vnriiachable_code", "unreac8ablWW_code", "unreMchablxxcode",
};
for (auto _ : state) {
for (auto* str : kStrings) {
auto result = ParseChromiumDiagnosticRule(str);
benchmark::DoNotOptimize(result);
}
}
}
BENCHMARK(ChromiumDiagnosticRuleParser);
} // namespace
} // namespace tint::builtin

View File

@ -19,7 +19,9 @@ See:
namespace tint::builtin {
namespace {
{{ Eval "BenchmarkParseEnum" (Sem.Enum "diagnostic_rule")}}
{{ Eval "BenchmarkParseEnum" (Sem.Enum "core_diagnostic_rule")}}
{{ Eval "BenchmarkParseEnum" (Sem.Enum "chromium_diagnostic_rule")}}
} // namespace
} // namespace tint::builtin

View File

@ -29,13 +29,13 @@
namespace tint::builtin {
namespace {
namespace diagnostic_rule_tests {
namespace core_diagnostic_rule_tests {
namespace parse_print_tests {
struct Case {
const char* string;
DiagnosticRule value;
CoreDiagnosticRule value;
};
inline std::ostream& operator<<(std::ostream& out, Case c) {
@ -43,43 +43,95 @@ inline std::ostream& operator<<(std::ostream& out, Case c) {
}
static constexpr Case kValidCases[] = {
{"chromium_unreachable_code", DiagnosticRule::kChromiumUnreachableCode},
{"derivative_uniformity", DiagnosticRule::kDerivativeUniformity},
{"derivative_uniformity", CoreDiagnosticRule::kDerivativeUniformity},
};
static constexpr Case kInvalidCases[] = {
{"chromium_unrachaccle_code", DiagnosticRule::kUndefined},
{"clromium_unreachab3_oe", DiagnosticRule::kUndefined},
{"chromium_unreachable_Vode", DiagnosticRule::kUndefined},
{"derivative_uniform1ty", DiagnosticRule::kUndefined},
{"derivativeJunifqrmity", DiagnosticRule::kUndefined},
{"derivative_unifllrmit77", DiagnosticRule::kUndefined},
{"deriative_unccformity", CoreDiagnosticRule::kUndefined},
{"dlivative_3iformiy", CoreDiagnosticRule::kUndefined},
{"derivative_uniforVity", CoreDiagnosticRule::kUndefined},
};
using DiagnosticRuleParseTest = testing::TestWithParam<Case>;
using CoreDiagnosticRuleParseTest = testing::TestWithParam<Case>;
TEST_P(DiagnosticRuleParseTest, Parse) {
TEST_P(CoreDiagnosticRuleParseTest, Parse) {
const char* string = GetParam().string;
DiagnosticRule expect = GetParam().value;
EXPECT_EQ(expect, ParseDiagnosticRule(string));
CoreDiagnosticRule expect = GetParam().value;
EXPECT_EQ(expect, ParseCoreDiagnosticRule(string));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticRuleParseTest, testing::ValuesIn(kValidCases));
INSTANTIATE_TEST_SUITE_P(InvalidCases, DiagnosticRuleParseTest, testing::ValuesIn(kInvalidCases));
INSTANTIATE_TEST_SUITE_P(ValidCases, CoreDiagnosticRuleParseTest, testing::ValuesIn(kValidCases));
INSTANTIATE_TEST_SUITE_P(InvalidCases,
CoreDiagnosticRuleParseTest,
testing::ValuesIn(kInvalidCases));
using DiagnosticRulePrintTest = testing::TestWithParam<Case>;
using CoreDiagnosticRulePrintTest = testing::TestWithParam<Case>;
TEST_P(DiagnosticRulePrintTest, Print) {
DiagnosticRule value = GetParam().value;
TEST_P(CoreDiagnosticRulePrintTest, Print) {
CoreDiagnosticRule value = GetParam().value;
const char* expect = GetParam().string;
EXPECT_EQ(expect, utils::ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticRulePrintTest, testing::ValuesIn(kValidCases));
INSTANTIATE_TEST_SUITE_P(ValidCases, CoreDiagnosticRulePrintTest, testing::ValuesIn(kValidCases));
} // namespace parse_print_tests
} // namespace diagnostic_rule_tests
} // namespace core_diagnostic_rule_tests
namespace chromium_diagnostic_rule_tests {
namespace parse_print_tests {
struct Case {
const char* string;
ChromiumDiagnosticRule value;
};
inline std::ostream& operator<<(std::ostream& out, Case c) {
return out << "'" << std::string(c.string) << "'";
}
static constexpr Case kValidCases[] = {
{"unreachable_code", ChromiumDiagnosticRule::kUnreachableCode},
};
static constexpr Case kInvalidCases[] = {
{"unreacha1le_code", ChromiumDiagnosticRule::kUndefined},
{"unreachableJcqde", ChromiumDiagnosticRule::kUndefined},
{"unreachable77llode", ChromiumDiagnosticRule::kUndefined},
};
using ChromiumDiagnosticRuleParseTest = testing::TestWithParam<Case>;
TEST_P(ChromiumDiagnosticRuleParseTest, Parse) {
const char* string = GetParam().string;
ChromiumDiagnosticRule expect = GetParam().value;
EXPECT_EQ(expect, ParseChromiumDiagnosticRule(string));
}
INSTANTIATE_TEST_SUITE_P(ValidCases,
ChromiumDiagnosticRuleParseTest,
testing::ValuesIn(kValidCases));
INSTANTIATE_TEST_SUITE_P(InvalidCases,
ChromiumDiagnosticRuleParseTest,
testing::ValuesIn(kInvalidCases));
using ChromiumDiagnosticRulePrintTest = testing::TestWithParam<Case>;
TEST_P(ChromiumDiagnosticRulePrintTest, Print) {
ChromiumDiagnosticRule value = GetParam().value;
const char* expect = GetParam().string;
EXPECT_EQ(expect, utils::ToString(value));
}
INSTANTIATE_TEST_SUITE_P(ValidCases,
ChromiumDiagnosticRulePrintTest,
testing::ValuesIn(kValidCases));
} // namespace parse_print_tests
} // namespace chromium_diagnostic_rule_tests
} // namespace
} // namespace tint::builtin

View File

@ -19,11 +19,17 @@ See:
namespace tint::builtin {
namespace {
namespace diagnostic_rule_tests {
namespace core_diagnostic_rule_tests {
{{ Eval "TestParsePrintEnum" (Sem.Enum "diagnostic_rule")}}
{{ Eval "TestParsePrintEnum" (Sem.Enum "core_diagnostic_rule")}}
} // namespace diagnostic_rule_tests
} // namespace core_diagnostic_rule_tests
namespace chromium_diagnostic_rule_tests {
{{ Eval "TestParsePrintEnum" (Sem.Enum "chromium_diagnostic_rule")}}
} // namespace chromium_diagnostic_rule_tests
} // namespace
} // namespace tint::builtin

View File

@ -41,11 +41,15 @@ enum builtin_value {
}
// https://gpuweb.github.io/gpuweb/wgsl/#filterable-triggering-rules
enum diagnostic_rule {
enum core_diagnostic_rule {
// Rules defined in the spec.
derivative_uniformity
}
// chromium-specific diagnostics
enum chromium_diagnostic_rule {
// Chromium specific rules not defined in the spec.
chromium_unreachable_code
unreachable_code
}
// https://gpuweb.github.io/gpuweb/wgsl/#syntax-severity_control_name

View File

@ -39,6 +39,7 @@
#include "src/tint/ast/diagnostic_attribute.h"
#include "src/tint/ast/diagnostic_control.h"
#include "src/tint/ast/diagnostic_directive.h"
#include "src/tint/ast/diagnostic_rule_name.h"
#include "src/tint/ast/disable_validation_attribute.h"
#include "src/tint/ast/discard_statement.h"
#include "src/tint/ast/enable.h"
@ -3752,57 +3753,129 @@ class ProgramBuilder {
validation);
}
/// Creates an ast::DiagnosticAttribute
/// @param source the source information
/// @param severity the diagnostic severity control
/// @param rule_name the diagnostic rule name
/// @returns the diagnostic attribute pointer
/// Passthrough overload
/// @param name the diagnostic rule name
/// @returns @p name
const ast::DiagnosticRuleName* DiagnosticRuleName(const ast::DiagnosticRuleName* name) {
return name;
}
/// Creates an ast::DiagnosticRuleName
/// @param name the diagnostic rule name
/// @returns the diagnostic rule name
template <typename NAME>
const ast::DiagnosticAttribute* DiagnosticAttribute(const Source& source,
builtin::DiagnosticSeverity severity,
NAME&& rule_name) {
const ast::DiagnosticRuleName* DiagnosticRuleName(NAME&& name) {
static_assert(
!utils::traits::IsType<utils::traits::PtrElTy<NAME>, ast::TemplatedIdentifier>,
"it is invalid for a diagnostic rule name to be templated");
auto* name_ident = Ident(std::forward<NAME>(name));
return create<ast::DiagnosticRuleName>(name_ident->source, name_ident);
}
/// Creates an ast::DiagnosticRuleName
/// @param category the diagnostic rule category
/// @param name the diagnostic rule name
/// @returns the diagnostic rule name
template <typename CATEGORY, typename NAME, typename = DisableIfSource<CATEGORY>>
const ast::DiagnosticRuleName* DiagnosticRuleName(CATEGORY&& category, NAME&& name) {
static_assert(
!utils::traits::IsType<utils::traits::PtrElTy<NAME>, ast::TemplatedIdentifier>,
"it is invalid for a diagnostic rule name to be templated");
static_assert(
!utils::traits::IsType<utils::traits::PtrElTy<CATEGORY>, ast::TemplatedIdentifier>,
"it is invalid for a diagnostic rule category to be templated");
auto* category_ident = Ident(std::forward<CATEGORY>(category));
auto* name_ident = Ident(std::forward<NAME>(name));
Source source = category_ident->source;
source.range.end = name_ident->source.range.end;
return create<ast::DiagnosticRuleName>(source, category_ident, name_ident);
}
/// Creates an ast::DiagnosticRuleName
/// @param source the source information
/// @param name the diagnostic rule name
/// @returns the diagnostic rule name
template <typename NAME>
const ast::DiagnosticRuleName* DiagnosticRuleName(const Source& source, NAME&& name) {
static_assert(
!utils::traits::IsType<utils::traits::PtrElTy<NAME>, ast::TemplatedIdentifier>,
"it is invalid for a diagnostic rule name to be templated");
auto* name_ident = Ident(std::forward<NAME>(name));
return create<ast::DiagnosticRuleName>(source, name_ident);
}
/// Creates an ast::DiagnosticRuleName
/// @param source the source information
/// @param category the diagnostic rule category
/// @param name the diagnostic rule name
/// @returns the diagnostic rule name
template <typename CATEGORY, typename NAME>
const ast::DiagnosticRuleName* DiagnosticRuleName(const Source& source,
CATEGORY&& category,
NAME&& name) {
static_assert(
!utils::traits::IsType<utils::traits::PtrElTy<NAME>, ast::TemplatedIdentifier>,
"it is invalid for a diagnostic rule name to be templated");
static_assert(
!utils::traits::IsType<utils::traits::PtrElTy<CATEGORY>, ast::TemplatedIdentifier>,
"it is invalid for a diagnostic rule category to be templated");
auto* category_ident = Ident(std::forward<CATEGORY>(category));
auto* name_ident = Ident(std::forward<NAME>(name));
return create<ast::DiagnosticRuleName>(source, category_ident, name_ident);
}
/// Creates an ast::DiagnosticAttribute
/// @param source the source information
/// @param severity the diagnostic severity control
/// @param rule_args the arguments used to construct the rule name
/// @returns the diagnostic attribute pointer
template <typename... RULE_ARGS>
const ast::DiagnosticAttribute* DiagnosticAttribute(const Source& source,
builtin::DiagnosticSeverity severity,
RULE_ARGS&&... rule_args) {
return create<ast::DiagnosticAttribute>(
source, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
source, ast::DiagnosticControl(
severity, DiagnosticRuleName(std::forward<RULE_ARGS>(rule_args)...)));
}
/// Creates an ast::DiagnosticAttribute
/// @param severity the diagnostic severity control
/// @param rule_name the diagnostic rule name
/// @param rule_args the arguments used to construct the rule name
/// @returns the diagnostic attribute pointer
template <typename NAME>
template <typename... RULE_ARGS>
const ast::DiagnosticAttribute* DiagnosticAttribute(builtin::DiagnosticSeverity severity,
NAME&& rule_name) {
RULE_ARGS&&... rule_args) {
return create<ast::DiagnosticAttribute>(
source_, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
source_, ast::DiagnosticControl(
severity, DiagnosticRuleName(std::forward<RULE_ARGS>(rule_args)...)));
}
/// Add a diagnostic directive to the module.
/// @param source the source information
/// @param severity the diagnostic severity control
/// @param rule_name the diagnostic rule name
/// @param rule_args the arguments used to construct the rule name
/// @returns the diagnostic directive pointer
template <typename NAME>
template <typename... RULE_ARGS>
const ast::DiagnosticDirective* DiagnosticDirective(const Source& source,
builtin::DiagnosticSeverity severity,
NAME&& rule_name) {
auto* directive = create<ast::DiagnosticDirective>(
source, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
RULE_ARGS&&... rule_args) {
auto* rule = DiagnosticRuleName(std::forward<RULE_ARGS>(rule_args)...);
auto* directive =
create<ast::DiagnosticDirective>(source, ast::DiagnosticControl(severity, rule));
AST().AddDiagnosticDirective(directive);
return directive;
}
/// Add a diagnostic directive to the module.
/// @param severity the diagnostic severity control
/// @param rule_name the diagnostic rule name
/// @param rule_args the arguments used to construct the rule name
/// @returns the diagnostic directive pointer
template <typename NAME>
template <typename... RULE_ARGS>
const ast::DiagnosticDirective* DiagnosticDirective(builtin::DiagnosticSeverity severity,
NAME&& rule_name) {
auto* directive = create<ast::DiagnosticDirective>(
source_, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
RULE_ARGS&&... rule_args) {
auto* rule = DiagnosticRuleName(std::forward<RULE_ARGS>(rule_args)...);
auto* directive =
create<ast::DiagnosticDirective>(source_, ast::DiagnosticControl(severity, rule));
AST().AddDiagnosticDirective(directive);
return directive;
}

View File

@ -3092,7 +3092,7 @@ Expect<builtin::DiagnosticSeverity> ParserImpl::expect_severity_control_name() {
}
// diagnostic_control
// : PAREN_LEFT severity_control_name COMMA ident_pattern_token COMMA ? PAREN_RIGHT
// : PAREN_LEFT severity_control_name COMMA diagnostic_rule_name COMMA ? PAREN_RIGHT
Expect<ast::DiagnosticControl> ParserImpl::expect_diagnostic_control() {
return expect_paren_block("diagnostic control", [&]() -> Expect<ast::DiagnosticControl> {
auto severity_control = expect_severity_control_name();
@ -3104,7 +3104,7 @@ Expect<ast::DiagnosticControl> ParserImpl::expect_diagnostic_control() {
return Failure::kErrored;
}
auto rule_name = expect_ident("diagnostic control");
auto rule_name = expect_diagnostic_rule_name();
if (rule_name.errored) {
return Failure::kErrored;
}
@ -3114,6 +3114,31 @@ Expect<ast::DiagnosticControl> ParserImpl::expect_diagnostic_control() {
});
}
// diagnostic_rule_name :
// | diagnostic_name_token
// | diagnostic_name_token '.' diagnostic_name_token
Expect<const ast::DiagnosticRuleName*> ParserImpl::expect_diagnostic_rule_name() {
if (peek_is(Token::Type::kPeriod, 1)) {
auto category = expect_ident("", "diagnostic rule category");
if (category.errored) {
return Failure::kErrored;
}
if (!expect("diagnostic rule", Token::Type::kPeriod)) {
return Failure::kErrored;
}
auto name = expect_ident("", "diagnostic rule name");
if (name.errored) {
return Failure::kErrored;
}
return builder_.DiagnosticRuleName(category.value, name.value);
}
auto name = expect_ident("", "diagnostic rule name");
if (name.errored) {
return Failure::kErrored;
}
return builder_.DiagnosticRuleName(name.value);
}
bool ParserImpl::match(Token::Type tok, Source* source /*= nullptr*/) {
auto& t = peek();
@ -3214,7 +3239,9 @@ Expect<uint32_t> ParserImpl::expect_nonzero_positive_sint(std::string_view use)
return {static_cast<uint32_t>(sint.value), sint.source};
}
Expect<const ast::Identifier*> ParserImpl::expect_ident(std::string_view use) {
Expect<const ast::Identifier*> ParserImpl::expect_ident(
std::string_view use,
std::string_view kind /* = "identifier" */) {
auto& t = peek();
if (t.IsIdentifier()) {
synchronized_ = true;
@ -3230,7 +3257,7 @@ Expect<const ast::Identifier*> ParserImpl::expect_ident(std::string_view use) {
return Failure::kErrored;
}
synchronized_ = false;
return add_error(t.source(), "expected identifier", use);
return add_error(t.source(), "expected " + std::string(kind), use);
}
template <typename F, typename T>

View File

@ -636,14 +636,17 @@ class ParserImpl {
/// Parses a single attribute, reporting an error if the next token does not
/// represent a attribute.
/// @see #attribute for the full list of attributes this method parses.
/// @return the parsed attribute, or nullptr on error.
/// @return the parsed attribute.
Expect<const ast::Attribute*> expect_attribute();
/// Parses a severity_control_name grammar element.
/// @return the parsed severity control name, or nullptr on error.
/// @return the parsed severity control name.
Expect<builtin::DiagnosticSeverity> expect_severity_control_name();
/// Parses a diagnostic_control grammar element.
/// @return the parsed diagnostic control, or nullptr on error.
/// @return the parsed diagnostic control.
Expect<ast::DiagnosticControl> expect_diagnostic_control();
/// Parses a diagnostic_rule_name grammar element.
/// @return the parsed diagnostic rule name.
Expect<const ast::DiagnosticRuleName*> expect_diagnostic_rule_name();
/// Splits a peekable token into to parts filling in the peekable fields.
/// @param lhs the token to set in the current position
@ -694,8 +697,11 @@ class ParserImpl {
/// Errors if the next token is not an identifier.
/// Consumes the next token on match.
/// @param use a description of what was being parsed if an error was raised
/// @param kind a string describing the kind of identifier.
/// Examples: "identifier", "diagnostic name"
/// @returns the parsed identifier.
Expect<const ast::Identifier*> expect_ident(std::string_view use);
Expect<const ast::Identifier*> expect_ident(std::string_view use,
std::string_view kind = "identifier");
/// Parses a lexical block starting with the token `start` and ending with
/// the token `end`. `body` is called to parse the lexical block body
/// between the `start` and `end` tokens. If the `start` or `end` tokens

View File

@ -20,7 +20,7 @@
namespace tint::reader::wgsl {
namespace {
TEST_F(ParserImplTest, DiagnosticAttribute_Valid) {
TEST_F(ParserImplTest, DiagnosticAttribute_Name) {
auto p = parser("diagnostic(off, foo)");
auto a = p->attribute();
EXPECT_FALSE(p->has_error()) << p->error();
@ -30,7 +30,22 @@ TEST_F(ParserImplTest, DiagnosticAttribute_Valid) {
EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kOff);
auto* r = d->control.rule_name;
ASSERT_NE(r, nullptr);
ast::CheckIdentifier(r, "foo");
EXPECT_EQ(r->category, nullptr);
ast::CheckIdentifier(r->name, "foo");
}
TEST_F(ParserImplTest, DiagnosticAttribute_CategoryName) {
auto p = parser("diagnostic(off, foo.bar)");
auto a = p->attribute();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(a.matched);
auto* d = a.value->As<ast::DiagnosticAttribute>();
ASSERT_NE(d, nullptr);
EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kOff);
auto* r = d->control.rule_name;
ASSERT_NE(r, nullptr);
ast::CheckIdentifier(r->category, "foo");
ast::CheckIdentifier(r->name, "bar");
}
} // namespace

View File

@ -23,7 +23,7 @@ namespace {
using SeverityPair = std::pair<std::string, builtin::DiagnosticSeverity>;
class DiagnosticControlParserTest : public ParserImplTestWithParam<SeverityPair> {};
TEST_P(DiagnosticControlParserTest, DiagnosticControl_Valid) {
TEST_P(DiagnosticControlParserTest, DiagnosticControl_Name) {
auto& params = GetParam();
auto p = parser("(" + params.first + ", foo)");
auto e = p->expect_diagnostic_control();
@ -33,7 +33,21 @@ TEST_P(DiagnosticControlParserTest, DiagnosticControl_Valid) {
auto* r = e->rule_name;
ASSERT_NE(r, nullptr);
ast::CheckIdentifier(r, "foo");
EXPECT_EQ(r->category, nullptr);
ast::CheckIdentifier(r->name, "foo");
}
TEST_P(DiagnosticControlParserTest, DiagnosticControl_CategoryAndName) {
auto& params = GetParam();
auto p = parser("(" + params.first + ", foo.bar)");
auto e = p->expect_diagnostic_control();
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e->severity, params.second);
auto* r = e->rule_name;
ASSERT_NE(r, nullptr);
ast::CheckIdentifier(r->category, "foo");
ast::CheckIdentifier(r->name, "bar");
}
INSTANTIATE_TEST_SUITE_P(DiagnosticControlParserTest,
DiagnosticControlParserTest,
@ -43,7 +57,7 @@ INSTANTIATE_TEST_SUITE_P(DiagnosticControlParserTest,
SeverityPair{"info", builtin::DiagnosticSeverity::kInfo},
SeverityPair{"off", builtin::DiagnosticSeverity::kOff}));
TEST_F(ParserImplTest, DiagnosticControl_Valid_TrailingComma) {
TEST_F(ParserImplTest, DiagnosticControl_Name_TrailingComma) {
auto p = parser("(error, foo,)");
auto e = p->expect_diagnostic_control();
EXPECT_FALSE(e.errored);
@ -52,7 +66,21 @@ TEST_F(ParserImplTest, DiagnosticControl_Valid_TrailingComma) {
auto* r = e->rule_name;
ASSERT_NE(r, nullptr);
ast::CheckIdentifier(r, "foo");
EXPECT_EQ(r->category, nullptr);
ast::CheckIdentifier(r->name, "foo");
}
TEST_F(ParserImplTest, DiagnosticControl_CategoryAndName_TrailingComma) {
auto p = parser("(error, foo.bar,)");
auto e = p->expect_diagnostic_control();
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e->severity, builtin::DiagnosticSeverity::kError);
auto* r = e->rule_name;
ASSERT_NE(r, nullptr);
ast::CheckIdentifier(r->category, "foo");
ast::CheckIdentifier(r->name, "bar");
}
TEST_F(ParserImplTest, DiagnosticControl_MissingOpenParen) {
@ -102,7 +130,15 @@ TEST_F(ParserImplTest, DiagnosticControl_MissingRuleName) {
auto e = p->expect_diagnostic_control();
EXPECT_TRUE(e.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:6: expected identifier for diagnostic control)");
EXPECT_EQ(p->error(), R"(1:6: expected diagnostic rule name)");
}
TEST_F(ParserImplTest, DiagnosticControl_MissingRuleCategory) {
auto p = parser("(off,for.foo)");
auto e = p->expect_diagnostic_control();
EXPECT_TRUE(e.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:6: expected diagnostic rule category)");
}
TEST_F(ParserImplTest, DiagnosticControl_InvalidRuleName) {

View File

@ -20,7 +20,7 @@
namespace tint::reader::wgsl {
namespace {
TEST_F(ParserImplTest, DiagnosticDirective_Valid) {
TEST_F(ParserImplTest, DiagnosticDirective_Name) {
auto p = parser("diagnostic(off, foo);");
p->diagnostic_directive();
EXPECT_FALSE(p->has_error()) << p->error();
@ -33,7 +33,25 @@ TEST_F(ParserImplTest, DiagnosticDirective_Valid) {
auto* r = directive->control.rule_name;
ASSERT_NE(r, nullptr);
ast::CheckIdentifier(r, "foo");
EXPECT_EQ(r->category, nullptr);
ast::CheckIdentifier(r->name, "foo");
}
TEST_F(ParserImplTest, DiagnosticDirective_CategoryName) {
auto p = parser("diagnostic(off, foo.bar);");
p->diagnostic_directive();
EXPECT_FALSE(p->has_error()) << p->error();
auto& ast = p->builder().AST();
ASSERT_EQ(ast.DiagnosticDirectives().Length(), 1u);
auto* directive = ast.DiagnosticDirectives()[0];
EXPECT_EQ(directive->control.severity, builtin::DiagnosticSeverity::kOff);
ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
EXPECT_EQ(ast.GlobalDeclarations()[0], directive);
auto* r = directive->control.rule_name;
ASSERT_NE(r, nullptr);
ast::CheckIdentifier(r->category, "foo");
ast::CheckIdentifier(r->name, "bar");
}
TEST_F(ParserImplTest, DiagnosticDirective_MissingSemicolon) {

View File

@ -101,7 +101,7 @@ static utils::Vector<const ast::Attribute*, 2> createAttributes(const Source& so
return {builder.Builtin(source, builtin::BuiltinValue::kPosition)};
case AttributeKind::kDiagnostic:
return {builder.DiagnosticAttribute(source, builtin::DiagnosticSeverity::kInfo,
"chromium_unreachable_code")};
"chromium", "unreachable_code")};
case AttributeKind::kGroup:
return {builder.Group(source, 1_a)};
case AttributeKind::kId:

View File

@ -32,7 +32,7 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_DefaultSeverity) {
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts);
@ -42,7 +42,7 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective) {
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaDirective) {
DiagnosticDirective(builtin::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
DiagnosticDirective(builtin::DiagnosticSeverity::kWarning, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts);
@ -52,7 +52,7 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaDirective) {
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaDirective) {
DiagnosticDirective(builtin::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
DiagnosticDirective(builtin::DiagnosticSeverity::kInfo, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts);
@ -62,7 +62,7 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaDirective) {
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaDirective) {
DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_code");
DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts);
@ -73,7 +73,7 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaDirective) {
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaAttribute) {
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@ -84,7 +84,7 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaAttribute) {
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaAttribute) {
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@ -95,7 +95,7 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaAttribute) {
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaAttribute) {
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@ -106,7 +106,7 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaAttribute) {
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaAttribute) {
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_code");
DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@ -116,15 +116,15 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaAttribute) {
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective_OverriddenViaAttribute) {
// diagnostic(error, chromium_unreachable_code);
// diagnostic(error, chromium.unreachable_code);
//
// @diagnostic(off, chromium_unreachable_code) fn foo() {
// @diagnostic(off, chromium.unreachable_code) fn foo() {
// return;
// return; // Should produce a warning
// }
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@ -134,7 +134,7 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective_Overridd
}
TEST_F(ResolverDiagnosticControlTest, FunctionAttributeScope) {
// @diagnostic(off, chromium_unreachable_code) fn foo() {
// @diagnostic(off, chromium.unreachable_code) fn foo() {
// return;
// return; // Should not produce a diagnostic
// }
@ -144,13 +144,13 @@ TEST_F(ResolverDiagnosticControlTest, FunctionAttributeScope) {
// return; // Should produce a warning (default severity)
// }
//
// @diagnostic(info, chromium_unreachable_code) fn bar() {
// @diagnostic(info, chromium.unreachable_code) fn bar() {
// return;
// return; // Should produce an info
// }
{
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_code");
DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_code");
Func("foo", {}, ty.void_(),
utils::Vector{
Return(),
@ -167,7 +167,7 @@ TEST_F(ResolverDiagnosticControlTest, FunctionAttributeScope) {
}
{
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium", "unreachable_code");
Func("zoo", {}, ty.void_(),
utils::Vector{
Return(),
@ -182,17 +182,17 @@ TEST_F(ResolverDiagnosticControlTest, FunctionAttributeScope) {
}
TEST_F(ResolverDiagnosticControlTest, BlockAttributeScope) {
// fn foo() @diagnostic(off, chromium_unreachable_code) {
// fn foo() @diagnostic(off, chromium.unreachable_code) {
// {
// return;
// return; // Should not produce a diagnostic
// }
// @diagnostic(warning, chromium_unreachable_code) {
// if (true) @diagnostic(info, chromium_unreachable_code) {
// @diagnostic(warning, chromium.unreachable_code) {
// if (true) @diagnostic(info, chromium.unreachable_code) {
// return;
// return; // Should produce an info
// } else {
// while (true) @diagnostic(off, chromium_unreachable_code) {
// while (true) @diagnostic(off, chromium.unreachable_code) {
// return;
// return; // Should not produce a diagnostic
// }
@ -203,7 +203,7 @@ TEST_F(ResolverDiagnosticControlTest, BlockAttributeScope) {
// }
auto attr = [&](auto severity) {
return utils::Vector{DiagnosticAttribute(severity, "chromium_unreachable_code")};
return utils::Vector{DiagnosticAttribute(severity, "chromium", "unreachable_code")};
};
Func("foo", {}, ty.void_(),
utils::Vector{
@ -241,113 +241,157 @@ TEST_F(ResolverDiagnosticControlTest, BlockAttributeScope) {
78:87 warning: code is unreachable)");
}
TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Directive) {
TEST_F(ResolverDiagnosticControlTest, UnrecognizedCoreRuleName_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
Ident(Source{{12, 34}}, "chromium_unreachable_cod"));
DiagnosticRuleName(Source{{12, 34}}, "derivative_uniform"));
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
R"(12:34 warning: unrecognized diagnostic rule 'chromium_unreachable_cod'
Did you mean 'chromium_unreachable_code'?
Possible values: 'chromium_unreachable_code', 'derivative_uniformity')");
R"(12:34 warning: unrecognized diagnostic rule 'derivative_uniform'
Did you mean 'derivative_uniformity'?
Possible values: 'derivative_uniformity')");
}
TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Attribute) {
TEST_F(ResolverDiagnosticControlTest, UnrecognizedCoreRuleName_Attribute) {
auto* attr = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
Ident(Source{{12, 34}}, "chromium_unreachable_cod"));
DiagnosticRuleName(Source{{12, 34}}, "derivative_uniform"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
R"(12:34 warning: unrecognized diagnostic rule 'chromium_unreachable_cod'
Did you mean 'chromium_unreachable_code'?
Possible values: 'chromium_unreachable_code', 'derivative_uniformity')");
R"(12:34 warning: unrecognized diagnostic rule 'derivative_uniform'
Did you mean 'derivative_uniformity'?
Possible values: 'derivative_uniformity')");
}
TEST_F(ResolverDiagnosticControlTest, UnrecognizedChromiumRuleName_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_cod"));
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
R"(12:34 warning: unrecognized diagnostic rule 'chromium.unreachable_cod'
Did you mean 'chromium.unreachable_code'?
Possible values: 'chromium.unreachable_code')");
}
TEST_F(ResolverDiagnosticControlTest, UnrecognizedChromiumRuleName_Attribute) {
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_cod"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
R"(12:34 warning: unrecognized diagnostic rule 'chromium.unreachable_cod'
Did you mean 'chromium.unreachable_code'?
Possible values: 'chromium.unreachable_code')");
}
TEST_F(ResolverDiagnosticControlTest, UnrecognizedOtherRuleName_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
DiagnosticRuleName(Source{{12, 34}}, "unknown", "unreachable_cod"));
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(), "");
}
TEST_F(ResolverDiagnosticControlTest, UnrecognizedOtherRuleName_Attribute) {
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
DiagnosticRuleName(Source{{12, 34}}, "unknown", "unreachable_cod"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(), "");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameSameSeverity_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
Ident(Source{{12, 34}}, "chromium_unreachable_code"));
DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_code"));
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
Ident(Source{{56, 78}}, "chromium_unreachable_code"));
DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_code"));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameDifferentSeverity_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
Ident(Source{{12, 34}}, "chromium_unreachable_code"));
DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_code"));
DiagnosticDirective(builtin::DiagnosticSeverity::kOff,
Ident(Source{{56, 78}}, "chromium_unreachable_code"));
DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_code"));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(56:78 error: conflicting diagnostic directive
12:34 note: severity of 'chromium_unreachable_code' set to 'off' here)");
12:34 note: severity of 'chromium.unreachable_code' set to 'off' here)");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameUnknownNameDifferentSeverity_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
Ident(Source{{12, 34}}, "chromium_unreachable_codes"));
DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_codes"));
DiagnosticDirective(builtin::DiagnosticSeverity::kOff,
Ident(Source{{56, 78}}, "chromium_unreachable_codes"));
DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_codes"));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 warning: unrecognized diagnostic rule 'chromium_unreachable_codes'
Did you mean 'chromium_unreachable_code'?
Possible values: 'chromium_unreachable_code', 'derivative_uniformity'
56:78 warning: unrecognized diagnostic rule 'chromium_unreachable_codes'
Did you mean 'chromium_unreachable_code'?
Possible values: 'chromium_unreachable_code', 'derivative_uniformity'
R"(12:34 warning: unrecognized diagnostic rule 'chromium.unreachable_codes'
Did you mean 'chromium.unreachable_code'?
Possible values: 'chromium.unreachable_code'
56:78 warning: unrecognized diagnostic rule 'chromium.unreachable_codes'
Did you mean 'chromium.unreachable_code'?
Possible values: 'chromium.unreachable_code'
56:78 error: conflicting diagnostic directive
12:34 note: severity of 'chromium_unreachable_codes' set to 'off' here)");
12:34 note: severity of 'chromium.unreachable_codes' set to 'off' here)");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_DifferentUnknownNameDifferentSeverity_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_codes");
DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_codex");
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_codes");
DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_codex");
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameSameSeverity_Attribute) {
auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
Ident(Source{{12, 34}}, "chromium_unreachable_code"));
auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
Ident(Source{{56, 78}}, "chromium_unreachable_code"));
auto* attr1 =
DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_code"));
auto* attr2 =
DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_code"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameDifferentSeverity_Attribute) {
auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
Ident(Source{{12, 34}}, "chromium_unreachable_code"));
auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
Ident(Source{{56, 78}}, "chromium_unreachable_code"));
auto* attr1 =
DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_code"));
auto* attr2 =
DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_code"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(56:78 error: conflicting diagnostic attribute
12:34 note: severity of 'chromium_unreachable_code' set to 'off' here)");
12:34 note: severity of 'chromium.unreachable_code' set to 'off' here)");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameUnknownNameDifferentSeverity_Attribute) {
auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
Ident(Source{{12, 34}}, "chromium_unreachable_codes"));
auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
Ident(Source{{56, 78}}, "chromium_unreachable_codes"));
auto* attr1 =
DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_codes"));
auto* attr2 =
DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_codes"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 warning: unrecognized diagnostic rule 'chromium_unreachable_codes'
Did you mean 'chromium_unreachable_code'?
Possible values: 'chromium_unreachable_code', 'derivative_uniformity'
56:78 warning: unrecognized diagnostic rule 'chromium_unreachable_codes'
Did you mean 'chromium_unreachable_code'?
Possible values: 'chromium_unreachable_code', 'derivative_uniformity'
R"(12:34 warning: unrecognized diagnostic rule 'chromium.unreachable_codes'
Did you mean 'chromium.unreachable_code'?
Possible values: 'chromium.unreachable_code'
56:78 warning: unrecognized diagnostic rule 'chromium.unreachable_codes'
Did you mean 'chromium.unreachable_code'?
Possible values: 'chromium.unreachable_code'
56:78 error: conflicting diagnostic attribute
12:34 note: severity of 'chromium_unreachable_codes' set to 'off' here)");
12:34 note: severity of 'chromium.unreachable_codes' set to 'off' here)");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_DifferentUnknownNameDifferentSeverity_Attribute) {
auto* attr1 =
DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium_unreachable_codes");
DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_codes");
auto* attr2 =
DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_codex");
DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_codex");
Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
EXPECT_TRUE(r()->Resolve()) << r()->error();
}

View File

@ -3466,15 +3466,33 @@ bool Resolver::InternalAttribute(const ast::InternalAttribute* attr) {
bool Resolver::DiagnosticControl(const ast::DiagnosticControl& control) {
Mark(control.rule_name);
Mark(control.rule_name->name);
auto name = control.rule_name->name->symbol.Name();
auto rule_name = control.rule_name->symbol.Name();
auto rule = builtin::ParseDiagnosticRule(rule_name);
if (rule != builtin::DiagnosticRule::kUndefined) {
if (control.rule_name->category) {
Mark(control.rule_name->category);
if (control.rule_name->category->symbol.Name() == "chromium") {
auto rule = builtin::ParseChromiumDiagnosticRule(name);
if (rule != builtin::ChromiumDiagnosticRule::kUndefined) {
validator_.DiagnosticFilters().Set(rule, control.severity);
} else {
utils::StringStream ss;
ss << "unrecognized diagnostic rule 'chromium." << name << "'\n";
utils::SuggestAlternatives(name, builtin::kChromiumDiagnosticRuleStrings, ss,
"chromium.");
AddWarning(ss.str(), control.rule_name->source);
}
}
return true;
}
auto rule = builtin::ParseCoreDiagnosticRule(name);
if (rule != builtin::CoreDiagnosticRule::kUndefined) {
validator_.DiagnosticFilters().Set(rule, control.severity);
} else {
utils::StringStream ss;
ss << "unrecognized diagnostic rule '" << rule_name << "'\n";
utils::SuggestAlternatives(rule_name, builtin::kDiagnosticRuleStrings, ss);
ss << "unrecognized diagnostic rule '" << name << "'\n";
utils::SuggestAlternatives(name, builtin::kCoreDiagnosticRuleStrings, ss);
AddWarning(ss.str(), control.rule_name->source);
}
return true;

View File

@ -1563,7 +1563,7 @@ class UniformityGraph {
builtin->Type() == builtin::Function::kTextureSampleCompare) {
// Get the severity of derivative uniformity violations in this context.
auto severity = sem_.DiagnosticSeverity(
call, builtin::DiagnosticRule::kDerivativeUniformity);
call, builtin::CoreDiagnosticRule::kDerivativeUniformity);
if (severity != builtin::DiagnosticSeverity::kOff) {
callsite_tag = {CallSiteTag::CallSiteRequiredToBeUniform, severity};
}

View File

@ -159,9 +159,9 @@ Validator::Validator(
atomic_composite_info_(atomic_composite_info),
valid_type_storage_layouts_(valid_type_storage_layouts) {
// Set default severities for filterable diagnostic rules.
diagnostic_filters_.Set(builtin::DiagnosticRule::kDerivativeUniformity,
diagnostic_filters_.Set(builtin::CoreDiagnosticRule::kDerivativeUniformity,
builtin::DiagnosticSeverity::kError);
diagnostic_filters_.Set(builtin::DiagnosticRule::kChromiumUnreachableCode,
diagnostic_filters_.Set(builtin::ChromiumDiagnosticRule::kUnreachableCode,
builtin::DiagnosticSeverity::kWarning);
}
@ -1417,7 +1417,7 @@ bool Validator::EvaluationStage(const sem::ValueExpression* expr,
bool Validator::Statements(utils::VectorRef<const ast::Statement*> stmts) const {
for (auto* stmt : stmts) {
if (!sem_.Get(stmt)->IsReachable()) {
if (!AddDiagnostic(builtin::DiagnosticRule::kChromiumUnreachableCode,
if (!AddDiagnostic(builtin::ChromiumDiagnosticRule::kUnreachableCode,
"code is unreachable", stmt->source)) {
return false;
}
@ -2530,9 +2530,12 @@ bool Validator::DiagnosticControls(utils::VectorRef<const ast::DiagnosticControl
const char* use) const {
// Make sure that no two diagnostic controls conflict.
// They conflict if the rule name is the same and the severity is different.
utils::Hashmap<Symbol, const ast::DiagnosticControl*, 8> diagnostics;
utils::Hashmap<std::pair<Symbol, Symbol>, const ast::DiagnosticControl*, 8> diagnostics;
for (auto* dc : controls) {
auto diag_added = diagnostics.Add(dc->rule_name->symbol, dc);
auto category = dc->rule_name->category ? dc->rule_name->category->symbol : Symbol();
auto name = dc->rule_name->name->symbol;
auto diag_added = diagnostics.Add(std::make_pair(category, name), dc);
if (!diag_added && (*diag_added.value)->severity != dc->severity) {
{
utils::StringStream ss;
@ -2541,8 +2544,8 @@ bool Validator::DiagnosticControls(utils::VectorRef<const ast::DiagnosticControl
}
{
utils::StringStream ss;
ss << "severity of '" << dc->rule_name->symbol.Name() << "' set to '"
<< dc->severity << "' here";
ss << "severity of '" << dc->rule_name->String() << "' set to '" << dc->severity
<< "' here";
AddNote(ss.str(), (*diag_added.value)->rule_name->source);
}
return false;

View File

@ -23,27 +23,27 @@ namespace {
class DiagnosticSeverityTest : public TestHelper {
protected:
/// Create a program with two functions, setting the severity for "chromium_unreachable_code"
/// Create a program with two functions, setting the severity for "chromium.unreachable_code"
/// using an attribute. Test that we correctly track the severity of the filter for the
/// functions and the statements with them.
/// @param global_severity the global severity of the "chromium_unreachable_code" filter
/// @param global_severity the global severity of the "chromium.unreachable_code" filter
void Run(builtin::DiagnosticSeverity global_severity) {
// @diagnostic(off, chromium_unreachable_code)
// @diagnostic(off, chromium.unreachable_code)
// fn foo() {
// @diagnostic(info, chromium_unreachable_code) {
// @diagnostic(error, chromium_unreachable_code)
// if (true) @diagnostic(warning, chromium_unreachable_code) {
// @diagnostic(info, chromium.unreachable_code) {
// @diagnostic(error, chromium.unreachable_code)
// if (true) @diagnostic(warning, chromium.unreachable_code) {
// return;
// } else if (false) {
// return;
// } else @diagnostic(info, chromium_unreachable_code) {
// } else @diagnostic(info, chromium.unreachable_code) {
// return;
// }
// return;
//
// @diagnostic(error, chromium_unreachable_code)
// switch (42) @diagnostic(off, chromium_unreachable_code) {
// case 0 @diagnostic(warning, chromium_unreachable_code) {
// @diagnostic(error, chromium.unreachable_code)
// switch (42) @diagnostic(off, chromium.unreachable_code) {
// case 0 @diagnostic(warning, chromium.unreachable_code) {
// return;
// }
// default {
@ -51,21 +51,21 @@ class DiagnosticSeverityTest : public TestHelper {
// }
// }
//
// @diagnostic(error, chromium_unreachable_code)
// for (var i = 0; false; i++) @diagnostic(warning, chromium_unreachable_code) {
// @diagnostic(error, chromium.unreachable_code)
// for (var i = 0; false; i++) @diagnostic(warning, chromium.unreachable_code) {
// return;
// }
//
// @diagnostic(warning, chromium_unreachable_code)
// loop @diagnostic(off, chromium_unreachable_code) {
// @diagnostic(warning, chromium.unreachable_code)
// loop @diagnostic(off, chromium.unreachable_code) {
// return;
// continuing @diagnostic(info, chromium_unreachable_code) {
// continuing @diagnostic(info, chromium.unreachable_code) {
// break if true;
// }
// }
//
// @diagnostic(error, chromium_unreachable_code)
// while (false) @diagnostic(warning, chromium_unreachable_code) {
// @diagnostic(error, chromium.unreachable_code)
// while (false) @diagnostic(warning, chromium.unreachable_code) {
// return;
// }
// }
@ -74,7 +74,7 @@ class DiagnosticSeverityTest : public TestHelper {
// fn bar() {
// return;
// }
auto rule = builtin::DiagnosticRule::kChromiumUnreachableCode;
auto rule = builtin::ChromiumDiagnosticRule::kUnreachableCode;
auto func_severity = builtin::DiagnosticSeverity::kOff;
auto block_severity = builtin::DiagnosticSeverity::kInfo;
auto if_severity = builtin::DiagnosticSeverity::kError;
@ -91,7 +91,7 @@ class DiagnosticSeverityTest : public TestHelper {
auto while_severity = builtin::DiagnosticSeverity::kError;
auto while_body_severity = builtin::DiagnosticSeverity::kWarning;
auto attr = [&](auto severity) {
return utils::Vector{DiagnosticAttribute(severity, "chromium_unreachable_code")};
return utils::Vector{DiagnosticAttribute(severity, "chromium", "unreachable_code")};
};
auto* return_foo_if = Return();
@ -123,7 +123,7 @@ class DiagnosticSeverityTest : public TestHelper {
attr(while_severity));
auto* block_1 =
Block(utils::Vector{if_foo, return_foo_block, swtch, fl, l, wl}, attr(block_severity));
auto* func_attr = DiagnosticAttribute(func_severity, "chromium_unreachable_code");
auto* func_attr = DiagnosticAttribute(func_severity, "chromium", "unreachable_code");
auto* foo = Func("foo", {}, ty.void_(), utils::Vector{block_1}, utils::Vector{func_attr});
auto* return_bar = Return();
@ -173,7 +173,7 @@ class DiagnosticSeverityTest : public TestHelper {
};
TEST_F(DiagnosticSeverityTest, WithDirective) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
Run(builtin::DiagnosticSeverity::kError);
}

View File

@ -1289,10 +1289,16 @@ Transform::ApplyResult Renamer::Apply(const Program* src,
}
},
[&](const ast::DiagnosticAttribute* diagnostic) {
preserved_identifiers.Add(diagnostic->control.rule_name);
if (auto* category = diagnostic->control.rule_name->category) {
preserved_identifiers.Add(category);
}
preserved_identifiers.Add(diagnostic->control.rule_name->name);
},
[&](const ast::DiagnosticDirective* diagnostic) {
preserved_identifiers.Add(diagnostic->control.rule_name);
if (auto* category = diagnostic->control.rule_name->category) {
preserved_identifiers.Add(category);
}
preserved_identifiers.Add(diagnostic->control.rule_name->name);
},
[&](const ast::IdentifierExpression* expr) {
Switch(

View File

@ -192,9 +192,9 @@ fn tint_symbol() {
EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
}
TEST_F(RenamerTest, PreserveDiagnosticControls) {
TEST_F(RenamerTest, PreserveCoreDiagnosticRuleName) {
auto* src = R"(
diagnostic(off, unreachable_code);
diagnostic(off, chromium.unreachable_code);
@diagnostic(off, derivative_uniformity)
@fragment
@ -208,7 +208,7 @@ fn entry(@location(0) value : f32) -> @location(0) f32 {
)";
auto* expect = R"(
diagnostic(off, unreachable_code);
diagnostic(off, chromium.unreachable_code);
@diagnostic(off, derivative_uniformity) @fragment
fn tint_symbol(@location(0) tint_symbol_1 : f32) -> @location(0) f32 {

View File

@ -134,7 +134,15 @@ struct Hasher<std::tuple<TYPES...>> {
}
};
/// Hasher specialization for std::tuple
/// Hasher specialization for std::pair
template <typename A, typename B>
struct Hasher<std::pair<A, B>> {
/// @param tuple the tuple to hash
/// @returns a hash of the tuple
size_t operator()(const std::pair<A, B>& tuple) const { return std::apply(Hash<A, B>, tuple); }
};
/// Hasher specialization for std::variant
template <typename... TYPES>
struct Hasher<std::variant<TYPES...>> {
/// @param variant the variant to hash

View File

@ -50,7 +50,8 @@ size_t Distance(std::string_view str_a, std::string_view str_b) {
void SuggestAlternatives(std::string_view got,
Slice<char const* const> strings,
utils::StringStream& ss) {
utils::StringStream& ss,
std::string_view prefix /* = "" */) {
// If the string typed was within kSuggestionDistance of one of the possible enum values,
// suggest that. Don't bother with suggestions if the string was extremely long.
constexpr size_t kSuggestionDistance = 5;
@ -66,7 +67,7 @@ void SuggestAlternatives(std::string_view got,
}
}
if (candidate) {
ss << "Did you mean '" << candidate << "'?\n";
ss << "Did you mean '" << prefix << candidate << "'?\n";
}
}
@ -76,7 +77,7 @@ void SuggestAlternatives(std::string_view got,
if (str != strings[0]) {
ss << ", ";
}
ss << "'" << str << "'";
ss << "'" << prefix << str << "'";
}
}

View File

@ -72,9 +72,11 @@ size_t Distance(std::string_view a, std::string_view b);
/// @param got the unrecognized string
/// @param strings the list of possible values
/// @param ss the stream to write the suggest and list of possible values to
/// @param prefix the prefix to apply to the strings when printing (optional)
void SuggestAlternatives(std::string_view got,
Slice<char const* const> strings,
utils::StringStream& ss);
utils::StringStream& ss,
std::string_view prefix = "");
} // namespace tint::utils

View File

@ -66,7 +66,7 @@ void GeneratorImpl::Generate() {
void GeneratorImpl::EmitDiagnosticControl(const ast::DiagnosticControl& diagnostic) {
line() << "DiagnosticControl [severity: " << diagnostic.severity
<< ", rule: " << diagnostic.rule_name->symbol.Name() << "]";
<< ", rule: " << diagnostic.rule_name->String() << "]";
}
void GeneratorImpl::EmitEnable(const ast::Enable* enable) {

View File

@ -82,8 +82,7 @@ void GeneratorImpl::Generate() {
void GeneratorImpl::EmitDiagnosticControl(utils::StringStream& out,
const ast::DiagnosticControl& diagnostic) {
out << "diagnostic(" << diagnostic.severity << ", " << diagnostic.rule_name->symbol.Name()
<< ")";
out << "diagnostic(" << diagnostic.severity << ", " << diagnostic.rule_name->String() << ")";
}
void GeneratorImpl::EmitEnable(const ast::Enable* enable) {

View File

@ -22,25 +22,25 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, Emit_DiagnosticDirective) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
GeneratorImpl& gen = Build();
gen.Generate();
EXPECT_THAT(gen.Diagnostics(), testing::IsEmpty());
EXPECT_EQ(gen.result(), R"(diagnostic(error, chromium_unreachable_code);
EXPECT_EQ(gen.result(), R"(diagnostic(error, chromium.unreachable_code);
)");
}
TEST_F(WgslGeneratorImplTest, Emit_DiagnosticAttribute) {
auto* attr =
DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
GeneratorImpl& gen = Build();
gen.Generate();
EXPECT_THAT(gen.Diagnostics(), testing::IsEmpty());
EXPECT_EQ(gen.result(), R"(@diagnostic(error, chromium_unreachable_code)
EXPECT_EQ(gen.result(), R"(@diagnostic(error, chromium.unreachable_code)
fn foo() {
}
)");