From fb3758aaa1a2559b2b598499c048a9742ca30966 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Mon, 13 Nov 2023 12:52:48 -0500 Subject: [PATCH] Fix compilation error in generate code caused by name collision (#3175) ## Motivation and Context If you had a model like this: ```smithy @http(uri: "/SomeOperation2", method: "GET") operation GetThing { // input: GetThingInput, output: GetThingOutput } ``` But then nested in some other API you did something like this: ```smithy list GetThings { member: GetThingOutput } ``` Code would fail to compile because we generated the same method signature for two different types. ## Description ## Testing - [x] fixes minimal reproducer ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --- .../client/smithy/NamingObstacleCourseTest.kt | 13 +++++ .../smithy/protocols/ProtocolFunctions.kt | 9 ++- .../NamingObstacleCourseTestModels.kt | 58 +++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/NamingObstacleCourseTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/NamingObstacleCourseTest.kt index aba0edc1a..addc4d8f1 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/NamingObstacleCourseTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/NamingObstacleCourseTest.kt @@ -6,7 +6,10 @@ package software.amazon.smithy.rust.codegen.client.smithy import org.junit.jupiter.api.Test +import software.amazon.smithy.aws.traits.protocols.RestJson1Trait +import software.amazon.smithy.aws.traits.protocols.RestXmlTrait import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest +import software.amazon.smithy.rust.codegen.core.testutil.NamingObstacleCourseTestModels.reusedInputOutputShapesModel import software.amazon.smithy.rust.codegen.core.testutil.NamingObstacleCourseTestModels.rustPreludeEnumVariantsModel import software.amazon.smithy.rust.codegen.core.testutil.NamingObstacleCourseTestModels.rustPreludeEnumsModel import software.amazon.smithy.rust.codegen.core.testutil.NamingObstacleCourseTestModels.rustPreludeOperationsModel @@ -32,4 +35,14 @@ class NamingObstacleCourseTest { fun `test Rust prelude enum variant names compile`() { clientIntegrationTest(rustPreludeEnumVariantsModel()) { _, _ -> } } + + @Test + fun `test reuse of input and output shapes json`() { + clientIntegrationTest(reusedInputOutputShapesModel(RestJson1Trait.builder().build())) + } + + @Test + fun `test reuse of input and output shapes xml`() { + clientIntegrationTest(reusedInputOutputShapesModel(RestXmlTrait.builder().build())) + } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctions.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctions.kt index 53bdfc009..c468fdca0 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctions.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctions.kt @@ -18,6 +18,10 @@ import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext 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.contextName +import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticInputTrait +import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticOutputTrait +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.toSnakeCase /** @@ -139,10 +143,13 @@ internal fun RustSymbolProvider.shapeModuleName(serviceShape: ServiceShape?, sha /** Creates a unique name for a ser/de function. */ fun RustSymbolProvider.shapeFunctionName(serviceShape: ServiceShape?, shape: Shape): String { + val extras = "".letIf(shape.hasTrait()) { + it + "_output" + }.letIf(shape.hasTrait()) { it + "_input" } val containerName = when (shape) { is MemberShape -> model.expectShape(shape.container).contextName(serviceShape).toSnakeCase() else -> shape.contextName(serviceShape).toSnakeCase() - } + } + extras return when (shape) { is MemberShape -> shape.memberName.toSnakeCase() is DocumentShape -> "document" diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/NamingObstacleCourseTestModels.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/NamingObstacleCourseTestModels.kt index c45a7d099..72979545b 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/NamingObstacleCourseTestModels.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/NamingObstacleCourseTestModels.kt @@ -6,6 +6,7 @@ package software.amazon.smithy.rust.codegen.core.testutil import software.amazon.smithy.model.Model +import software.amazon.smithy.model.traits.Trait import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope object NamingObstacleCourseTestModels { @@ -169,4 +170,61 @@ object NamingObstacleCourseTestModels { """, ) }.toString().asSmithyModel() + + /** + * This targets two bug classes: + * - operation inputs used as nested outputs + * - operation outputs used as nested outputs + */ + fun reusedInputOutputShapesModel(protocol: Trait) = """ + namespace test + use ${protocol.toShapeId()} + use aws.api#service + @${protocol.toShapeId().name} + @service(sdkId: "test") + service Service { + version: "2006-03-01", + operations: [GetThing, ReuseGetThingIO] + } + + // re-use get thing output in a list & in an operation + @http(uri: "/SomeOperation2", method: "POST") + operation GetThing { + output: GetThingOutput + input: GetThingInput + } + + // an operation that re-uses the input and output shapes from `GetThing` above. this has caused issues in the + // past with operation/input shape confusion during function signature generation + @http(uri: "/SomeOperation3", method: "POST") + operation ReuseGetThingIO { + input: GetThingNested + output: GetThingNested + } + + structure GetThingOutput { + @required + meta: String + } + + structure GetThingInput { + @required + meta: String + } + + // nested structure which reuses input and output shapes internally + structure GetThingNested { + thingsOut: GetThingOutputList, + thingsIn: GetThingInputList, + thingOut: GetThingOutput, + thingIn: GetThingInput + } + + list GetThingOutputList { + member: GetThingOutput + } + list GetThingInputList { + member: GetThingInput + } + """.asSmithyModel() } -- GitLab