From bd1d14213451daf2c29d53ae1955eb80e7c0c42c Mon Sep 17 00:00:00 2001 From: David Neto Date: Mon, 23 Mar 2020 16:42:21 +0000 Subject: [PATCH] Add reader::spv::Namer::Sanitize Bug: tint:3 Change-Id: I4d554755dacecac0f2dacf191d85f8e339e87923 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17420 Reviewed-by: dan sinclair --- src/reader/spirv/namer.cc | 26 ++++++++++++++++++++++++++ src/reader/spirv/namer.h | 13 +++++++++++++ src/reader/spirv/namer_test.cc | 24 +++++++++++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/reader/spirv/namer.cc b/src/reader/spirv/namer.cc index 8f316c9c30..e56f395d20 100644 --- a/src/reader/spirv/namer.cc +++ b/src/reader/spirv/namer.cc @@ -14,6 +14,8 @@ #include "src/reader/spirv/namer.h" +#include + namespace tint { namespace reader { namespace spirv { @@ -22,6 +24,30 @@ Namer::Namer(const FailStream& fail_stream) : fail_stream_(fail_stream) {} Namer::~Namer() = default; +std::string Namer::Sanitize(const std::string& suggested_name) { + if (suggested_name.empty()) { + return "empty"; + } + // Otherwise, replace invalid characters by '_'. + std::string result; + std::string invalid_as_first_char = "_0123456789"; + std::string valid = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "_0123456789"; + // If the first character is invalid for starting a WGSL identifier, then + // prefix the result with "x". + if ((std::string::npos != invalid_as_first_char.find(suggested_name[0])) || + (std::string::npos == valid.find(suggested_name[0]))) { + result = "x"; + } + std::transform(suggested_name.begin(), suggested_name.end(), + std::back_inserter(result), [&valid](const char c) { + return (std::string::npos == valid.find(c)) ? '_' : c; + }); + return result; +} + bool Namer::SaveName(uint32_t id, const std::string& name) { if (HasName(id)) { return Fail() << "internal error: ID " << id diff --git a/src/reader/spirv/namer.h b/src/reader/spirv/namer.h index 03fc531637..470228ebf7 100644 --- a/src/reader/spirv/namer.h +++ b/src/reader/spirv/namer.h @@ -26,6 +26,12 @@ namespace reader { namespace spirv { /// A Namer maps SPIR-V IDs to strings. +/// +/// Sanitization: +/// Some names are user-suggested, but "sanitized" in the sense that an +/// unusual character (e.g. invalid for use in WGSL identifiers) is remapped +/// to a safer character such as an underscore. Also, sanitized names +/// never start with an underscorre. class Namer { public: /// Creates a new namer @@ -34,6 +40,13 @@ class Namer { /// Destructor ~Namer(); + /// Sanitizes the given string, to replace unusual characters with + /// obviously-valid idenfier characters. An empy string yields "empty". + /// A sanitized name never starts with an underscore. + /// @param suggested_name input string + /// @returns sanitized name, suitable for use as an identifier + static std::string Sanitize(const std::string& suggested_name); + /// Registers a failure. /// @returns a fail stream to accumulate diagnostics. FailStream& Fail() { return fail_stream_.Fail(); } diff --git a/src/reader/spirv/namer_test.cc b/src/reader/spirv/namer_test.cc index aa6eeeecb6..647706e60b 100644 --- a/src/reader/spirv/namer_test.cc +++ b/src/reader/spirv/namer_test.cc @@ -18,7 +18,7 @@ #include #include -#include "gtest/gtest.h" +#include "gmock/gmock.h" #include "src/reader/spirv/fail_stream.h" namespace tint { @@ -26,6 +26,8 @@ namespace reader { namespace spirv { namespace { +using ::testing::Eq; + class SpvNamerTest : public testing::Test { public: SpvNamerTest() : fail_stream_(&success_, &errors_) {} @@ -39,6 +41,26 @@ class SpvNamerTest : public testing::Test { FailStream fail_stream_; }; +TEST_F(SpvNamerTest, SanitizeEmpty) { + EXPECT_THAT(Namer::Sanitize(""), Eq("empty")); +} + +TEST_F(SpvNamerTest, SanitizeLeadingUnderscore) { + EXPECT_THAT(Namer::Sanitize("_"), Eq("x_")); +} + +TEST_F(SpvNamerTest, SanitizeLeadingDigit) { + EXPECT_THAT(Namer::Sanitize("7zip"), Eq("x7zip")); +} + +TEST_F(SpvNamerTest, SanitizeOkChars) { + EXPECT_THAT(Namer::Sanitize("_abcdef12345"), Eq("x_abcdef12345")); +} + +TEST_F(SpvNamerTest, SanitizeNonIdentifierChars) { + EXPECT_THAT(Namer::Sanitize("a:1.2'f\n"), "a_1_2_f_"); +} + TEST_F(SpvNamerTest, NoFailureToStart) { Namer namer(fail_stream_); EXPECT_TRUE(success_);