Unverified Commit 4835af9d authored by John DiSanti's avatar John DiSanti Committed by GitHub
Browse files

Make `RustReservedWordsSymbolProvider` configurable (#2382)

* 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.

* Fix escaping of `Self` in symbol providers

* Clean up an old hack

* Make `RustReservedWordsSymbolProvider` configurable

* Update changelog

* Incorporate feedback
parent 2f60a5e0
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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"
+35 −0
Original line number Diff line number Diff line
/*
 * 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(
    structureMemberMap = StructureGenerator.structureMemberNameMap +
        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_",
    ),
)
+1 −1
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() {
                .let { StreamingShapeMetadataProvider(it) }
                // 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) }
                .let { RustReservedWordSymbolProvider(it, ClientReservedWords) }
                // Allows decorators to inject a custom symbol provider
                .let { codegenDecorator.symbolProvider(it) }
    }
+19 −29
Original line number Diff line number Diff line
@@ -16,12 +16,23 @@ 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) : WrappingSymbolProvider(base) {
data class RustReservedWordConfig(
    /** Map of struct member names that should get renamed */
    val structureMemberMap: Map<String, String>,
    /** Map of union member names that should get renamed */
    val unionMemberMap: Map<String, String>,
    /** Map of enum member names that should get renamed */
    val enumMemberMap: Map<String, String>,
)

class RustReservedWordSymbolProvider(
    private val base: RustSymbolProvider,
    private val reservedWordConfig: RustReservedWordConfig,
) : WrappingSymbolProvider(base) {
    private val internal =
        ReservedWordSymbolProvider.builder().symbolProvider(base)
            .nameReservedWords(RustReservedWords)
@@ -33,35 +44,14 @@ class RustReservedWordSymbolProvider(private val base: RustSymbolProvider) : Wra
        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 ->
                reservedWordConfig.structureMemberMap.getOrDefault(baseName, reservedWordReplacedName)

            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 ->
                reservedWordConfig.unionMemberMap.getOrDefault(baseName, reservedWordReplacedName)

            container is EnumShape || container.hasTrait<EnumTrait>() -> 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<EnumTrait>() ->
                reservedWordConfig.enumMemberMap.getOrDefault(baseName, reservedWordReplacedName)

            else -> error("unexpected container: $container")
        }
+9 −0
Original line number Diff line number Diff line
@@ -60,6 +60,15 @@ open class StructureGenerator(
    private val shape: StructureShape,
    private val customizations: List<StructureCustomization>,
) {
    companion object {
        /** Reserved struct member names */
        val structureMemberNameMap: Map<String, String> = mapOf(
            "build" to "build_value",
            "builder" to "builder_value",
            "default" to "default_value",
        )
    }

    private val errorTrait = shape.getTrait<ErrorTrait>()
    protected val members: List<MemberShape> = shape.allMembers.values.toList()
    private val accessorMembers: List<MemberShape> = when (errorTrait) {
Loading