From d3c95a2820fbc0b36b8c0a1ad91eeb12e718dc8b Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 15 Feb 2023 10:55:43 -0800 Subject: [PATCH 1/6] Remove `toEnumVariantName` from `RustSymbolProvider` The `toEnumVariantName` function existed on symbol provider to work around enum definitions not being shapes. In the future when we refactor to use `EnumShape` instead of `EnumTrait`, there will be `MemberShape`s for each enum member. This change incrementally moves us to that future by creating fake `MemberShape`s in the enum generator from the enum definition. --- .../StreamingShapeSymbolProviderTest.kt | 16 +++- .../core/rustlang/RustReservedWords.kt | 73 +++++++++---------- .../core/smithy/SymbolMetadataProvider.kt | 7 +- .../rust/codegen/core/smithy/SymbolVisitor.kt | 25 ++----- .../core/smithy/generators/EnumGenerator.kt | 39 +++++++++- .../core/smithy/generators/UnionGenerator.kt | 13 +++- .../EventStreamErrorMarshallerGenerator.kt | 4 +- .../core/rustlang/RustReservedWordsTest.kt | 56 +++++++------- .../smithy/generators/BuilderGeneratorTest.kt | 28 +------ .../smithy/generators/EnumGeneratorTest.kt | 7 +- .../ServerBuilderGeneratorCommon.kt | 5 +- 11 files changed, 147 insertions(+), 126 deletions(-) diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingShapeSymbolProviderTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingShapeSymbolProviderTest.kt index 6c0c3cdadf..a2e233c719 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingShapeSymbolProviderTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingShapeSymbolProviderTest.kt @@ -9,8 +9,10 @@ import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider +import software.amazon.smithy.rust.codegen.core.rustlang.RustType import software.amazon.smithy.rust.codegen.core.smithy.Default import software.amazon.smithy.rust.codegen.core.smithy.defaultValue +import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.smithy.transformers.OperationNormalizer import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.util.lookup @@ -38,8 +40,18 @@ internal class StreamingShapeSymbolProviderTest { // "doing the right thing" val modelWithOperationTraits = OperationNormalizer.transform(model) val symbolProvider = testSymbolProvider(modelWithOperationTraits) - symbolProvider.toSymbol(modelWithOperationTraits.lookup("test.synthetic#GenerateSpeechOutput\$data")).name shouldBe ("ByteStream") - symbolProvider.toSymbol(modelWithOperationTraits.lookup("test.synthetic#GenerateSpeechInput\$data")).name shouldBe ("ByteStream") + modelWithOperationTraits.lookup("test.synthetic#GenerateSpeechOutput\$data").also { shape -> + symbolProvider.toSymbol(shape).also { symbol -> + symbol.name shouldBe "data" + symbol.rustType() shouldBe RustType.Opaque("ByteStream", "aws_smithy_http::byte_stream") + } + } + modelWithOperationTraits.lookup("test.synthetic#GenerateSpeechInput\$data").also { shape -> + symbolProvider.toSymbol(shape).also { symbol -> + symbol.name shouldBe "data" + symbol.rustType() shouldBe RustType.Opaque("ByteStream", "aws_smithy_http::byte_stream") + } + } } @Test diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt index 34a4382302..ceb539911d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt @@ -9,19 +9,18 @@ import software.amazon.smithy.codegen.core.ReservedWordSymbolProvider import software.amazon.smithy.codegen.core.ReservedWords import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumDefinition -import software.amazon.smithy.rust.codegen.core.smithy.MaybeRenamed +import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator import software.amazon.smithy.rust.codegen.core.smithy.renamedFrom +import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.letIf -import software.amazon.smithy.rust.codegen.core.util.orNull -import software.amazon.smithy.rust.codegen.core.util.toPascalCase class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, private val model: Model) : WrappingSymbolProvider(base) { @@ -29,9 +28,11 @@ class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, priva ReservedWordSymbolProvider.builder().symbolProvider(base).memberReservedWords(RustReservedWords).build() override fun toMemberName(shape: MemberShape): String { - val baseName = internal.toMemberName(shape) - return when (val container = model.expectShape(shape.container)) { - is StructureShape -> when (baseName) { + val baseName = super.toMemberName(shape) + val reservedWordReplacedName = internal.toMemberName(shape) + val container = model.expectShape(shape.container) + return when { + container is StructureShape -> when (baseName) { "build" -> "build_value" "builder" -> "builder_value" "default" -> "default_value" @@ -42,10 +43,10 @@ class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, priva "customize" -> "customize_value" // To avoid conflicts with the error metadata `meta` field "meta" -> "meta_value" - else -> baseName + else -> reservedWordReplacedName } - is UnionShape -> when (baseName) { + container is UnionShape -> when (baseName) { // Unions contain an `Unknown` variant. This exists to support parsing data returned from the server // that represent union variants that have been added since this SDK was generated. UnionGenerator.UnknownVariantName -> "${UnionGenerator.UnknownVariantName}Value" @@ -55,7 +56,20 @@ class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, priva "Self" -> "SelfValue" // Real models won't end in `_` so it's safe to stop here "SelfValue" -> "SelfValue_" - else -> baseName + else -> reservedWordReplacedName + } + + container is EnumShape || container.hasTrait() -> when (baseName) { + // Self cannot be used as a raw identifier, so we can't use the normal escaping strategy + // https://internals.rust-lang.org/t/raw-identifiers-dont-work-for-all-identifiers/9094/4 + "Self" -> "SelfValue" + // Real models won't end in `_` so it's safe to stop here + "SelfValue" -> "SelfValue_" + // Unknown is used as the name of the variant containing unexpected values + "Unknown" -> "UnknownValue" + // Real models won't end in `_` so it's safe to stop here + "UnknownValue" -> "UnknownValue_" + else -> reservedWordReplacedName } else -> error("unexpected container: $container") @@ -69,46 +83,31 @@ class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, priva * code generators to generate special docs. */ override fun toSymbol(shape: Shape): Symbol { + // Sanity check that the symbol provider stack is set up correctly + check(super.toSymbol(shape).renamedFrom() == null) { + "RustReservedWordSymbolProvider should only run once" + } + + var renamedSymbol = internal.toSymbol(shape) return when (shape) { is MemberShape -> { val container = model.expectShape(shape.container) - if (!(container is StructureShape || container is UnionShape)) { + val containerIsEnum = container is EnumShape || container.hasTrait() + if (container !is StructureShape && container !is UnionShape && !containerIsEnum) { return base.toSymbol(shape) } val previousName = base.toMemberName(shape) val escapedName = this.toMemberName(shape) - val baseSymbol = base.toSymbol(shape) // if the names don't match and it isn't a simple escaping with `r#`, record a rename - baseSymbol.letIf(escapedName != previousName && !escapedName.contains("r#")) { - it.toBuilder().renamedFrom(previousName).build() - } + renamedSymbol.toBuilder().name(escapedName) + .letIf(escapedName != previousName && !escapedName.contains("r#")) { + it.renamedFrom(previousName) + }.build() } else -> base.toSymbol(shape) } } - - override fun toEnumVariantName(definition: EnumDefinition): MaybeRenamed? { - val baseName = base.toEnumVariantName(definition) ?: return null - check(definition.name.orNull()?.toPascalCase() == baseName.name) { - "Enum variants must already be in pascal case ${baseName.name} differed from ${baseName.name.toPascalCase()}. Definition: ${definition.name}" - } - check(baseName.renamedFrom == null) { - "definitions should only pass through the renamer once" - } - return when (baseName.name) { - // Self cannot be used as a raw identifier, so we can't use the normal escaping strategy - // https://internals.rust-lang.org/t/raw-identifiers-dont-work-for-all-identifiers/9094/4 - "Self" -> MaybeRenamed("SelfValue", "Self") - // Real models won't end in `_` so it's safe to stop here - "SelfValue" -> MaybeRenamed("SelfValue_", "SelfValue") - // Unknown is used as the name of the variant containing unexpected values - "Unknown" -> MaybeRenamed("UnknownValue", "Unknown") - // Real models won't end in `_` so it's safe to stop here - "UnknownValue" -> MaybeRenamed("UnknownValue_", "UnknownValue") - else -> baseName - } - } } object RustReservedWords : ReservedWords { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt index a1faf8702c..0ba2055228 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt @@ -19,7 +19,6 @@ import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumDefinition import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.SensitiveTrait import software.amazon.smithy.model.traits.StreamingTrait @@ -33,7 +32,6 @@ import software.amazon.smithy.rust.codegen.core.util.hasTrait */ open class WrappingSymbolProvider(private val base: RustSymbolProvider) : RustSymbolProvider { override fun config(): SymbolVisitorConfig = base.config() - override fun toEnumVariantName(definition: EnumDefinition): MaybeRenamed? = base.toEnumVariantName(definition) override fun toSymbol(shape: Shape): Symbol = base.toSymbol(shape) override fun toMemberName(shape: MemberShape): String = base.toMemberName(shape) override fun symbolForOperationError(operation: OperationShape): Symbol = base.symbolForOperationError(operation) @@ -130,6 +128,11 @@ class BaseSymbolMetadataProvider( } is UnionShape, is CollectionShape, is MapShape -> RustMetadata(visibility = Visibility.PUBLIC) + + // This covers strings with the enum trait for now, and can be removed once we're fully on EnumShape + // TODO(https://github.com/awslabs/smithy-rs/issues/1700): Remove this `is StringShape` match arm + is StringShape -> RustMetadata(visibility = Visibility.PUBLIC) + else -> TODO("Unrecognized container type: $container") } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt index 21c09ac693..87552f9b8d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt @@ -17,6 +17,7 @@ import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.ByteShape import software.amazon.smithy.model.shapes.DocumentShape import software.amazon.smithy.model.shapes.DoubleShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.FloatShape import software.amazon.smithy.model.shapes.IntegerShape import software.amazon.smithy.model.shapes.ListShape @@ -35,7 +36,6 @@ import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.TimestampShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumDefinition import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.ErrorTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute @@ -179,7 +179,6 @@ data class MaybeRenamed(val name: String, val renamedFrom: String?) */ interface RustSymbolProvider : SymbolProvider, ModuleProvider { fun config(): SymbolVisitorConfig - fun toEnumVariantName(definition: EnumDefinition): MaybeRenamed? override fun moduleForShape(shape: Shape): RustModule.LeafModule = config().moduleProvider.moduleForShape(shape) override fun moduleForOperationError(operation: OperationShape): RustModule.LeafModule = @@ -248,21 +247,13 @@ open class SymbolVisitor( module.toType().resolve("${symbol.name}Error").toSymbol().toBuilder().locatedIn(module).build() } - /** - * Return the name of a given `enum` variant. Note that this refers to `enum` in the Smithy context - * where enum is a trait that can be applied to [StringShape] and not in the Rust context of an algebraic data type. - * - * Because enum variants are not member shape, a separate handler is required. - */ - override fun toEnumVariantName(definition: EnumDefinition): MaybeRenamed? { - val baseName = definition.name.orNull()?.toPascalCase() ?: return null - return MaybeRenamed(baseName, null) - } - - override fun toMemberName(shape: MemberShape): String = when (val container = model.expectShape(shape.container)) { - is StructureShape -> shape.memberName.toSnakeCase() - is UnionShape -> shape.memberName.toPascalCase() - else -> error("unexpected container shape: $container") + override fun toMemberName(shape: MemberShape): String { + val container = model.expectShape(shape.container) + return when { + container is StructureShape -> shape.memberName.toSnakeCase() + container is UnionShape || container is EnumShape || container.hasTrait() -> shape.memberName.toPascalCase() + else -> error("unexpected container shape: $container") + } } override fun blobShape(shape: BlobShape?): Symbol { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt index 5e7dc1d2b7..379a6982da 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt @@ -7,6 +7,8 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.MemberShape +import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.model.traits.EnumDefinition @@ -27,12 +29,14 @@ import software.amazon.smithy.rust.codegen.core.smithy.MaybeRenamed import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.expectRustMetadata +import software.amazon.smithy.rust.codegen.core.smithy.renamedFrom import software.amazon.smithy.rust.codegen.core.util.REDACTION import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.getTrait import software.amazon.smithy.rust.codegen.core.util.orNull import software.amazon.smithy.rust.codegen.core.util.shouldRedact +import software.amazon.smithy.rust.codegen.core.util.toPascalCase data class EnumGeneratorContext( val enumName: String, @@ -71,14 +75,41 @@ abstract class EnumType { } /** Model that wraps [EnumDefinition] to calculate and cache values required to generate the Rust enum source. */ -class EnumMemberModel(private val definition: EnumDefinition, private val symbolProvider: RustSymbolProvider) { +class EnumMemberModel( + private val parentShape: Shape, + private val definition: EnumDefinition, + private val symbolProvider: RustSymbolProvider, +) { + companion object { + /** + * Return the name of a given `enum` variant. Note that this refers to `enum` in the Smithy context + * where enum is a trait that can be applied to [StringShape] and not in the Rust context of an algebraic data type. + * + * Ordinarily, the symbol provider would determine this name, but the enum trait doesn't allow for this. + * + * TODO(https://github.com/awslabs/smithy-rs/issues/1700): Remove this function when refactoring to EnumShape. + */ + @Deprecated("This function will go away when we handle EnumShape instead of EnumTrait") + fun toEnumVariantName( + symbolProvider: RustSymbolProvider, + parentShape: Shape, + definition: EnumDefinition, + ): MaybeRenamed? { + val name = definition.name.orNull()?.toPascalCase() ?: return null + // Create a fake member shape for symbol look up until we refactor to use EnumShape + val fakeMemberShape = + MemberShape.builder().id(parentShape.id.withMember(name)).target("smithy.api#String").build() + val symbol = symbolProvider.toSymbol(fakeMemberShape) + return MaybeRenamed(symbol.name, symbol.renamedFrom()) + } + } // Because enum variants always start with an upper case letter, they will never // conflict with reserved words (which are always lower case), therefore, we never need // to fall back to raw identifiers val value: String get() = definition.value - fun name(): MaybeRenamed? = symbolProvider.toEnumVariantName(definition) + fun name(): MaybeRenamed? = toEnumVariantName(symbolProvider, parentShape, definition) private fun renderDocumentation(writer: RustWriter) { val name = @@ -97,7 +128,7 @@ class EnumMemberModel(private val definition: EnumDefinition, private val symbol } } - fun derivedName() = checkNotNull(symbolProvider.toEnumVariantName(definition)).name + fun derivedName() = checkNotNull(toEnumVariantName(symbolProvider, parentShape, definition)).name fun render(writer: RustWriter) { renderDocumentation(writer) @@ -138,7 +169,7 @@ open class EnumGenerator( enumName = symbol.name, enumMeta = symbol.expectRustMetadata(), enumTrait = enumTrait, - sortedMembers = enumTrait.values.sortedBy { it.value }.map { EnumMemberModel(it, symbolProvider) }, + sortedMembers = enumTrait.values.sortedBy { it.value }.map { EnumMemberModel(shape, it, symbolProvider) }, ) fun render(writer: RustWriter) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt index 69cd25f2ea..dbec900302 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt @@ -16,6 +16,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.core.rustlang.docs import software.amazon.smithy.rust.codegen.core.rustlang.documentShape +import software.amazon.smithy.rust.codegen.core.rustlang.render import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate @@ -23,6 +24,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.expectRustMetadata import software.amazon.smithy.rust.codegen.core.smithy.renamedFrom +import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.util.REDACTION import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.hasTrait @@ -112,7 +114,7 @@ class UnionGenerator( if (sortedMembers.size == 1) { Attribute.AllowIrrefutableLetPatterns.render(this) } - writer.renderAsVariant(member, variantName, funcNamePart, unionSymbol, memberSymbol) + writer.renderAsVariant(model, symbolProvider, member, variantName, funcNamePart, unionSymbol) rust("/// Returns true if this is a [`$variantName`](#T::$variantName).", unionSymbol) rustBlock("pub fn is_$funcNamePart(&self) -> bool") { rust("self.as_$funcNamePart().is_ok()") @@ -183,11 +185,12 @@ private fun RustWriter.renderVariant(symbolProvider: SymbolProvider, member: Mem } private fun RustWriter.renderAsVariant( + model: Model, + symbolProvider: SymbolProvider, member: MemberShape, variantName: String, funcNamePart: String, unionSymbol: Symbol, - memberSymbol: Symbol, ) { if (member.isTargetUnit()) { rust( @@ -198,13 +201,15 @@ private fun RustWriter.renderAsVariant( rust("if let ${unionSymbol.name}::$variantName = &self { Ok(()) } else { Err(self) }") } } else { + val memberSymbol = symbolProvider.toSymbol(member) + val targetSymbol = symbolProvider.toSymbol(model.expectShape(member.target)) rust( "/// Tries to convert the enum instance into [`$variantName`](#T::$variantName), extracting the inner #D.", unionSymbol, - memberSymbol, + targetSymbol, ) rust("/// Returns `Err(&Self)` if it can't be converted.") - rustBlock("pub fn as_$funcNamePart(&self) -> std::result::Result<&#T, &Self>", memberSymbol) { + rustBlock("pub fn as_$funcNamePart(&self) -> std::result::Result<&${memberSymbol.rustType().render()}, &Self>") { rust("if let ${unionSymbol.name}::$variantName(val) = &self { Ok(val) } else { Err(self) }") } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamErrorMarshallerGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamErrorMarshallerGenerator.kt index 1324b91a11..ebd42d609d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamErrorMarshallerGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamErrorMarshallerGenerator.kt @@ -100,10 +100,10 @@ class EventStreamErrorMarshallerGenerator( } else { rustBlock("let payload = match _input") { errorsShape.errorMembers.forEach { error -> - val errorSymbol = symbolProvider.toSymbol(error) val errorString = error.memberName val target = model.expectShape(error.target, StructureShape::class.java) - rustBlock("#T::${errorSymbol.name}(inner) => ", operationErrorSymbol) { + val targetSymbol = symbolProvider.toSymbol(target) + rustBlock("#T::${targetSymbol.name}(inner) => ", operationErrorSymbol) { addStringHeader(":exception-type", "${errorString.dq()}.into()") renderMarshallEvent(error, target) } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt index 9ef10a5af8..676c6c6993 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt @@ -7,34 +7,19 @@ package software.amazon.smithy.rust.codegen.core.rustlang import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test -import software.amazon.smithy.codegen.core.Symbol +import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.Shape -import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumDefinition +import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.core.smithy.MaybeRenamed -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitorConfig +import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor +import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.renamedFrom +import software.amazon.smithy.rust.codegen.core.testutil.TestSymbolVisitorConfig import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel -import software.amazon.smithy.rust.codegen.core.util.PANIC -import software.amazon.smithy.rust.codegen.core.util.orNull -import software.amazon.smithy.rust.codegen.core.util.toPascalCase internal class RustReservedWordSymbolProviderTest { - class Stub : RustSymbolProvider { - override fun config(): SymbolVisitorConfig = PANIC() - override fun symbolForOperationError(operation: OperationShape): Symbol = PANIC() - override fun symbolForEventStreamError(eventStream: UnionShape): Symbol = PANIC() - - override fun toEnumVariantName(definition: EnumDefinition): MaybeRenamed? { - return definition.name.orNull()?.let { MaybeRenamed(it.toPascalCase(), null) } - } - - override fun toSymbol(shape: Shape): Symbol { - return Symbol.builder().name(shape.id.name).build() - } - } + private class TestSymbolProvider(model: Model) : + WrappingSymbolProvider(SymbolVisitor(model, null, TestSymbolVisitorConfig)) @Test fun `member names are escaped`() { @@ -44,7 +29,7 @@ internal class RustReservedWordSymbolProviderTest { async: String } """.trimMargin().asSmithyModel() - val provider = RustReservedWordSymbolProvider(Stub(), model) + val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model) provider.toMemberName( MemberShape.builder().id("namespace#container\$async").target("namespace#Integer").build(), ) shouldBe "r##async" @@ -56,6 +41,23 @@ internal class RustReservedWordSymbolProviderTest { @Test fun `enum variant names are updated to avoid conflicts`() { + val model = """ + namespace foo + @enum([{ name: "dontcare", value: "dontcare" }]) string Container + """.asSmithyModel() + val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model) + + fun expectEnumRename(original: String, expected: MaybeRenamed) { + val symbol = provider.toSymbol( + MemberShape.builder() + .id(ShapeId.fromParts("foo", "Container").withMember(original)) + .target("smithy.api#String") + .build(), + ) + symbol.name shouldBe expected.name + symbol.renamedFrom() shouldBe expected.renamedFrom + } + expectEnumRename("Unknown", MaybeRenamed("UnknownValue", "Unknown")) expectEnumRename("UnknownValue", MaybeRenamed("UnknownValue_", "UnknownValue")) expectEnumRename("UnknownOther", MaybeRenamed("UnknownOther", null)) @@ -65,10 +67,4 @@ internal class RustReservedWordSymbolProviderTest { expectEnumRename("SelfOther", MaybeRenamed("SelfOther", null)) expectEnumRename("SELF", MaybeRenamed("SelfValue", "Self")) } - - private fun expectEnumRename(original: String, expected: MaybeRenamed) { - val model = "namespace foo".asSmithyModel() - val provider = RustReservedWordSymbolProvider(Stub(), model) - provider.toEnumVariantName(EnumDefinition.builder().name(original).value("foo").build()) shouldBe expected - } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index e1ae567571..4761ec7afe 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -7,24 +7,17 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators import org.junit.jupiter.api.Test import software.amazon.smithy.codegen.core.Symbol -import software.amazon.smithy.model.shapes.MemberShape -import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.Shape -import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumDefinition import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.AllowDeprecated import software.amazon.smithy.rust.codegen.core.rustlang.implBlock import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.smithy.Default -import software.amazon.smithy.rust.codegen.core.smithy.MaybeRenamed -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitorConfig +import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.setDefault import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest -import software.amazon.smithy.rust.codegen.core.util.PANIC internal class BuilderGeneratorTest { private val model = StructureGeneratorTest.model @@ -65,25 +58,10 @@ internal class BuilderGeneratorTest { fun `generate fallible builders`() { val baseProvider = testSymbolProvider(StructureGeneratorTest.model) val provider = - object : RustSymbolProvider { - override fun config(): SymbolVisitorConfig { - return baseProvider.config() - } - - override fun toEnumVariantName(definition: EnumDefinition): MaybeRenamed? { - return baseProvider.toEnumVariantName(definition) - } - - override fun toSymbol(shape: Shape?): Symbol { + object : WrappingSymbolProvider(baseProvider) { + override fun toSymbol(shape: Shape): Symbol { return baseProvider.toSymbol(shape).toBuilder().setDefault(Default.NoDefault).build() } - - override fun symbolForOperationError(operation: OperationShape): Symbol = PANIC() - override fun symbolForEventStreamError(eventStream: UnionShape): Symbol = PANIC() - - override fun toMemberName(shape: MemberShape?): String { - return baseProvider.toMemberName(shape) - } } val project = TestWorkspace.testProject(provider) project.moduleFor(StructureGeneratorTest.struct) { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt index 480342e78d..2da87e1d45 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt @@ -51,8 +51,11 @@ class EnumGeneratorTest { private val enumTrait = testModel.lookup("test#EnumWithUnknown").expectTrait() - private fun model(name: String): EnumMemberModel = - EnumMemberModel(enumTrait.values.first { it.name.orNull() == name }, symbolProvider) + private fun model(name: String): EnumMemberModel = EnumMemberModel( + testModel.lookup("test#EnumWithUnknown"), + enumTrait.values.first { it.name.orNull() == name }, + symbolProvider, + ) @Test fun `it converts enum names to PascalCase and renames any named Unknown to UnknownValue`() { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorCommon.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorCommon.kt index f16e2640b2..389f0dc173 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorCommon.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorCommon.kt @@ -39,6 +39,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumMemberModel import software.amazon.smithy.rust.codegen.core.util.UNREACHABLE import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.expectTrait @@ -143,7 +144,9 @@ fun defaultValue( .entries .filter { entry -> entry.value == value } .map { entry -> - symbolProvider.toEnumVariantName( + EnumMemberModel.toEnumVariantName( + symbolProvider, + target, EnumDefinition.builder().name(entry.key).value(entry.value.toString()).build(), )!! } From c1add653e4f37ec9fe2c8591f2f20e29053d5be7 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 15 Feb 2023 14:00:37 -0800 Subject: [PATCH 2/6] Fix escaping of `Self` in symbol providers --- .../codegen/core/rustlang/RustReservedWords.kt | 7 +++++-- .../codegen/core/rustlang/RustReservedWordsTest.kt | 14 +++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt index ceb539911d..faf8cf4065 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt @@ -25,7 +25,10 @@ import software.amazon.smithy.rust.codegen.core.util.letIf class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, private val model: Model) : WrappingSymbolProvider(base) { private val internal = - ReservedWordSymbolProvider.builder().symbolProvider(base).memberReservedWords(RustReservedWords).build() + ReservedWordSymbolProvider.builder().symbolProvider(base) + .nameReservedWords(RustReservedWords) + .memberReservedWords(RustReservedWords) + .build() override fun toMemberName(shape: MemberShape): String { val baseName = super.toMemberName(shape) @@ -105,7 +108,7 @@ class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, priva }.build() } - else -> base.toSymbol(shape) + else -> renamedSymbol } } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt index 676c6c6993..45ce9f70b5 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt @@ -16,11 +16,23 @@ import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.renamedFrom import software.amazon.smithy.rust.codegen.core.testutil.TestSymbolVisitorConfig import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel +import software.amazon.smithy.rust.codegen.core.util.lookup internal class RustReservedWordSymbolProviderTest { private class TestSymbolProvider(model: Model) : WrappingSymbolProvider(SymbolVisitor(model, null, TestSymbolVisitorConfig)) + @Test + fun `structs are escaped`() { + val model = """ + namespace test + structure Self {} + """.asSmithyModel() + val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model) + val symbol = provider.toSymbol(model.lookup("test#Self")) + symbol.name shouldBe "r##Self" + } + @Test fun `member names are escaped`() { val model = """ @@ -28,7 +40,7 @@ internal class RustReservedWordSymbolProviderTest { structure container { async: String } - """.trimMargin().asSmithyModel() + """.asSmithyModel() val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model) provider.toMemberName( MemberShape.builder().id("namespace#container\$async").target("namespace#Integer").build(), From 3337f935d6602265d989039b20b203f59a17b53d Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 15 Feb 2023 14:23:43 -0800 Subject: [PATCH 3/6] Clean up an old hack --- .../core/rustlang/RustReservedWords.kt | 29 +++++++++---------- .../core/rustlang/RustReservedWordsTest.kt | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt index faf8cf4065..b59863f532 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt @@ -54,20 +54,10 @@ class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, priva // that represent union variants that have been added since this SDK was generated. UnionGenerator.UnknownVariantName -> "${UnionGenerator.UnknownVariantName}Value" "${UnionGenerator.UnknownVariantName}Value" -> "${UnionGenerator.UnknownVariantName}Value_" - // Self cannot be used as a raw identifier, so we can't use the normal escaping strategy - // https://internals.rust-lang.org/t/raw-identifiers-dont-work-for-all-identifiers/9094/4 - "Self" -> "SelfValue" - // Real models won't end in `_` so it's safe to stop here - "SelfValue" -> "SelfValue_" else -> reservedWordReplacedName } container is EnumShape || container.hasTrait() -> when (baseName) { - // Self cannot be used as a raw identifier, so we can't use the normal escaping strategy - // https://internals.rust-lang.org/t/raw-identifiers-dont-work-for-all-identifiers/9094/4 - "Self" -> "SelfValue" - // Real models won't end in `_` so it's safe to stop here - "SelfValue" -> "SelfValue_" // Unknown is used as the name of the variant containing unexpected values "Unknown" -> "UnknownValue" // Real models won't end in `_` so it's safe to stop here @@ -170,11 +160,20 @@ object RustReservedWords : ReservedWords { "try", ) - private val cantBeRaw = setOf("self", "crate", "super") + // Some things can't be used as a raw identifier, so we can't use the normal escaping strategy + // https://internals.rust-lang.org/t/raw-identifiers-dont-work-for-all-identifiers/9094/4 + private val keywordEscapingMap = mapOf( + "crate" to "crate_", + "super" to "super_", + "self" to "self_", + "Self" to "SelfValue", + // Real models won't end in `_` so it's safe to stop here + "SelfValue" to "SelfValue_", + ) - override fun escape(word: String): String = when { - cantBeRaw.contains(word) -> "${word}_" - else -> "r##$word" + override fun escape(word: String): String = when (val mapped = keywordEscapingMap[word]) { + null -> "r##$word" + else -> mapped } fun escapeIfNeeded(word: String): String = when (isReserved(word)) { @@ -182,5 +181,5 @@ object RustReservedWords : ReservedWords { else -> word } - override fun isReserved(word: String): Boolean = RustKeywords.contains(word) + override fun isReserved(word: String): Boolean = RustKeywords.contains(word) || keywordEscapingMap.contains(word) } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt index 45ce9f70b5..8ff6b9d6ca 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt @@ -30,7 +30,7 @@ internal class RustReservedWordSymbolProviderTest { """.asSmithyModel() val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model) val symbol = provider.toSymbol(model.lookup("test#Self")) - symbol.name shouldBe "r##Self" + symbol.name shouldBe "SelfValue" } @Test From 4f5907602eba24222978253eaa4414587a97a6c3 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Wed, 15 Feb 2023 15:12:07 -0800 Subject: [PATCH 4/6] Make `RustReservedWordsSymbolProvider` configurable --- .../client/smithy/ClientReservedWords.kt | 35 ++++++ .../client/smithy/RustClientCodegenPlugin.kt | 2 +- .../core/rustlang/RustReservedWords.kt | 50 ++++----- .../smithy/generators/StructureGenerator.kt | 9 ++ .../rust/codegen/core/testutil/TestHelpers.kt | 14 ++- .../core/rustlang/RustReservedWordsTest.kt | 104 +++++++++++++++++- .../smithy/generators/EnumGeneratorTest.kt | 11 +- .../generators/StructureGeneratorTest.kt | 31 ++++-- .../smithy/RustServerCodegenPythonPlugin.kt | 3 +- .../server/smithy/RustServerCodegenPlugin.kt | 2 +- .../server/smithy/ServerReservedWords.kt | 15 +++ 11 files changed, 227 insertions(+), 49 deletions(-) create mode 100644 codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt create mode 100644 codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt new file mode 100644 index 0000000000..f73a8b5d5b --- /dev/null +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt @@ -0,0 +1,35 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.client.smithy + +import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordConfig +import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator +import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator + +val ClientReservedWords = RustReservedWordConfig( + structMemberMap = StructureGenerator.structMemberMap + + mapOf( + "send" to "send_value", + // To avoid conflicts with the `make_operation` and `presigned` functions on generated inputs + "make_operation" to "make_operation_value", + "presigned" to "presigned_value", + "customize" to "customize_value", + // To avoid conflicts with the error metadata `meta` field + "meta" to "meta_value", + ), + unionMemberMap = mapOf( + // Unions contain an `Unknown` variant. This exists to support parsing data returned from the server + // that represent union variants that have been added since this SDK was generated. + UnionGenerator.UnknownVariantName to "${UnionGenerator.UnknownVariantName}Value", + "${UnionGenerator.UnknownVariantName}Value" to "${UnionGenerator.UnknownVariantName}Value_", + ), + enumMemberMap = mapOf( + // Unknown is used as the name of the variant containing unexpected values + "Unknown" to "UnknownValue", + // Real models won't end in `_` so it's safe to stop here + "UnknownValue" to "UnknownValue_", + ), +) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index aa94e25b77..fe6186e363 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -84,6 +84,6 @@ class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { .let { StreamingShapeMetadataProvider(it, model) } // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot // be the name of an operation input - .let { RustReservedWordSymbolProvider(it, model) } + .let { RustReservedWordSymbolProvider(it, model, ClientReservedWords) } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt index b59863f532..a08016d80d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt @@ -17,13 +17,24 @@ import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator import software.amazon.smithy.rust.codegen.core.smithy.renamedFrom import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.letIf -class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, private val model: Model) : - WrappingSymbolProvider(base) { +data class RustReservedWordConfig( + /** Map of struct member names that should get renamed */ + val structMemberMap: Map, + /** Map of union member names that should get renamed */ + val unionMemberMap: Map, + /** Map of enum member names that should get renamed */ + val enumMemberMap: Map, +) + +class RustReservedWordSymbolProvider( + private val base: RustSymbolProvider, + private val model: Model, + private val config: RustReservedWordConfig, +) : WrappingSymbolProvider(base) { private val internal = ReservedWordSymbolProvider.builder().symbolProvider(base) .nameReservedWords(RustReservedWords) @@ -35,34 +46,19 @@ class RustReservedWordSymbolProvider(private val base: RustSymbolProvider, priva val reservedWordReplacedName = internal.toMemberName(shape) val container = model.expectShape(shape.container) return when { - container is StructureShape -> when (baseName) { - "build" -> "build_value" - "builder" -> "builder_value" - "default" -> "default_value" - "send" -> "send_value" - // To avoid conflicts with the `make_operation` and `presigned` functions on generated inputs - "make_operation" -> "make_operation_value" - "presigned" -> "presigned_value" - "customize" -> "customize_value" - // To avoid conflicts with the error metadata `meta` field - "meta" -> "meta_value" - else -> reservedWordReplacedName + container is StructureShape -> when (val mapped = config.structMemberMap[baseName]) { + null -> reservedWordReplacedName + else -> mapped } - container is UnionShape -> when (baseName) { - // Unions contain an `Unknown` variant. This exists to support parsing data returned from the server - // that represent union variants that have been added since this SDK was generated. - UnionGenerator.UnknownVariantName -> "${UnionGenerator.UnknownVariantName}Value" - "${UnionGenerator.UnknownVariantName}Value" -> "${UnionGenerator.UnknownVariantName}Value_" - else -> reservedWordReplacedName + container is UnionShape -> when (val mapped = config.unionMemberMap[baseName]) { + null -> reservedWordReplacedName + else -> mapped } - container is EnumShape || container.hasTrait() -> when (baseName) { - // Unknown is used as the name of the variant containing unexpected values - "Unknown" -> "UnknownValue" - // Real models won't end in `_` so it's safe to stop here - "UnknownValue" -> "UnknownValue_" - else -> reservedWordReplacedName + container is EnumShape || container.hasTrait() -> when (val mapped = config.enumMemberMap[baseName]) { + null -> reservedWordReplacedName + else -> mapped } else -> error("unexpected container: $container") diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index 46f0c31544..215495fe0e 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -60,6 +60,15 @@ open class StructureGenerator( private val shape: StructureShape, private val customizations: List, ) { + companion object { + /** Reserved struct member names */ + val structMemberMap: Map = mapOf( + "build" to "build_value", + "builder" to "builder_value", + "default" to "default_value", + ) + } + private val errorTrait = shape.getTrait() protected val members: List = shape.allMembers.values.toList() private val accessorMembers: List = when (errorTrait) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt index 2e80865640..8cfbee38e3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt @@ -16,6 +16,7 @@ import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.ErrorTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustModule +import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordConfig import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolProvider import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.implBlock @@ -113,12 +114,21 @@ fun String.asSmithyModel(sourceLocation: String? = null, smithyVersion: String = } // Intentionally only visible to codegen-core since the other modules have their own symbol providers -internal fun testSymbolProvider(model: Model): RustSymbolProvider = SymbolVisitor( +internal fun testSymbolProvider( + model: Model, + rustReservedWordConfig: RustReservedWordConfig? = null, +): RustSymbolProvider = SymbolVisitor( model, ServiceShape.builder().version("test").id("test#Service").build(), TestSymbolVisitorConfig, ).let { BaseSymbolMetadataProvider(it, model, additionalAttributes = listOf(Attribute.NonExhaustive)) } - .let { RustReservedWordSymbolProvider(it, model) } + .let { + RustReservedWordSymbolProvider( + it, + model, + rustReservedWordConfig ?: RustReservedWordConfig(emptyMap(), emptyMap(), emptyMap()), + ) + } // Intentionally only visible to codegen-core since the other modules have their own contexts internal fun testCodegenContext( diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt index 8ff6b9d6ca..cdcdcc5aed 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt @@ -21,6 +21,7 @@ import software.amazon.smithy.rust.codegen.core.util.lookup internal class RustReservedWordSymbolProviderTest { private class TestSymbolProvider(model: Model) : WrappingSymbolProvider(SymbolVisitor(model, null, TestSymbolVisitorConfig)) + private val emptyConfig = RustReservedWordConfig(emptyMap(), emptyMap(), emptyMap()) @Test fun `structs are escaped`() { @@ -28,11 +29,100 @@ internal class RustReservedWordSymbolProviderTest { namespace test structure Self {} """.asSmithyModel() - val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model) + val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model, emptyConfig) val symbol = provider.toSymbol(model.lookup("test#Self")) symbol.name shouldBe "SelfValue" } + private fun mappingTest(config: RustReservedWordConfig, model: Model, id: String, test: (String) -> Unit) { + val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model, config) + val symbol = provider.toMemberName(model.lookup("test#Container\$$id")) + test(symbol) + } + + @Test + fun `structs member names are mapped via config`() { + val config = emptyConfig.copy( + structMemberMap = mapOf( + "name_to_map" to "mapped_name", + "NameToMap" to "MappedName", + ), + ) + var model = """ + namespace test + structure Container { + name_to_map: String + } + """.asSmithyModel() + mappingTest(config, model, "name_to_map") { memberName -> + memberName shouldBe "mapped_name" + } + + model = """ + namespace test + enum Container { + NameToMap = "NameToMap" + } + """.asSmithyModel(smithyVersion = "2.0") + mappingTest(config, model, "NameToMap") { memberName -> + // Container was not a struct, so the field keeps its old name + memberName shouldBe "NameToMap" + } + + model = """ + namespace test + union Container { + NameToMap: String + } + """.asSmithyModel() + mappingTest(config, model, "NameToMap") { memberName -> + // Container was not a struct, so the field keeps its old name + memberName shouldBe "NameToMap" + } + } + + @Test + fun `union member names are mapped via config`() { + val config = emptyConfig.copy( + unionMemberMap = mapOf( + "name_to_map" to "mapped_name", + "NameToMap" to "MappedName", + ), + ) + + var model = """ + namespace test + union Container { + NameToMap: String + } + """.asSmithyModel() + mappingTest(config, model, "NameToMap") { memberName -> + memberName shouldBe "MappedName" + } + + model = """ + namespace test + structure Container { + name_to_map: String + } + """.asSmithyModel() + mappingTest(config, model, "name_to_map") { memberName -> + // Container was not a union, so the field keeps its old name + memberName shouldBe "name_to_map" + } + + model = """ + namespace test + enum Container { + NameToMap = "NameToMap" + } + """.asSmithyModel(smithyVersion = "2.0") + mappingTest(config, model, "NameToMap") { memberName -> + // Container was not a union, so the field keeps its old name + memberName shouldBe "NameToMap" + } + } + @Test fun `member names are escaped`() { val model = """ @@ -41,7 +131,7 @@ internal class RustReservedWordSymbolProviderTest { async: String } """.asSmithyModel() - val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model) + val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model, emptyConfig) provider.toMemberName( MemberShape.builder().id("namespace#container\$async").target("namespace#Integer").build(), ) shouldBe "r##async" @@ -57,7 +147,15 @@ internal class RustReservedWordSymbolProviderTest { namespace foo @enum([{ name: "dontcare", value: "dontcare" }]) string Container """.asSmithyModel() - val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model), model) + val provider = RustReservedWordSymbolProvider( + TestSymbolProvider(model), model, + config = emptyConfig.copy( + enumMemberMap = mapOf( + "Unknown" to "UnknownValue", + "UnknownValue" to "UnknownValue_", + ), + ), + ) fun expectEnumRename(original: String, expected: MaybeRenamed) { val symbol = provider.toSymbol( diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt index 2da87e1d45..77a90f6b97 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt @@ -14,6 +14,7 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.AllowDeprecated +import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordConfig import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -30,6 +31,12 @@ import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.orNull class EnumGeneratorTest { + private val rustReservedWordConfig = RustReservedWordConfig( + enumMemberMap = mapOf("Unknown" to "UnknownValue"), + structMemberMap = emptyMap(), + unionMemberMap = emptyMap(), + ) + @Nested inner class EnumMemberModelTests { private val testModel = """ @@ -47,7 +54,7 @@ class EnumGeneratorTest { ]) string EnumWithUnknown """.asSmithyModel() - private val symbolProvider = testSymbolProvider(testModel) + private val symbolProvider = testSymbolProvider(testModel, rustReservedWordConfig = rustReservedWordConfig) private val enumTrait = testModel.lookup("test#EnumWithUnknown").expectTrait() @@ -276,7 +283,7 @@ class EnumGeneratorTest { """.asSmithyModel() val shape = model.lookup("test#SomeEnum") - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.moduleFor(shape) { renderEnum(model, provider, shape) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt index 72a2dce315..6631813ed3 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt @@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustModule +import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordConfig import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock @@ -85,11 +86,17 @@ class StructureGeneratorTest { val secretStructure = model.lookup("com.test#SecretStructure") val structWithInnerSecretStructure = model.lookup("com.test#StructWithInnerSecretStructure") val error = model.lookup("com.test#MyError") + + val rustReservedWordConfig: RustReservedWordConfig = RustReservedWordConfig( + structMemberMap = StructureGenerator.structMemberMap, + enumMemberMap = emptyMap(), + unionMemberMap = emptyMap(), + ) } @Test fun `generate basic structures`() { - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.useShapeWriter(inner) { StructureGenerator(model, provider, this, inner, emptyList()).render() @@ -110,7 +117,7 @@ class StructureGeneratorTest { @Test fun `generate structures with public fields`() { - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.lib { Attribute.AllowDeprecated.render(this) } @@ -140,7 +147,7 @@ class StructureGeneratorTest { @Test fun `generate a custom debug implementation when the sensitive trait is applied to some members`() { - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val writer = RustWriter.forModule("lib") val generator = StructureGenerator(model, provider, writer, credentials, emptyList()) generator.render() @@ -160,7 +167,7 @@ class StructureGeneratorTest { @Test fun `generate a custom debug implementation when the sensitive trait is applied to the struct`() { - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val writer = RustWriter.forModule("lib") val generator = StructureGenerator(model, provider, writer, secretStructure, emptyList()) generator.render() @@ -178,7 +185,7 @@ class StructureGeneratorTest { @Test fun `generate a custom debug implementation when the sensitive trait is applied to an inner struct`() { - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.useShapeWriter(inner) { val secretGenerator = StructureGenerator(model, provider, this, secretStructure, emptyList()) @@ -219,7 +226,7 @@ class StructureGeneratorTest { nested2: Inner }""".asSmithyModel() - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.lib { Attribute.DenyMissingDocs.render(this) @@ -234,7 +241,7 @@ class StructureGeneratorTest { @Test fun `documents are optional in structs`() { - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val writer = RustWriter.forModule("lib") StructureGenerator(model, provider, writer, structWithDoc, emptyList()).render() @@ -265,7 +272,7 @@ class StructureGeneratorTest { @deprecated(message: "Fly, you fools!", since: "1.2.3") structure Qux {} """.asSmithyModel() - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.lib { rust("##![allow(deprecated)]") } project.moduleFor(model.lookup("test#Foo")) { @@ -298,7 +305,7 @@ class StructureGeneratorTest { @deprecated structure Bar {} """.asSmithyModel() - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.lib { rust("##![allow(deprecated)]") } project.moduleFor(model.lookup("test#Nested")) { @@ -347,7 +354,7 @@ class StructureGeneratorTest { } """.asSmithyModel(), ) - val provider = testSymbolProvider(testModel) + val provider = testSymbolProvider(testModel, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.useShapeWriter(inner) { @@ -407,7 +414,7 @@ class StructureGeneratorTest { """.asSmithyModel() val struct = model.lookup("com.test#MyStruct") - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) RustWriter.forModule("test").let { StructureGenerator(model, provider, it, struct, emptyList()).render() assertEquals(6, it.toString().split("#[doc(hidden)]").size, "there should be 5 doc-hiddens") @@ -423,7 +430,7 @@ class StructureGeneratorTest { """.asSmithyModel() val struct = model.lookup("com.test#MyStruct") - val provider = testSymbolProvider(model) + val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) RustWriter.forModule("test").let { writer -> StructureGenerator(model, provider, writer, struct, emptyList()).render() writer.toString().shouldNotContain("#[doc(hidden)]") diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/RustServerCodegenPythonPlugin.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/RustServerCodegenPythonPlugin.kt index 19e3e0dba2..3e038b03c8 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/RustServerCodegenPythonPlugin.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/RustServerCodegenPythonPlugin.kt @@ -19,6 +19,7 @@ import software.amazon.smithy.rust.codegen.server.python.smithy.customizations.D import software.amazon.smithy.rust.codegen.server.smithy.ConstrainedShapeSymbolMetadataProvider import software.amazon.smithy.rust.codegen.server.smithy.ConstrainedShapeSymbolProvider import software.amazon.smithy.rust.codegen.server.smithy.DeriveEqAndHashSymbolMetadataProvider +import software.amazon.smithy.rust.codegen.server.smithy.ServerReservedWords import software.amazon.smithy.rust.codegen.server.smithy.customizations.CustomValidationExceptionWithReasonDecorator import software.amazon.smithy.rust.codegen.server.smithy.customizations.ServerRequiredCustomizations import software.amazon.smithy.rust.codegen.server.smithy.customizations.SmithyValidationExceptionDecorator @@ -92,6 +93,6 @@ class RustServerCodegenPythonPlugin : SmithyBuildPlugin { .let { DeriveEqAndHashSymbolMetadataProvider(it, model) } // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot // be the name of an operation input - .let { RustReservedWordSymbolProvider(it, model) } + .let { RustReservedWordSymbolProvider(it, model, ServerReservedWords) } } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustServerCodegenPlugin.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustServerCodegenPlugin.kt index 812bc50916..fabcab4cb9 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustServerCodegenPlugin.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustServerCodegenPlugin.kt @@ -85,6 +85,6 @@ class RustServerCodegenPlugin : ServerDecoratableBuildPlugin() { .let { DeriveEqAndHashSymbolMetadataProvider(it, model) } // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot // be the name of an operation input - .let { RustReservedWordSymbolProvider(it, model) } + .let { RustReservedWordSymbolProvider(it, model, ServerReservedWords) } } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt new file mode 100644 index 0000000000..9b913b4a72 --- /dev/null +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt @@ -0,0 +1,15 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.server.smithy + +import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordConfig +import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator + +val ServerReservedWords = RustReservedWordConfig( + structMemberMap = StructureGenerator.structMemberMap, + unionMemberMap = emptyMap(), + enumMemberMap = emptyMap(), +) From 4097d45d8b309175f29406af6ae577c826ef0a74 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Fri, 10 Mar 2023 11:22:55 -0800 Subject: [PATCH 5/6] Update changelog --- CHANGELOG.next.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index b785b2e4c0..31f396ac92 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -263,3 +263,9 @@ message = "Add more client re-exports. Specifically, it re-exports `aws_smithy_h references = ["smithy-rs#2437", "aws-sdk-rust#600"] meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } author = "ysaito1001" + +[[smithy-rs]] +message = "Smithy members named `send` were previously renamed to `send_value` at codegen time. These will now be called `send` in the generated code." +references = ["smithy-rs#2382"] +meta = { "breaking" = true, "tada" = false, "bug" = true, "target" = "server" } +author = "jdisanti" From a88b8477c1814053575673a9c333d2be4d0eb077 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Mon, 13 Mar 2023 11:52:18 -0700 Subject: [PATCH 6/6] Incorporate feedback --- .../client/smithy/ClientReservedWords.kt | 2 +- .../core/rustlang/RustReservedWords.kt | 20 +++++++------------ .../smithy/generators/StructureGenerator.kt | 2 +- .../core/rustlang/RustReservedWordsTest.kt | 2 +- .../smithy/generators/EnumGeneratorTest.kt | 2 +- .../generators/StructureGeneratorTest.kt | 2 +- .../server/smithy/ServerReservedWords.kt | 2 +- 7 files changed, 13 insertions(+), 19 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt index f73a8b5d5b..add9f53f6d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt @@ -10,7 +10,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGener import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator val ClientReservedWords = RustReservedWordConfig( - structMemberMap = StructureGenerator.structMemberMap + + structureMemberMap = StructureGenerator.structureMemberNameMap + mapOf( "send" to "send_value", // To avoid conflicts with the `make_operation` and `presigned` functions on generated inputs diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt index b1f9db08eb..c9fdbafb13 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt @@ -22,7 +22,7 @@ import software.amazon.smithy.rust.codegen.core.util.letIf data class RustReservedWordConfig( /** Map of struct member names that should get renamed */ - val structMemberMap: Map, + val structureMemberMap: Map, /** Map of union member names that should get renamed */ val unionMemberMap: Map, /** Map of enum member names that should get renamed */ @@ -44,20 +44,14 @@ class RustReservedWordSymbolProvider( val reservedWordReplacedName = internal.toMemberName(shape) val container = model.expectShape(shape.container) return when { - container is StructureShape -> when (val mapped = reservedWordConfig.structMemberMap[baseName]) { - null -> reservedWordReplacedName - else -> mapped - } + container is StructureShape -> + reservedWordConfig.structureMemberMap.getOrDefault(baseName, reservedWordReplacedName) - container is UnionShape -> when (val mapped = reservedWordConfig.unionMemberMap[baseName]) { - null -> reservedWordReplacedName - else -> mapped - } + container is UnionShape -> + reservedWordConfig.unionMemberMap.getOrDefault(baseName, reservedWordReplacedName) - container is EnumShape || container.hasTrait() -> when (val mapped = reservedWordConfig.enumMemberMap[baseName]) { - null -> reservedWordReplacedName - else -> mapped - } + container is EnumShape || container.hasTrait() -> + reservedWordConfig.enumMemberMap.getOrDefault(baseName, reservedWordReplacedName) else -> error("unexpected container: $container") } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index 5df847c4a1..6905058d46 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -62,7 +62,7 @@ open class StructureGenerator( ) { companion object { /** Reserved struct member names */ - val structMemberMap: Map = mapOf( + val structureMemberNameMap: Map = mapOf( "build" to "build_value", "builder" to "builder_value", "default" to "default_value", diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt index 230df98ae7..25e47e0963 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt @@ -44,7 +44,7 @@ internal class RustReservedWordSymbolProviderTest { @Test fun `structs member names are mapped via config`() { val config = emptyConfig.copy( - structMemberMap = mapOf( + structureMemberMap = mapOf( "name_to_map" to "mapped_name", "NameToMap" to "MappedName", ), diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt index 77a90f6b97..b233a763bd 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt @@ -33,7 +33,7 @@ import software.amazon.smithy.rust.codegen.core.util.orNull class EnumGeneratorTest { private val rustReservedWordConfig = RustReservedWordConfig( enumMemberMap = mapOf("Unknown" to "UnknownValue"), - structMemberMap = emptyMap(), + structureMemberMap = emptyMap(), unionMemberMap = emptyMap(), ) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt index 0cd4a0ad10..86e81c45f9 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt @@ -88,7 +88,7 @@ class StructureGeneratorTest { val error = model.lookup("com.test#MyError") val rustReservedWordConfig: RustReservedWordConfig = RustReservedWordConfig( - structMemberMap = StructureGenerator.structMemberMap, + structureMemberMap = StructureGenerator.structureMemberNameMap, enumMemberMap = emptyMap(), unionMemberMap = emptyMap(), ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt index 9b913b4a72..64d9ea04f4 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt @@ -9,7 +9,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordConfig import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator val ServerReservedWords = RustReservedWordConfig( - structMemberMap = StructureGenerator.structMemberMap, + structureMemberMap = StructureGenerator.structureMemberNameMap, unionMemberMap = emptyMap(), enumMemberMap = emptyMap(), )