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 <dsinclair@google.com>
diff --git a/src/reader/spirv/namer.cc b/src/reader/spirv/namer.cc
index 8f316c9..e56f395 100644
--- a/src/reader/spirv/namer.cc
+++ b/src/reader/spirv/namer.cc
@@ -14,6 +14,8 @@
#include "src/reader/spirv/namer.h"
+#include <algorithm>
+
namespace tint {
namespace reader {
namespace spirv {
@@ -22,6 +24,30 @@
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 03fc531..470228e 100644
--- a/src/reader/spirv/namer.h
+++ b/src/reader/spirv/namer.h
@@ -26,6 +26,12 @@
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 @@
/// 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 aa6eeee..647706e 100644
--- a/src/reader/spirv/namer_test.cc
+++ b/src/reader/spirv/namer_test.cc
@@ -18,7 +18,7 @@
#include <sstream>
#include <string>
-#include "gtest/gtest.h"
+#include "gmock/gmock.h"
#include "src/reader/spirv/fail_stream.h"
namespace tint {
@@ -26,6 +26,8 @@
namespace spirv {
namespace {
+using ::testing::Eq;
+
class SpvNamerTest : public testing::Test {
public:
SpvNamerTest() : fail_stream_(&success_, &errors_) {}
@@ -39,6 +41,26 @@
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_);