From 68043128c3bf9f5e65c364d3fd37e969ffea98a9 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 14:28:58 +0100 Subject: [PATCH 01/17] Add helper for creating deprecated attribute * `Attribute.Custom.deprecated` is the main logic for building up `#[deprecated]` attribute * `RustWriter.deprecatedShape` is the counterpart of `documentShape`, but we do not going to generalize it as what `documentShape` does. Deprecated is only for Rust code and probably won't be used in other output language. Signed-off-by: Weihang Lo --- .../smithy/rust/codegen/rustlang/RustTypes.kt | 22 +++++++++++++++++++ .../rust/codegen/rustlang/RustWriter.kt | 16 ++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt index 84673f2239..ad4ac83f72 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt @@ -375,6 +375,28 @@ sealed class Attribute { writer.addDependency(it.dependency) } } + + companion object { + /** + * Renders a + * [`#[deprecated]`](https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute) + * attribute. + */ + fun deprecated(note: String = "", since: String = ""): Custom { + val builder = StringBuilder() + builder.append("deprecated") + if (note.isBlank().and(since.isBlank())) { + // No-op. Rustc would emit a default message. + } else if (note.isNotBlank().and(since.isBlank())) { + builder.append("(note = \"${note}\")") + } else if (note.isBlank().and(since.isNotBlank())) { + builder.append("(since = \"${since}\")") + } else { + builder.append("(note = \"${note}\", since = \"${since}\")") + } + return Custom(builder.toString()) + } + } } data class Cfg(val cond: String) : Attribute() { diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt index 027e6d153b..f6953bdce8 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt @@ -18,10 +18,12 @@ import software.amazon.smithy.model.shapes.CollectionShape import software.amazon.smithy.model.shapes.NumberShape import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.model.traits.DeprecatedTrait import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.smithy.RuntimeType import software.amazon.smithy.rust.codegen.smithy.isOptional import software.amazon.smithy.rust.codegen.smithy.rustType +import software.amazon.smithy.rust.codegen.util.getTrait import software.amazon.smithy.rust.codegen.util.orNull import software.amazon.smithy.utils.AbstractCodeWriter import java.io.File @@ -269,6 +271,20 @@ fun > T.docs(text: String, vararg args: Any, newlinePr return this } +/** + * Generates a `#[deprecated]` attribute for [shape]. + */ +fun RustWriter.deprecatedShape(shape: Shape): RustWriter { + val deprecatedTrait = shape.getTrait() ?: return this + + val note = deprecatedTrait.message.orElse("") + val since = deprecatedTrait.since.orElse("") + + Attribute.Custom.deprecated(note, since).render(this) + + return this +} + /** Escape the [expressionStart] character to avoid problems during formatting */ fun > T.escape(text: String): String = text.replace("$expressionStart", "$expressionStart$expressionStart") From b1f5bc5eaf9b87b845233415cee4c93e0305d960 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 15:30:05 +0100 Subject: [PATCH 02/17] Test `@deprecated` trait for RustWriter --- .../amazon/smithy/rust/lang/RustWriterTest.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/lang/RustWriterTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/lang/RustWriterTest.kt index b42dbe7773..5e3d658e99 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/lang/RustWriterTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/lang/RustWriterTest.kt @@ -132,6 +132,34 @@ class RustWriterTest { sut.toString().shouldContain("#[foo]\n/// heres an attribute") } + @Test + fun `deprecated attribute without any field`() { + val sut = RustWriter.forModule("lib") + Attribute.Custom.deprecated().render(sut) + sut.toString() shouldContain "#[deprecated]" + } + + @Test + fun `deprecated attribute with a note`() { + val sut = RustWriter.forModule("lib") + Attribute.Custom.deprecated("custom").render(sut) + sut.toString() shouldContain "#[deprecated(note = \"custom\")]" + } + + @Test + fun `deprecated attribute with a since`() { + val sut = RustWriter.forModule("lib") + Attribute.Custom.deprecated(since = "1.2.3").render(sut) + sut.toString() shouldContain "#[deprecated(since = \"1.2.3\")]" + } + + @Test + fun `deprecated attribute with a note and a since`() { + val sut = RustWriter.forModule("lib") + Attribute.Custom.deprecated("custom", "1.2.3").render(sut) + sut.toString() shouldContain "#[deprecated(note = \"custom\", since = \"1.2.3\")]" + } + @Test fun `template writables with upper case names`() { val inner = writable { rust("hello") } From e5f2357d4ffc469aff7675e7e94fea587c3efdaa Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 15:34:16 +0100 Subject: [PATCH 03/17] Support `@deprecated` trait for StructureGenerator --- .../smithy/generators/StructureGenerator.kt | 4 ++ .../generators/StructureGeneratorTest.kt | 70 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/StructureGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/StructureGenerator.kt index cb545391f7..5859a9fc89 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/StructureGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/StructureGenerator.kt @@ -17,6 +17,7 @@ import software.amazon.smithy.rust.codegen.rustlang.RustType import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.asDeref import software.amazon.smithy.rust.codegen.rustlang.asRef +import software.amazon.smithy.rust.codegen.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.isCopy import software.amazon.smithy.rust.codegen.rustlang.isDeref @@ -133,6 +134,7 @@ open class StructureGenerator( // Render field accessor methods forEachMember(accessorMembers) { member, memberName, memberSymbol -> renderMemberDoc(member, memberSymbol) + writer.deprecatedShape(member) val memberType = memberSymbol.rustType() val returnType = when { memberType.isCopy() -> memberType @@ -155,6 +157,7 @@ open class StructureGenerator( open fun renderStructureMember(writer: RustWriter, member: MemberShape, memberName: String, memberSymbol: Symbol) { writer.renderMemberDoc(member, memberSymbol) + writer.deprecatedShape(member) memberSymbol.expectRustMetadata().render(writer) writer.write("$memberName: #T,", symbolProvider.toSymbol(member)) } @@ -163,6 +166,7 @@ open class StructureGenerator( val symbol = symbolProvider.toSymbol(shape) val containerMeta = symbol.expectRustMetadata() writer.documentShape(shape, model) + writer.deprecatedShape(shape) val withoutDebug = containerMeta.derives.copy(derives = containerMeta.derives.derives - RuntimeType.Debug) containerMeta.copy(derives = withoutDebug).render(writer) diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/StructureGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/StructureGeneratorTest.kt index a893e9bba4..835a8d0389 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/StructureGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/StructureGeneratorTest.kt @@ -5,7 +5,9 @@ package software.amazon.smithy.rust.codegen.generators +import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldContainInOrder +import io.kotest.matchers.string.shouldNotContain import org.junit.jupiter.api.Test import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.rustlang.Attribute @@ -35,6 +37,8 @@ class StructureGeneratorTest { foo: String, @documentation("This *is* documentation about the member.") bar: PrimitiveInteger, + // Intentionally deprecated. + @deprecated baz: Integer, ts: Timestamp, inner: Inner, @@ -209,6 +213,72 @@ class StructureGeneratorTest { ) } + @Test + fun `deprecated trait with message and since`() { + val model = """ + namespace test + + @deprecated + structure Foo {} + + @deprecated(message: "Fly, you fools!") + structure Bar {} + + @deprecated(since: "1.2.3") + structure Baz {} + + @deprecated(message: "Fly, you fools!", since: "1.2.3") + structure Qux {} + """.asSmithyModel() + val provider = testSymbolProvider(model) + val writer = RustWriter.root() + writer.withModule("model") { + StructureGenerator(model, provider, this, model.lookup("test#Foo")).render() + StructureGenerator(model, provider, this, model.lookup("test#Bar")).render() + StructureGenerator(model, provider, this, model.lookup("test#Baz")).render() + StructureGenerator(model, provider, this, model.lookup("test#Qux")).render() + } + + // turn on clippy to check the semver-compliant version of `since`. + writer.compileAndTest(clippy = true) + } + @Test + fun `nested deprecated trait`() { + val model = """ + namespace test + + structure Nested { + foo: Foo, + @deprecated + foo2: Foo, + } + + @deprecated + structure Foo { + bar: Bar, + } + + @deprecated + structure Bar {} + """.asSmithyModel() + val provider = testSymbolProvider(model) + val writer = RustWriter.root() + writer.withModule("model") { + StructureGenerator(model, provider, this, model.lookup("test#Nested")).render() + StructureGenerator(model, provider, this, model.lookup("test#Foo")).render() + StructureGenerator(model, provider, this, model.lookup("test#Bar")).render() + } + + val output = writer.compileAndTest() + output shouldNotContain "use of deprecated struct `model::Nested`" + output shouldContain "use of deprecated struct `model::Foo`" + output shouldContain "use of deprecated struct `model::Bar`" + + output shouldNotContain "use of deprecated field `model::Nested::foo`" + output shouldContain "use of deprecated field `model::Nested::foo2`" + output shouldContain "use of deprecated field `model::Foo::bar`" + } + @Test fun `it generates accessor methods`() { val testModel = From 33831a8afa1378b88de69f345d962d3a27448b21 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 15:35:51 +0100 Subject: [PATCH 04/17] Support `@deprecated` trait for UnionGenerator Signed-off-by: Weihang Lo --- .../smithy/generators/UnionGenerator.kt | 3 ++ .../codegen/generators/UnionGeneratorTest.kt | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/UnionGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/UnionGenerator.kt index 73a425a2ed..50b02fe871 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/UnionGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/UnionGenerator.kt @@ -11,6 +11,7 @@ import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.rust.codegen.rustlang.Attribute import software.amazon.smithy.rust.codegen.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.rustlang.docs import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.rust @@ -52,6 +53,7 @@ class UnionGenerator( private fun renderUnion() { writer.documentShape(shape, model) + writer.deprecatedShape(shape) val unionSymbol = symbolProvider.toSymbol(shape) val containerMeta = unionSymbol.expectRustMetadata() @@ -62,6 +64,7 @@ class UnionGenerator( val note = memberSymbol.renamedFrom()?.let { oldName -> "This variant has been renamed from `$oldName`." } documentShape(member, model, note = note) + deprecatedShape(member) memberSymbol.expectRustMetadata().renderAttributes(this) write("${symbolProvider.toMemberName(member)}(#T),", symbolProvider.toSymbol(member)) } diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/UnionGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/UnionGeneratorTest.kt index 95bc84aec8..fc6ba0e736 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/UnionGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/UnionGeneratorTest.kt @@ -6,6 +6,7 @@ package software.amazon.smithy.rust.codegen.generators import io.kotest.matchers.string.shouldContain +import io.kotest.matchers.string.shouldNotContain import org.junit.jupiter.api.Test import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.rust.codegen.rustlang.RustWriter @@ -95,6 +96,40 @@ class UnionGeneratorTest { ) } + @Test + fun `generate deprecated unions`() { + val model = """namespace test + union Nested { + foo: Foo, + @deprecated + foo2: Foo, + } + @deprecated + union Foo { + bar: Bar, + } + + @deprecated + union Bar {} + """.asSmithyModel() + val provider: SymbolProvider = testSymbolProvider(model) + val writer = RustWriter.root() + writer.withModule("model") { + UnionGenerator(model, provider, this, model.lookup("test#Nested")).render() + UnionGenerator(model, provider, this, model.lookup("test#Foo")).render() + UnionGenerator(model, provider, this, model.lookup("test#Bar")).render() + } + + val output = writer.compileAndTest() + output shouldNotContain "use of deprecated enum `model::Nested`" + output shouldContain "use of deprecated enum `model::Foo`" + output shouldContain "use of deprecated enum `model::Bar`" + + output shouldNotContain "use of deprecated tuple variant `model::Nested::Foo`" + output shouldContain "use of deprecated tuple variant `model::Nested::Foo2`" + output shouldContain "use of deprecated tuple variant `model::Foo::Bar`" + } + private fun generateUnion(modelSmithy: String, unionName: String = "MyUnion", unknownVariant: Boolean = true): RustWriter { val model = "namespace test\n$modelSmithy".asSmithyModel() val provider: SymbolProvider = testSymbolProvider(model) From 1d0fe8d98e1bfb028989f47ea70db7ac6d0b4913 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 15:48:11 +0100 Subject: [PATCH 05/17] Support `@deprecated` trait for EnumGenerator --- .../rust/codegen/smithy/generators/EnumGenerator.kt | 10 ++++++++++ .../rust/codegen/generators/EnumGeneratorTest.kt | 11 +++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/EnumGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/EnumGenerator.kt index 2e761ff379..2277395889 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/EnumGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/EnumGenerator.kt @@ -11,6 +11,7 @@ import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.model.traits.EnumDefinition import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.rustlang.docs import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.escape @@ -47,10 +48,17 @@ class EnumMemberModel(private val definition: EnumDefinition, private val symbol ) } + private fun renderDeprecated(writer: RustWriter) { + if (definition.isDeprecated) { + writer.rust("##[deprecated]") + } + } + fun derivedName() = checkNotNull(symbolProvider.toEnumVariantName(definition)).name fun render(writer: RustWriter) { renderDocumentation(writer) + renderDeprecated(writer) writer.write("${derivedName()},") } } @@ -116,6 +124,7 @@ open class EnumGenerator( private fun renderUnnamedEnum() { writer.documentShape(shape, model) + writer.deprecatedShape(shape) meta.render(writer) writer.write("struct $enumName(String);") writer.rustBlock("impl $enumName") { @@ -150,6 +159,7 @@ open class EnumGenerator( shape.getTrait()?.value, renamedWarning.ifBlank { null } ) + writer.deprecatedShape(shape) meta.render(writer) writer.rustBlock("enum $enumName") { diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/EnumGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/EnumGeneratorTest.kt index f914282f61..c044a33cb4 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/EnumGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/EnumGeneratorTest.kt @@ -100,9 +100,11 @@ class EnumGeneratorTest { value: "t2.micro", name: "T2_MICRO", documentation: "T2 instances are Burstable Performance Instances.", + deprecated: true, tags: ["ebsOnly"] }, ]) + @deprecated(since: "1.2.3") string InstanceType """.asSmithyModel() val provider = testSymbolProvider(model) @@ -120,8 +122,12 @@ class EnumGeneratorTest { assert_eq!(InstanceType::from("other").as_str(), "other"); """ ) - - writer.toString() shouldContain "#[non_exhaustive]" + val output = writer.toString() + output shouldContain "#[non_exhaustive]" + // on enum variant `T2Micro` + output shouldContain "#[deprecated]" + // on enum itself + output shouldContain "#[deprecated(since = \"1.2.3\")]" } @Test @@ -165,6 +171,7 @@ class EnumGeneratorTest { { value: "Bar", }]) + @deprecated string FooEnum """.asSmithyModel() val shape = model.lookup("test#FooEnum") From 43cfd8f3ac62b1434ffe14d2d550e3aa3290e8bd Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 17:15:58 +0100 Subject: [PATCH 06/17] Support `@deprecated` trait for TopLevelErrorGenerator --- .../smithy/generators/error/TopLevelErrorGenerator.kt | 2 ++ .../smithy/generators/error/TopLevelErrorGeneratorTest.kt | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/TopLevelErrorGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/TopLevelErrorGenerator.kt index 9757d55f35..a47ea91730 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/TopLevelErrorGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/TopLevelErrorGenerator.kt @@ -15,6 +15,7 @@ import software.amazon.smithy.rust.codegen.rustlang.RustModule import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Visibility import software.amazon.smithy.rust.codegen.rustlang.asType +import software.amazon.smithy.rust.codegen.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.rustBlock @@ -131,6 +132,7 @@ class TopLevelErrorGenerator(private val coreCodegenContext: CoreCodegenContext, rustBlock("enum Error") { allErrors.forEach { error -> documentShape(error, model) + deprecatedShape(error) val sym = symbolProvider.toSymbol(error) rust("${sym.name}(#T),", sym) } diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/TopLevelErrorGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/TopLevelErrorGeneratorTest.kt index e0aa46bbe3..4157f17274 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/TopLevelErrorGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/TopLevelErrorGeneratorTest.kt @@ -31,7 +31,7 @@ internal class TopLevelErrorGeneratorTest { @http(uri: "/", method: "POST") operation SayHello { - errors: [SorryBusy, CanYouRepeatThat] + errors: [SorryBusy, CanYouRepeatThat, MeDeprecated] } @@ -40,6 +40,10 @@ internal class TopLevelErrorGeneratorTest { @error("client") structure CanYouRepeatThat { } + + @error("client") + @deprecated + structure MeDeprecated { } """.asSmithyModel() val (pluginContext, testDir) = generatePluginContext(model) From 399bdda24496982b70bd3a1ae7f33853518a1bf5 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 17:37:44 +0100 Subject: [PATCH 07/17] Support `@deprecated` trait for CombinedErrorGenerator --- .../generators/error/CombinedErrorGenerator.kt | 2 ++ .../smithy/generators/CombinedErrorGeneratorTest.kt | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/CombinedErrorGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/CombinedErrorGenerator.kt index b9994bbfd4..9554ed5249 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/CombinedErrorGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/CombinedErrorGenerator.kt @@ -18,6 +18,7 @@ import software.amazon.smithy.rust.codegen.rustlang.RustModule import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Visibility import software.amazon.smithy.rust.codegen.rustlang.Writable +import software.amazon.smithy.rust.codegen.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.rustBlock @@ -157,6 +158,7 @@ class CombinedErrorGenerator( writer.rustBlock("enum ${errorSymbol.name}Kind") { errors.forEach { errorVariant -> documentShape(errorVariant, model) + deprecatedShape(errorVariant) val errorVariantSymbol = symbolProvider.toSymbol(errorVariant) write("${errorVariantSymbol.name}(#T),", errorVariantSymbol) } diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/CombinedErrorGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/CombinedErrorGeneratorTest.kt index 8b5a54cae0..1681af6385 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/CombinedErrorGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/CombinedErrorGeneratorTest.kt @@ -23,7 +23,7 @@ class CombinedErrorGeneratorTest { namespace error operation Greeting { - errors: [InvalidGreeting, ComplexError, FooException] + errors: [InvalidGreeting, ComplexError, FooException, Deprecated] } @error("client") @@ -40,6 +40,10 @@ class CombinedErrorGeneratorTest { abc: String, other: Integer } + + @error("server") + @deprecated + structure Deprecated { } """.asSmithyModel() private val model = OperationNormalizer.transform(baseModel) private val symbolProvider = testSymbolProvider(model) @@ -48,7 +52,7 @@ class CombinedErrorGeneratorTest { fun `generates combined error enums`() { val project = TestWorkspace.testProject(symbolProvider) project.withModule(RustModule.public("error")) { writer -> - listOf("FooException", "ComplexError", "InvalidGreeting").forEach { + listOf("FooException", "ComplexError", "InvalidGreeting", "Deprecated").forEach { model.lookup("error#$it").renderWithModelBuilder(model, symbolProvider, writer) } val errors = listOf("FooException", "ComplexError", "InvalidGreeting").map { model.lookup("error#$it") } @@ -80,7 +84,10 @@ class CombinedErrorGeneratorTest { // Indicate the original name in the display output. let error = FooError::builder().build(); - assert_eq!(format!("{}", error), "FooError [FooException]") + assert_eq!(format!("{}", error), "FooError [FooException]"); + + let error = Deprecated::builder().build(); + assert_eq!(error.to_string(), "Deprecated"); """ ) From 058290878f3768850a59ce1965acf29adbea77f9 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 17:49:38 +0100 Subject: [PATCH 08/17] Support `@deprecated` trait for ServerCombinedErrorGenerator --- .../ServerCombinedErrorGeneratorTest.kt | 15 ++++++++++++--- .../error/ServerCombinedErrorGenerator.kt | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerCombinedErrorGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerCombinedErrorGeneratorTest.kt index 6c5324cde9..c1037648ff 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerCombinedErrorGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerCombinedErrorGeneratorTest.kt @@ -24,7 +24,7 @@ class ServerCombinedErrorGeneratorTest { namespace error operation Greeting { - errors: [InvalidGreeting, ComplexError, FooException] + errors: [InvalidGreeting, ComplexError, FooException, Deprecated] } @error("client") @@ -42,6 +42,10 @@ class ServerCombinedErrorGeneratorTest { abc: String, other: Integer } + + @error("server") + @deprecated + structure Deprecated { } """.asSmithyModel() private val model = OperationNormalizer.transform(baseModel) private val symbolProvider = serverTestSymbolProvider(model) @@ -50,7 +54,7 @@ class ServerCombinedErrorGeneratorTest { fun `generates combined error enums`() { val project = TestWorkspace.testProject(symbolProvider) project.withModule(RustModule.public("error")) { writer -> - listOf("FooException", "ComplexError", "InvalidGreeting").forEach { + listOf("FooException", "ComplexError", "InvalidGreeting", "Deprecated").forEach { model.lookup("error#$it").renderWithModelBuilder(model, symbolProvider, writer, CodegenTarget.SERVER) } val errors = listOf("FooException", "ComplexError", "InvalidGreeting").map { model.lookup("error#$it") } @@ -76,7 +80,10 @@ class ServerCombinedErrorGeneratorTest { // Indicate the original name in the display output. let error = FooException::builder().build(); - assert_eq!(format!("{}", error), "FooException") + assert_eq!(format!("{}", error), "FooException"); + + let error = Deprecated::builder().build(); + assert_eq!(error.to_string(), "Deprecated"); """ ) @@ -88,6 +95,8 @@ class ServerCombinedErrorGeneratorTest { """ ) + println("file:///${project.baseDir}/src/lib.rs") + println("file:///${project.baseDir}/src/error.rs") project.compileAndTest() } } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/ServerCombinedErrorGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/ServerCombinedErrorGenerator.kt index e1da616d56..5a75193020 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/ServerCombinedErrorGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/error/ServerCombinedErrorGenerator.kt @@ -13,6 +13,7 @@ import software.amazon.smithy.rust.codegen.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Visibility import software.amazon.smithy.rust.codegen.rustlang.Writable +import software.amazon.smithy.rust.codegen.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.rustBlock @@ -53,6 +54,7 @@ open class ServerCombinedErrorGenerator( writer.rustBlock("enum ${errorSymbol.name}") { errors.forEach { errorVariant -> documentShape(errorVariant, model) + deprecatedShape(errorVariant) val errorVariantSymbol = symbolProvider.toSymbol(errorVariant) write("${errorVariantSymbol.name}(#T),", errorVariantSymbol) } From 77ab717efae892081b12952815e823aae6418dbc Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 17:54:29 +0100 Subject: [PATCH 09/17] Support `@deprecated` trait for FluentClient --- .../rust/codegen/smithy/generators/client/FluentClientCore.kt | 4 ++++ .../codegen/smithy/generators/client/FluentClientDecorator.kt | 2 ++ 2 files changed, 6 insertions(+) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/client/FluentClientCore.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/client/FluentClientCore.kt index 5f8be068d2..383ace2a8a 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/client/FluentClientCore.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/client/FluentClientCore.kt @@ -10,6 +10,7 @@ import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.rust.codegen.rustlang.RustType import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.asArgument +import software.amazon.smithy.rust.codegen.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.rustlang.docs import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.rust @@ -26,6 +27,7 @@ class FluentClientCore(private val model: Model) { val input = coreType.member.asArgument("input") documentShape(member, model) + deprecatedShape(member) rustBlock("pub fn $memberName(mut self, ${input.argument}) -> Self") { write("self.inner = self.inner.$memberName(${input.value});") write("self") @@ -42,6 +44,7 @@ class FluentClientCore(private val model: Model) { val v = coreType.member.asArgument("v") documentShape(member, model) + deprecatedShape(member) rustBlock("pub fn $memberName(mut self, ${k.argument}, ${v.argument}) -> Self") { write("self.inner = self.inner.$memberName(${k.value}, ${v.value});") write("self") @@ -58,6 +61,7 @@ class FluentClientCore(private val model: Model) { val functionInput = coreType.asArgument("input") documentShape(member, model) + deprecatedShape(member) rustBlock("pub fn $memberName(mut self, ${functionInput.argument}) -> Self") { write("self.inner = self.inner.$memberName(${functionInput.value});") write("self") diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/client/FluentClientDecorator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/client/FluentClientDecorator.kt index 730a568dd1..c6f4263df1 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/client/FluentClientDecorator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/client/FluentClientDecorator.kt @@ -25,6 +25,7 @@ import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asArgumentType import software.amazon.smithy.rust.codegen.rustlang.asOptional import software.amazon.smithy.rust.codegen.rustlang.asType +import software.amazon.smithy.rust.codegen.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.rustlang.docLink import software.amazon.smithy.rust.codegen.rustlang.docs import software.amazon.smithy.rust.codegen.rustlang.documentShape @@ -466,6 +467,7 @@ class FluentClientGenerator( ) documentShape(operation, model, autoSuppressMissingDocs = false) + deprecatedShape(operation) baseDerives.copy(derives = derives).render(this) rustTemplate( """ From c051519be1e04486b7a7a8050d841871b7781622 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 25 Jul 2022 17:54:46 +0100 Subject: [PATCH 10/17] Support `@deprecated` trait for BuilderGenerator --- .../rust/codegen/smithy/generators/BuilderGenerator.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt index 1e1f3daf60..9044888938 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGenerator.kt @@ -15,6 +15,7 @@ import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.asArgument import software.amazon.smithy.rust.codegen.rustlang.asOptional import software.amazon.smithy.rust.codegen.rustlang.conditionalBlock +import software.amazon.smithy.rust.codegen.rustlang.deprecatedShape import software.amazon.smithy.rust.codegen.rustlang.docs import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.render @@ -124,6 +125,7 @@ class BuilderGenerator( val input = coreType.asArgument("input") writer.documentShape(member, model) + writer.deprecatedShape(member) writer.rustBlock("pub fn $memberName(mut self, ${input.argument}) -> Self") { write("self.$memberName = Some(${input.value});") write("self") @@ -146,6 +148,7 @@ class BuilderGenerator( val inputType = outerType.asOptional() writer.documentShape(member, model) + writer.deprecatedShape(member) writer.rustBlock("pub fn ${member.setterName()}(mut self, input: ${inputType.render(true)}) -> Self") { rust("self.$memberName = input; self") } @@ -195,6 +198,7 @@ class BuilderGenerator( docs("To override the contents of this collection use [`${member.setterName()}`](Self::${member.setterName()}).") rust("///") documentShape(member, model, autoSuppressMissingDocs = false) + deprecatedShape(member) val input = coreType.member.asArgument("input") rustBlock("pub fn $memberName(mut self, ${input.argument}) -> Self") { @@ -215,6 +219,7 @@ class BuilderGenerator( docs("To override the contents of this collection use [`${member.setterName()}`](Self::${member.setterName()}).") rust("///") documentShape(member, model, autoSuppressMissingDocs = false) + deprecatedShape(member) val k = coreType.key.asArgument("k") val v = coreType.member.asArgument("v") From fe8749c9c80c6f6cbe0b20a856ce4959dcba12f3 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 26 Jul 2022 11:06:16 +0100 Subject: [PATCH 11/17] Cleanup leftover in test --- .../smithy/generators/ServerCombinedErrorGeneratorTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerCombinedErrorGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerCombinedErrorGeneratorTest.kt index c1037648ff..471c7a0d53 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerCombinedErrorGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerCombinedErrorGeneratorTest.kt @@ -95,8 +95,6 @@ class ServerCombinedErrorGeneratorTest { """ ) - println("file:///${project.baseDir}/src/lib.rs") - println("file:///${project.baseDir}/src/error.rs") project.compileAndTest() } } From 1899b555d34717888299ed98fe033e3e3bc71bc0 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 26 Jul 2022 11:09:09 +0100 Subject: [PATCH 12/17] Use `dq()` helper method instead of escaping by hands Signed-off-by: Weihang Lo --- .../amazon/smithy/rust/codegen/rustlang/RustTypes.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt index ad4ac83f72..6d78633a6b 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt @@ -388,11 +388,11 @@ sealed class Attribute { if (note.isBlank().and(since.isBlank())) { // No-op. Rustc would emit a default message. } else if (note.isNotBlank().and(since.isBlank())) { - builder.append("(note = \"${note}\")") + builder.append("(note = ${note.dq()})") } else if (note.isBlank().and(since.isNotBlank())) { - builder.append("(since = \"${since}\")") + builder.append("(since = ${since.dq()})") } else { - builder.append("(note = \"${note}\", since = \"${since}\")") + builder.append("(note = ${note.dq()}, since = ${since.dq()})") } return Custom(builder.toString()) } From 774ee1503a5d35d4e93b0390b240b9540c6a7421 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 26 Jul 2022 12:00:26 +0100 Subject: [PATCH 13/17] Leverage Kotlin null safety well Signed-off-by: Weihang Lo --- .../amazon/smithy/rust/codegen/rustlang/RustTypes.kt | 12 ++++++++---- .../smithy/rust/codegen/rustlang/RustWriter.kt | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt index 6d78633a6b..8a487bef50 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt @@ -382,14 +382,18 @@ sealed class Attribute { * [`#[deprecated]`](https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute) * attribute. */ - fun deprecated(note: String = "", since: String = ""): Custom { + fun deprecated(note: String? = null, since: String? = null): Custom { val builder = StringBuilder() builder.append("deprecated") - if (note.isBlank().and(since.isBlank())) { + + val note = note ?: "" + val since = since ?: "" + + if (note.isBlank() && since.isBlank()) { // No-op. Rustc would emit a default message. - } else if (note.isNotBlank().and(since.isBlank())) { + } else if (note.isNotBlank() && since.isBlank()) { builder.append("(note = ${note.dq()})") - } else if (note.isBlank().and(since.isNotBlank())) { + } else if (note.isBlank() && since.isNotBlank()) { builder.append("(since = ${since.dq()})") } else { builder.append("(note = ${note.dq()}, since = ${since.dq()})") diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt index f6953bdce8..af91146ba6 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustWriter.kt @@ -277,8 +277,8 @@ fun > T.docs(text: String, vararg args: Any, newlinePr fun RustWriter.deprecatedShape(shape: Shape): RustWriter { val deprecatedTrait = shape.getTrait() ?: return this - val note = deprecatedTrait.message.orElse("") - val since = deprecatedTrait.since.orElse("") + val note = deprecatedTrait.message.orNull() + val since = deprecatedTrait.since.orNull() Attribute.Custom.deprecated(note, since).render(this) From 6ab77ed0be41bab946129a0dbf90d7d7261dc85f Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 26 Jul 2022 12:10:26 +0100 Subject: [PATCH 14/17] Allow `deprecated` rustc lint rule Signed-off-by: Weihang Lo --- .../customizations/AllowLintsGenerator.kt | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/AllowLintsGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/AllowLintsGenerator.kt index ce9cf6c44e..c59df4d605 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/AllowLintsGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/AllowLintsGenerator.kt @@ -10,7 +10,12 @@ import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.smithy.generators.LibRsSection -val ClippyAllowLints = listOf( +val AllowedRustcLints = listOf( + // Deprecated items should be safe to compile, so don't block the compilation. + "deprecated", +) + +val AllowedClippyLints = listOf( // Sometimes operations are named the same as our module e.g. output leading to `output::output`. "module_inception", @@ -36,26 +41,26 @@ val ClippyAllowLints = listOf( "type_complexity", ) -val AllowDocsLints = listOf( +val AllowedRustdocLints = listOf( // Rust >=1.53.0 requires links to be wrapped in ``. This is extremely hard to enforce for // docs that come from the modeled documentation, so we need to disable this lint "bare_urls" ) class AllowLintsGenerator( - private val bareLints: List = listOf(), - private val clippyLints: List = ClippyAllowLints, - private val docsLints: List = AllowDocsLints + private val rustcLints: List = AllowedRustcLints, + private val clippyLints: List = AllowedClippyLints, + private val rustdocLints: List = AllowedRustdocLints, ) : LibRsCustomization() { override fun section(section: LibRsSection) = when (section) { is LibRsSection.Attributes -> writable { - bareLints.forEach { + rustcLints.forEach { Attribute.Custom("allow($it)", container = true).render(this) } clippyLints.forEach { Attribute.Custom("allow(clippy::$it)", container = true).render(this) } - docsLints.forEach { + rustdocLints.forEach { Attribute.Custom("allow(rustdoc::$it)", container = true).render(this) } // add a newline at the end From f8e6644789d5ba5427a2dd78f9f13cda8f460643 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 26 Jul 2022 15:02:07 +0100 Subject: [PATCH 15/17] Allow deprecated in unit tests Signed-off-by: Weihang Lo --- .../rust/codegen/generators/EnumGeneratorTest.kt | 4 ++++ .../codegen/generators/StructureGeneratorTest.kt | 14 ++++---------- .../rust/codegen/generators/UnionGeneratorTest.kt | 12 +++--------- .../smithy/generators/BuilderGeneratorTest.kt | 3 +++ 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/EnumGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/EnumGeneratorTest.kt index c044a33cb4..519d891441 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/EnumGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/EnumGeneratorTest.kt @@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.smithy.generators.EnumGenerator import software.amazon.smithy.rust.codegen.smithy.generators.EnumMemberModel import software.amazon.smithy.rust.codegen.testutil.asSmithyModel @@ -109,6 +110,7 @@ class EnumGeneratorTest { """.asSmithyModel() val provider = testSymbolProvider(model) val writer = RustWriter.forModule("model") + writer.rust("##![allow(deprecated)]") val shape = model.lookup("test#InstanceType") val generator = EnumGenerator(model, provider, writer, shape, shape.expectTrait()) generator.render() @@ -177,6 +179,7 @@ class EnumGeneratorTest { val shape = model.lookup("test#FooEnum") val trait = shape.expectTrait() val writer = RustWriter.forModule("model") + writer.rust("##![allow(deprecated)]") val generator = EnumGenerator(model, testSymbolProvider(model), writer, shape, trait) generator.render() writer.compileAndTest( @@ -216,6 +219,7 @@ class EnumGeneratorTest { val trait = shape.expectTrait() val provider = testSymbolProvider(model) val writer = RustWriter.forModule("model") + writer.rust("##![allow(deprecated)]") val generator = EnumGenerator(model, provider, writer, shape, trait) generator.render() writer.compileAndTest( diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/StructureGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/StructureGeneratorTest.kt index 835a8d0389..7f57ee1393 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/StructureGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/StructureGeneratorTest.kt @@ -5,9 +5,7 @@ package software.amazon.smithy.rust.codegen.generators -import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldContainInOrder -import io.kotest.matchers.string.shouldNotContain import org.junit.jupiter.api.Test import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.rustlang.Attribute @@ -103,6 +101,7 @@ class StructureGeneratorTest { fun `generate structures with public fields`() { val provider = testSymbolProvider(model) val writer = RustWriter.root() + writer.rust("##![allow(deprecated)]") writer.withModule("model") { val innerGenerator = StructureGenerator(model, provider, this, inner) innerGenerator.render() @@ -232,6 +231,7 @@ class StructureGeneratorTest { """.asSmithyModel() val provider = testSymbolProvider(model) val writer = RustWriter.root() + writer.rust("##![allow(deprecated)]") writer.withModule("model") { StructureGenerator(model, provider, this, model.lookup("test#Foo")).render() StructureGenerator(model, provider, this, model.lookup("test#Bar")).render() @@ -263,20 +263,14 @@ class StructureGeneratorTest { """.asSmithyModel() val provider = testSymbolProvider(model) val writer = RustWriter.root() + writer.rust("##![allow(deprecated)]") writer.withModule("model") { StructureGenerator(model, provider, this, model.lookup("test#Nested")).render() StructureGenerator(model, provider, this, model.lookup("test#Foo")).render() StructureGenerator(model, provider, this, model.lookup("test#Bar")).render() } - val output = writer.compileAndTest() - output shouldNotContain "use of deprecated struct `model::Nested`" - output shouldContain "use of deprecated struct `model::Foo`" - output shouldContain "use of deprecated struct `model::Bar`" - - output shouldNotContain "use of deprecated field `model::Nested::foo`" - output shouldContain "use of deprecated field `model::Nested::foo2`" - output shouldContain "use of deprecated field `model::Foo::bar`" + writer.compileAndTest() } @Test diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/UnionGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/UnionGeneratorTest.kt index fc6ba0e736..5be114e07c 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/UnionGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/generators/UnionGeneratorTest.kt @@ -6,10 +6,10 @@ package software.amazon.smithy.rust.codegen.generators import io.kotest.matchers.string.shouldContain -import io.kotest.matchers.string.shouldNotContain import org.junit.jupiter.api.Test import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.rust.codegen.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.smithy.generators.UnionGenerator import software.amazon.smithy.rust.codegen.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.testutil.compileAndTest @@ -114,20 +114,14 @@ class UnionGeneratorTest { """.asSmithyModel() val provider: SymbolProvider = testSymbolProvider(model) val writer = RustWriter.root() + writer.rust("##![allow(deprecated)]") writer.withModule("model") { UnionGenerator(model, provider, this, model.lookup("test#Nested")).render() UnionGenerator(model, provider, this, model.lookup("test#Foo")).render() UnionGenerator(model, provider, this, model.lookup("test#Bar")).render() } - val output = writer.compileAndTest() - output shouldNotContain "use of deprecated enum `model::Nested`" - output shouldContain "use of deprecated enum `model::Foo`" - output shouldContain "use of deprecated enum `model::Bar`" - - output shouldNotContain "use of deprecated tuple variant `model::Nested::Foo`" - output shouldContain "use of deprecated tuple variant `model::Nested::Foo2`" - output shouldContain "use of deprecated tuple variant `model::Foo::Bar`" + writer.compileAndTest() } private fun generateUnion(modelSmithy: String, unionName: String = "MyUnion", unknownVariant: Boolean = true): RustWriter { diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGeneratorTest.kt index 5b0580afdc..8e09065ba2 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/BuilderGeneratorTest.kt @@ -12,6 +12,7 @@ import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.traits.EnumDefinition import software.amazon.smithy.rust.codegen.generators.StructureGeneratorTest import software.amazon.smithy.rust.codegen.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.smithy.Default import software.amazon.smithy.rust.codegen.smithy.MaybeRenamed import software.amazon.smithy.rust.codegen.smithy.RustSymbolProvider @@ -29,6 +30,7 @@ internal class BuilderGeneratorTest { fun `generate builders`() { val provider = testSymbolProvider(model) val writer = RustWriter.forModule("model") + writer.rust("##![allow(deprecated)]") val innerGenerator = StructureGenerator(model, provider, writer, inner) val generator = StructureGenerator(model, provider, writer, struct) val builderGenerator = BuilderGenerator(model, provider, struct) @@ -69,6 +71,7 @@ internal class BuilderGeneratorTest { } } val writer = RustWriter.forModule("model") + writer.rust("##![allow(deprecated)]") val innerGenerator = StructureGenerator( StructureGeneratorTest.model, provider, writer, StructureGeneratorTest.inner From b8161d4c82ffa9d29705254f83d50121bb03bd50 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 26 Jul 2022 17:49:11 +0100 Subject: [PATCH 16/17] Leverage kotlin null safety check again Signed-off-by: Weihang Lo --- .../smithy/rust/codegen/rustlang/RustTypes.kt | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt index 8a487bef50..93b9e5ec1c 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustTypes.kt @@ -386,17 +386,14 @@ sealed class Attribute { val builder = StringBuilder() builder.append("deprecated") - val note = note ?: "" - val since = since ?: "" - - if (note.isBlank() && since.isBlank()) { - // No-op. Rustc would emit a default message. - } else if (note.isNotBlank() && since.isBlank()) { + if (note != null && since != null) { + builder.append("(note = ${note.dq()}, since = ${since.dq()})") + } else if (note != null) { builder.append("(note = ${note.dq()})") - } else if (note.isBlank() && since.isNotBlank()) { + } else if (since != null) { builder.append("(since = ${since.dq()})") } else { - builder.append("(note = ${note.dq()}, since = ${since.dq()})") + // No-op. Rustc would emit a default message. } return Custom(builder.toString()) } From 3006aac26622e57fb960e41c76246c953c39da71 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 26 Jul 2022 15:23:01 +0100 Subject: [PATCH 17/17] changelog: Support @deprecated trait Signed-off-by: Weihang Lo --- CHANGELOG.next.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 34e3627cff..362921a0d1 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -213,3 +213,9 @@ Add explicit cast during JSON deserialization in case of custom Symbol providers references = ["smithy-rs#1520"] meta = { "breaking" = false, "tada" = false, "bug" = false } author = "crisidev" + +[[smithy-rs]] +message = "Support @deprecated trait for aggregate shapes" +references = ["smithy-rs#1570"] +meta = { "breaking" = true, "tada" = true, "bug" = false } +author = "weihanglo"