mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-01 04:01:26 +00:00
tint: Move "suggest alternatives" logic to utils
This will be used for suggesting alternative diagnostic rule names in the Resolver. Bug: tint:1809 Change-Id: Icc9af02937326f6f774fbaf2aeaa9314c88fdea6 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/117565 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
2cf9764e45
commit
f629770bcd
@ -1240,40 +1240,15 @@ Expect<ENUM> ParserImpl::expect_enum(std::string_view name,
|
||||
}
|
||||
|
||||
/// Create a sensible error message
|
||||
std::stringstream err;
|
||||
std::ostringstream err;
|
||||
err << "expected " << name;
|
||||
|
||||
if (!use.empty()) {
|
||||
err << " for " << use;
|
||||
}
|
||||
err << "\n";
|
||||
|
||||
// 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;
|
||||
constexpr size_t kSuggestionMaxLength = 64;
|
||||
if (auto got = t.to_str(); !got.empty() && got.size() < kSuggestionMaxLength) {
|
||||
size_t candidate_dist = kSuggestionDistance;
|
||||
const char* candidate = nullptr;
|
||||
for (auto* str : strings) {
|
||||
auto dist = utils::Distance(str, got);
|
||||
if (dist < candidate_dist) {
|
||||
candidate = str;
|
||||
candidate_dist = dist;
|
||||
}
|
||||
}
|
||||
if (candidate) {
|
||||
err << ". Did you mean '" << candidate << "'?";
|
||||
}
|
||||
}
|
||||
|
||||
// List all the possible enumerator values
|
||||
err << "\nPossible values: ";
|
||||
for (auto* str : strings) {
|
||||
if (str != strings[0]) {
|
||||
err << ", ";
|
||||
}
|
||||
err << "'" << str << "'";
|
||||
}
|
||||
utils::SuggestAlternatives(t.to_str(), strings, err);
|
||||
|
||||
synchronized_ = false;
|
||||
return add_error(t.source(), err.str());
|
||||
|
@ -74,7 +74,8 @@ TEST_F(EnableDirectiveTest, InvalidIdentifierSuggest) {
|
||||
p->enable_directive();
|
||||
// Error when unknown extension found
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), R"(1:8: expected extension. Did you mean 'f16'?
|
||||
EXPECT_EQ(p->error(), R"(1:8: expected extension
|
||||
Did you mean 'f16'?
|
||||
Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
|
||||
auto program = p->program();
|
||||
auto& ast = program.AST();
|
||||
|
@ -1110,7 +1110,8 @@ Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBuiltinInvalidValue) {
|
||||
EXPECT("@builtin(frag_d3pth) var i : i32;",
|
||||
R"(test.wgsl:1:10 error: expected builtin. Did you mean 'frag_depth'?
|
||||
R"(test.wgsl:1:10 error: expected builtin
|
||||
Did you mean 'frag_depth'?
|
||||
Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id'
|
||||
@builtin(frag_d3pth) var i : i32;
|
||||
^^^^^^^^^^
|
||||
|
@ -230,7 +230,8 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidTypeSuggest) {
|
||||
EXPECT_FALSE(t.matched);
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_EQ(p->error(),
|
||||
R"(1:20: expected texel format for storage texture type. Did you mean 'rg32float'?
|
||||
R"(1:20: expected texel format for storage texture type
|
||||
Did you mean 'rg32float'?
|
||||
Possible values: 'bgra8unorm', 'r32float', 'r32sint', 'r32uint', 'rg32float', 'rg32sint', 'rg32uint', 'rgba16float', 'rgba16sint', 'rgba16uint', 'rgba32float', 'rgba32sint', 'rgba32uint', 'rgba8sint', 'rgba8snorm', 'rgba8uint', 'rgba8unorm')");
|
||||
}
|
||||
|
||||
@ -241,7 +242,8 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidAccess) {
|
||||
EXPECT_FALSE(t.matched);
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_EQ(p->error(),
|
||||
R"(1:30: expected access control for storage texture type. Did you mean 'read'?
|
||||
R"(1:30: expected access control for storage texture type
|
||||
Did you mean 'read'?
|
||||
Possible values: 'read', 'read_write', 'write')");
|
||||
}
|
||||
|
||||
|
@ -316,7 +316,8 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_BadAddressSpace) {
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(),
|
||||
R"(1:5: expected address space for ptr declaration. Did you mean 'uniform'?
|
||||
R"(1:5: expected address space for ptr declaration
|
||||
Did you mean 'uniform'?
|
||||
Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,8 @@ TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_BadAddressSpace) {
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(),
|
||||
R"(1:5: expected address space for ptr declaration. Did you mean 'uniform'?
|
||||
R"(1:5: expected address space for ptr declaration
|
||||
Did you mean 'uniform'?
|
||||
Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,8 @@ TEST_F(ParserImplTest, AttributeList_InvalidValueSuggest) {
|
||||
EXPECT_TRUE(attrs.errored);
|
||||
EXPECT_FALSE(attrs.matched);
|
||||
EXPECT_TRUE(attrs.value.IsEmpty());
|
||||
EXPECT_EQ(p->error(), R"(1:10: expected builtin. Did you mean 'instance_index'?
|
||||
EXPECT_EQ(p->error(), R"(1:10: expected builtin
|
||||
Did you mean 'instance_index'?
|
||||
Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id')");
|
||||
}
|
||||
} // namespace
|
||||
|
@ -323,7 +323,8 @@ TEST_F(ParserImplTest, Attribute_Builtin_InvalidValueSuggest) {
|
||||
EXPECT_TRUE(attr.errored);
|
||||
EXPECT_EQ(attr.value, nullptr);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), R"(1:9: expected builtin. Did you mean 'front_facing'?
|
||||
EXPECT_EQ(p->error(), R"(1:9: expected builtin
|
||||
Did you mean 'front_facing'?
|
||||
Possible values: 'frag_depth', 'front_facing', 'global_invocation_id', 'instance_index', 'local_invocation_id', 'local_invocation_index', 'num_workgroups', 'position', 'sample_index', 'sample_mask', 'vertex_index', 'workgroup_id')");
|
||||
}
|
||||
|
||||
@ -494,7 +495,8 @@ TEST_F(ParserImplTest, Attribute_Interpolate_InvalidSecondValue) {
|
||||
EXPECT_TRUE(attr.errored);
|
||||
EXPECT_EQ(attr.value, nullptr);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), R"(1:26: expected interpolation sampling. Did you mean 'sample'?
|
||||
EXPECT_EQ(p->error(), R"(1:26: expected interpolation sampling
|
||||
Did you mean 'sample'?
|
||||
Possible values: 'center', 'centroid', 'sample')");
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,8 @@ TEST_F(ParserImplTest, VariableDecl_InvalidAddressSpace) {
|
||||
EXPECT_TRUE(v.errored);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(),
|
||||
R"(1:5: expected address space for variable declaration. Did you mean 'uniform'?
|
||||
R"(1:5: expected address space for variable declaration
|
||||
Did you mean 'uniform'?
|
||||
Possible values: 'function', 'private', 'push_constant', 'storage', 'uniform', 'workgroup')");
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,43 @@ inline size_t HasPrefix(std::string_view str, std::string_view prefix) {
|
||||
/// @returns the Levenshtein distance between @p a and @p b
|
||||
size_t Distance(std::string_view a, std::string_view b);
|
||||
|
||||
/// Suggest alternatives for an unrecognized string from a list of expected values.
|
||||
/// @param got the unrecognized string
|
||||
/// @param strings the list of expected values
|
||||
/// @param ss the stream to write the suggest and list of possible values to
|
||||
template <size_t N>
|
||||
void SuggestAlternatives(std::string_view got,
|
||||
const char* const (&strings)[N],
|
||||
std::ostringstream& ss) {
|
||||
// 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;
|
||||
constexpr size_t kSuggestionMaxLength = 64;
|
||||
if (!got.empty() && got.size() < kSuggestionMaxLength) {
|
||||
size_t candidate_dist = kSuggestionDistance;
|
||||
const char* candidate = nullptr;
|
||||
for (auto* str : strings) {
|
||||
auto dist = utils::Distance(str, got);
|
||||
if (dist < candidate_dist) {
|
||||
candidate = str;
|
||||
candidate_dist = dist;
|
||||
}
|
||||
}
|
||||
if (candidate) {
|
||||
ss << "Did you mean '" << candidate << "'?\n";
|
||||
}
|
||||
}
|
||||
|
||||
// List all the possible enumerator values
|
||||
ss << "Possible values: ";
|
||||
for (auto* str : strings) {
|
||||
if (str != strings[0]) {
|
||||
ss << ", ";
|
||||
}
|
||||
ss << "'" << str << "'";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tint::utils
|
||||
|
||||
#endif // SRC_TINT_UTILS_STRING_H_
|
||||
|
@ -58,5 +58,19 @@ TEST(StringTest, Distance) {
|
||||
EXPECT_EQ(Distance("", "Hello world"), 11u);
|
||||
}
|
||||
|
||||
TEST(StringTest, SuggestAlternatives) {
|
||||
{
|
||||
std::ostringstream ss;
|
||||
SuggestAlternatives("hello wordl", {"hello world", "Hello World"}, ss);
|
||||
EXPECT_EQ(ss.str(), R"(Did you mean 'hello world'?
|
||||
Possible values: 'hello world', 'Hello World')");
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
SuggestAlternatives("hello world", {"foobar", "something else"}, ss);
|
||||
EXPECT_EQ(ss.str(), R"(Possible values: 'foobar', 'something else')");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::utils
|
||||
|
Loading…
x
Reference in New Issue
Block a user