From 9c7307af4ca7f7fed725635f9f899931654c0d6a Mon Sep 17 00:00:00 2001 From: Zelda Hessler Date: Thu, 5 Jan 2023 11:49:39 -0600 Subject: [PATCH] Refactor attribute macro codegen (#2126) * refactor: rust Attribute codegen * update: post-refactor usage of Attribute in codegen add: more attribute tests update: don't render attributes missing required args * fix: Python Server codegen broken by Attribute refactor * fix: Python Server codegen broken by extra `:W` * remove: TODOs * update: codegen code to use new attribute syntax * fix: RustMetadata creation in ConstrainedBlobGenerator --- .../generators/EndpointParamsGenerator.kt | 11 +- .../generators/EndpointResolverGenerator.kt | 5 +- .../endpoint/rulesgen/TemplateGenerator.kt | 2 +- .../client/FluentClientGenerator.kt | 7 +- .../http/RequestBindingGenerator.kt | 2 +- .../protocol/ClientProtocolGenerator.kt | 3 +- .../protocol/MakeOperationGenerator.kt | 13 +- .../protocol/ProtocolTestGenerator.kt | 8 +- .../protocols/HttpBoundProtocolGenerator.kt | 8 +- .../HttpVersionListGeneratorTest.kt | 8 +- .../client/endpoint/EndpointsDecoratorTest.kt | 4 +- .../generators/EndpointTraitBindingsTest.kt | 4 +- .../generators/PaginatorGeneratorTest.kt | 2 +- .../rust/codegen/core/rustlang/RustType.kt | 259 +++++++++--------- .../rust/codegen/core/rustlang/RustWriter.kt | 13 +- .../rust/codegen/core/rustlang/Writable.kt | 2 + .../rust/codegen/core/smithy/RuntimeType.kt | 1 + .../core/smithy/SymbolMetadataProvider.kt | 37 ++- .../customizations/AllowLintsCustomization.kt | 8 +- .../smithy/generators/BuilderGenerator.kt | 10 +- .../core/smithy/generators/EnumGenerator.kt | 2 +- .../smithy/generators/StructureGenerator.kt | 2 +- .../core/smithy/generators/UnionGenerator.kt | 4 +- .../error/OperationErrorGenerator.kt | 2 +- .../smithy/rust/codegen/core/testutil/Rust.kt | 4 +- .../rust/codegen/core/testutil/TestHelpers.kt | 3 - .../codegen/core/rustlang/RustTypeTest.kt | 65 +++++ .../codegen/core/rustlang/RustWriterTest.kt | 21 +- .../generators/StructureGeneratorTest.kt | 7 +- .../error/ServiceErrorGeneratorTest.kt | 3 +- .../generators/PythonServerEnumGenerator.kt | 6 +- .../PythonServerStructureGenerator.kt | 30 +- ...bCrateConstraintViolationSymbolProvider.kt | 3 +- .../generators/ConstrainedBlobGenerator.kt | 2 +- .../ConstrainedCollectionGenerator.kt | 2 +- .../generators/ConstrainedMapGenerator.kt | 2 +- .../generators/ConstrainedNumberGenerator.kt | 16 +- .../generators/ConstrainedStringGenerator.kt | 2 +- .../ServerBuilderConstraintViolations.kt | 3 +- .../generators/ServerBuilderGenerator.kt | 12 +- ...rGeneratorWithoutPublicConstrainedTypes.kt | 7 +- .../smithy/generators/ServerEnumGenerator.kt | 5 +- .../ServerOperationErrorGenerator.kt | 3 +- .../ServerOperationRegistryGenerator.kt | 3 +- .../generators/ServerServiceGenerator.kt | 3 +- .../generators/UnconstrainedUnionGenerator.kt | 3 +- .../protocol/ServerProtocolTestGenerator.kt | 10 +- .../ServerHttpBoundProtocolGenerator.kt | 6 +- 48 files changed, 378 insertions(+), 260 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt index c1fc9c852..1e5059830 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt @@ -12,6 +12,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.endpoint.memberName import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rustName import software.amazon.smithy.rust.codegen.client.smithy.endpoint.symbol import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustType @@ -27,10 +28,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.Clone -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.Debug -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.Default -import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.PartialEq import software.amazon.smithy.rust.codegen.core.smithy.isOptional import software.amazon.smithy.rust.codegen.core.smithy.makeOptional import software.amazon.smithy.rust.codegen.core.smithy.mapRustType @@ -175,7 +172,7 @@ internal class EndpointParamsGenerator(private val parameters: Parameters) { // Ensure that fields can be added in the future Attribute.NonExhaustive.render(writer) // Automatically implement standard Rust functionality - Attribute.Derives(setOf(Debug, PartialEq, Clone)).render(writer) + Attribute(derive(RuntimeType.Debug, RuntimeType.PartialEq, RuntimeType.Clone)).render(writer) // Generate the struct block: /* pub struct Params { @@ -238,7 +235,7 @@ internal class EndpointParamsGenerator(private val parameters: Parameters) { private fun generateEndpointParamsBuilder(rustWriter: RustWriter) { rustWriter.docs("Builder for [`Params`]") - Attribute.Derives(setOf(Debug, Default, PartialEq, Clone)).render(rustWriter) + Attribute(derive(RuntimeType.Debug, RuntimeType.Default, RuntimeType.PartialEq, RuntimeType.Clone)).render(rustWriter) rustWriter.rustBlock("pub struct ParamsBuilder") { parameters.toList().forEach { parameter -> val name = parameter.memberName() @@ -255,7 +252,7 @@ internal class EndpointParamsGenerator(private val parameters: Parameters) { "ParamsError" to paramsError(), ) { val params = writable { - Attribute.Custom("allow(clippy::unnecessary_lazy_evaluations)").render(this) + Attribute.AllowClippyUnnecessaryLazyEvaluations.render(this) rustBlockTemplate("#{Params}", "Params" to paramsStruct()) { parameters.toList().forEach { parameter -> rust("${parameter.memberName()}: self.${parameter.memberName()}") diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt index aa9eebca7..385ab1324 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt @@ -23,6 +23,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rulesgen.Expre import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rulesgen.Ownership import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rustName import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.allow 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.comment @@ -202,7 +203,7 @@ internal class EndpointResolverGenerator(stdlib: List, ru fnsUsed: List, ): RuntimeType { return RuntimeType.forInlineFun("resolve_endpoint", EndpointsImpl) { - allowLintsForResolver.map { Attribute.Custom("allow($it)") }.map { it.render(this) } + Attribute(allow(allowLintsForResolver)).render(this) rustTemplate( """ pub(super) fn resolve_endpoint($ParamsName: &#{Params}, $DiagnosticCollector: &mut #{DiagnosticCollector}, #{additional_args}) -> #{endpoint}::Result { @@ -233,7 +234,7 @@ internal class EndpointResolverGenerator(stdlib: List, ru } if (!isExhaustive(rules.last())) { // it's hard to figure out if these are always needed or not - Attribute.Custom("allow(unreachable_code)").render(this) + Attribute.AllowUnreachableCode.render(this) rustTemplate( """return Err(#{EndpointError}::message(format!("No rules matched these parameters. This is a bug. {:?}", $ParamsName)));""", *codegenScope, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGenerator.kt index 4d4bae43a..933813139 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGenerator.kt @@ -56,7 +56,7 @@ class TemplateGenerator( override fun visitDynamicElement(expr: Expression) = writable { // we don't need to own the argument to push_str - Attribute.Custom("allow(clippy::needless_borrow)").render(this) + Attribute.AllowClippyNeedlessBorrow.render(this) rust("out.push_str(&#W);", exprGenerator(expr, Ownership.Borrowed)) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 08f77fe6b..a1e1c7395 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -15,6 +15,8 @@ import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.generators.PaginatorGenerator import software.amazon.smithy.rust.codegen.client.smithy.generators.isPaginated +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.core.rustlang.RustType @@ -230,7 +232,8 @@ class FluentClientGenerator( val operationSymbol = symbolProvider.toSymbol(operation) val input = operation.inputShape(model) val baseDerives = symbolProvider.toSymbol(input).expectRustMetadata().derives - val derives = baseDerives.derives.intersect(setOf(RuntimeType.Clone)) + RuntimeType.Debug + // Filter out any derive that isn't Clone. Then add a Debug derive + val derives = baseDerives.filter { it == RuntimeType.Clone } + RuntimeType.Debug rust( """ /// Fluent builder constructing a request to `${operationSymbol.name}`. @@ -240,7 +243,7 @@ class FluentClientGenerator( documentShape(operation, model, autoSuppressMissingDocs = false) deprecatedShape(operation) - baseDerives.copy(derives = derives).render(this) + Attribute(derive(derives.toSet())).render(this) rustTemplate( """ pub struct ${operationSymbol.name}#{generics:W} { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt index 9d625c51a..9ec7173d0 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt @@ -88,7 +88,7 @@ class RequestBindingGenerator( uriBase(implBlockWriter) val addHeadersFn = httpBindingGenerator.generateAddHeadersFn(operationShape) val hasQuery = uriQuery(implBlockWriter) - Attribute.Custom("allow(clippy::unnecessary_wraps)").render(implBlockWriter) + Attribute.AllowClippyUnnecessaryWraps.render(implBlockWriter) implBlockWriter.rustBlockTemplate( """ fn update_http_builder( diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ClientProtocolGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ClientProtocolGenerator.kt index a2530e758..b8d6a652e 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ClientProtocolGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ClientProtocolGenerator.kt @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators.protocol import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientGenerator import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.docLink import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -77,7 +78,7 @@ open class ClientProtocolGenerator( /// See [`crate::client::fluent_builders::$operationName`] for more details about the operation. """, ) - Attribute.Derives(setOf(RuntimeType.Clone, RuntimeType.Default, RuntimeType.Debug)).render(operationWriter) + Attribute(derive(RuntimeType.Clone, RuntimeType.Default, RuntimeType.Debug)).render(operationWriter) operationWriter.rustBlock("pub struct $operationName") { write("_private: ()") } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt index 4d4fc4e5f..541af1ceb 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt @@ -81,11 +81,12 @@ open class MakeOperationGenerator( val fnType = if (public) "pub async fn" else "async fn" implBlockWriter.docs("Consumes the builder and constructs an Operation<#D>", outputSymbol) - Attribute.AllowUnusedMut.render(implBlockWriter) // For codegen simplicity - Attribute.Custom("allow(clippy::let_and_return)") - .render(implBlockWriter) // For codegen simplicity, allow `let x = ...; x` - Attribute.Custom("allow(clippy::needless_borrow)") - .render(implBlockWriter) // Allows builders that don’t consume the input borrow + // For codegen simplicity + Attribute.AllowUnusedMut.render(implBlockWriter) + // For codegen simplicity, allow `let x = ...; x` + Attribute.AllowClippyLetAndReturn.render(implBlockWriter) + // Allows builders that don’t consume the input borrow + Attribute.AllowClippyNeedlessBorrow.render(implBlockWriter) implBlockWriter.rustBlockTemplate( "$fnType $functionName($self, _config: &#{config}::Config) -> $returnType", *codegenScope, @@ -99,7 +100,7 @@ open class MakeOperationGenerator( // When the payload is a `ByteStream`, `into_inner()` already returns an `SdkBody`, so we mute this // Clippy warning to make the codegen a little simpler in that case. - Attribute.Custom("allow(clippy::useless_conversion)").render(this) + Attribute.AllowClippyUselessConversion.render(this) withBlockTemplate("let body = #{SdkBody}::from(", ");", *codegenScope) { bodyGenerator.generatePayload(this, "self", shape) val streamingMember = shape.inputShape(model).findStreamingMember(model) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt index def222956..98d229558 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt @@ -22,6 +22,7 @@ import software.amazon.smithy.protocoltests.traits.HttpResponseTestsTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.generators.clientInstantiator import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.allow import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter @@ -36,7 +37,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.generators.error.errorSymbol import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolSupport -import software.amazon.smithy.rust.codegen.core.testutil.TokioTest import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.findMemberWithTrait import software.amazon.smithy.rust.codegen.core.util.getTrait @@ -96,8 +96,8 @@ class ProtocolTestGenerator( val moduleMeta = RustMetadata( visibility = Visibility.PRIVATE, additionalAttributes = listOf( - Attribute.Cfg("test"), - Attribute.Custom("allow(unreachable_code, unused_variables)"), + Attribute.CfgTest, + Attribute(allow("unreachable_code", "unused_variables")), ), ) writer.withInlineModule(RustModule.LeafModule(testModuleName, moduleMeta, inline = true)) { @@ -142,7 +142,7 @@ class ProtocolTestGenerator( } testModuleWriter.write("Test ID: ${testCase.id}") testModuleWriter.newlinePrefix = "" - TokioTest.render(testModuleWriter) + Attribute.TokioTest.render(testModuleWriter) val action = when (testCase) { is HttpResponseTestCase -> Action.Response is HttpRequestTestCase -> Action.Request diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt index 9a9884f86..0592d91cd 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt @@ -169,7 +169,7 @@ class HttpBoundProtocolTraitImplGenerator( val outputSymbol = symbolProvider.toSymbol(outputShape) val errorSymbol = operationShape.errorSymbol(symbolProvider) return RuntimeType.forInlineFun(fnName, operationDeserModule) { - Attribute.Custom("allow(clippy::unnecessary_wraps)").render(this) + Attribute.AllowClippyUnnecessaryWraps.render(this) rustBlockTemplate( "pub fn $fnName(response: &#{http}::Response<#{Bytes}>) -> std::result::Result<#{O}, #{E}>", *codegenScope, @@ -243,7 +243,7 @@ class HttpBoundProtocolTraitImplGenerator( val outputSymbol = symbolProvider.toSymbol(outputShape) val errorSymbol = operationShape.errorSymbol(symbolProvider) return RuntimeType.forInlineFun(fnName, operationDeserModule) { - Attribute.Custom("allow(clippy::unnecessary_wraps)").render(this) + Attribute.AllowClippyUnnecessaryWraps.render(this) rustBlockTemplate( "pub fn $fnName(op_response: &mut #{operation}::Response) -> std::result::Result<#{O}, #{E}>", *codegenScope, @@ -251,7 +251,7 @@ class HttpBoundProtocolTraitImplGenerator( "E" to errorSymbol, ) { // Not all implementations will use the property bag, but some will - Attribute.Custom("allow(unused_variables)").render(this) + Attribute.AllowUnusedVariables.render(this) rust("let (response, properties) = op_response.parts_mut();") withBlock("Ok({", "})") { renderShapeParser( @@ -272,7 +272,7 @@ class HttpBoundProtocolTraitImplGenerator( val outputSymbol = symbolProvider.toSymbol(outputShape) val errorSymbol = operationShape.errorSymbol(symbolProvider) return RuntimeType.forInlineFun(fnName, operationDeserModule) { - Attribute.Custom("allow(clippy::unnecessary_wraps)").render(this) + Attribute.AllowClippyUnnecessaryWraps.render(this) rustBlockTemplate( "pub fn $fnName(response: &#{http}::Response<#{Bytes}>) -> std::result::Result<#{O}, #{E}>", *codegenScope, diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/customizations/HttpVersionListGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/customizations/HttpVersionListGeneratorTest.kt index 495e34870..0c57ba622 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/customizations/HttpVersionListGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/customizations/HttpVersionListGeneratorTest.kt @@ -12,13 +12,13 @@ import software.amazon.smithy.rust.codegen.client.smithy.generators.config.Confi import software.amazon.smithy.rust.codegen.client.smithy.generators.config.EventStreamSigningConfig import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rust 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.RuntimeType -import software.amazon.smithy.rust.codegen.core.testutil.TokioTest import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.integrationTest @@ -56,7 +56,7 @@ internal class HttpVersionListGeneratorTest { clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val moduleName = clientCodegenContext.moduleUseName() rustCrate.integrationTest("http_version_list") { - TokioTest.render(this) + Attribute.TokioTest.render(this) rust( """ async fn test_http_version_list_defaults() { @@ -107,7 +107,7 @@ internal class HttpVersionListGeneratorTest { clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val moduleName = clientCodegenContext.moduleUseName() rustCrate.integrationTest("validate_http") { - TokioTest.render(this) + Attribute.TokioTest.render(this) rust( """ async fn test_http_version_list_defaults() { @@ -175,7 +175,7 @@ internal class HttpVersionListGeneratorTest { ) { clientCodegenContext, rustCrate -> val moduleName = clientCodegenContext.moduleUseName() rustCrate.integrationTest("validate_eventstream_http") { - TokioTest.render(this) + Attribute.TokioTest.render(this) rust( """ async fn test_http_version_list_defaults() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/endpoint/EndpointsDecoratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/endpoint/EndpointsDecoratorTest.kt index f7e5e414e..9e47cf661 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/endpoint/EndpointsDecoratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/endpoint/EndpointsDecoratorTest.kt @@ -9,8 +9,8 @@ import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.Test import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.testutil.TokioTest import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.integrationTest import software.amazon.smithy.rust.codegen.core.testutil.runWithWarnings @@ -120,7 +120,7 @@ class EndpointsDecoratorTest { ) { clientCodegenContext, rustCrate -> rustCrate.integrationTest("endpoint_params_test") { val moduleName = clientCodegenContext.moduleUseName() - TokioTest.render(this) + Attribute.TokioTest.render(this) rust( """ async fn endpoint_params_are_set() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingsTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingsTest.kt index f682446d0..2a9787f69 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingsTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingsTest.kt @@ -11,6 +11,7 @@ import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.traits.EndpointTrait import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.client.testutil.testSymbolProvider +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.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock @@ -19,7 +20,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.implBlock import software.amazon.smithy.rust.codegen.core.smithy.generators.operationBuildError import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace -import software.amazon.smithy.rust.codegen.core.testutil.TokioTest import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest import software.amazon.smithy.rust.codegen.core.testutil.integrationTest @@ -140,7 +140,7 @@ internal class EndpointTraitBindingsTest { clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val moduleName = clientCodegenContext.moduleUseName() rustCrate.integrationTest("test_endpoint_prefix") { - TokioTest.render(this) + Attribute.TokioTest.render(this) rust( """ async fn test_endpoint_prefix() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt index 9108415f0..f45f56a1c 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt @@ -71,7 +71,7 @@ internal class PaginatorGeneratorTest { fun `generate paginators that compile`() { clientIntegrationTest(model) { clientCodegenContext, rustCrate -> rustCrate.integrationTest("paginators_generated") { - Attribute.Custom("allow(unused_imports)").render(this) + Attribute.AllowUnusedImports.render(this) rust("use ${clientCodegenContext.moduleUseName()}::paginator::PaginatedListPaginator;") } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index 489b3f08c..c39af9da0 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -5,8 +5,8 @@ package software.amazon.smithy.rust.codegen.core.rustlang +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType -import software.amazon.smithy.rust.codegen.core.util.PANIC import software.amazon.smithy.rust.codegen.core.util.dq /** @@ -199,11 +199,10 @@ fun RustType.asArgumentType(fullyQualified: Boolean = true): String { } /** Format this Rust type so that it may be used as an argument type in a function definition */ -fun RustType.asArgumentValue(name: String) = - when (this) { - is RustType.String, is RustType.Box -> "$name.into()" - else -> name - } +fun RustType.asArgumentValue(name: String) = when (this) { + is RustType.String, is RustType.Box -> "$name.into()" + else -> name +} /** * For a given name, generate an `Argument` data class containing pre-formatted strings for using this type when @@ -241,6 +240,7 @@ fun RustType.render(fullyQualified: Boolean = true): String { "&${this.lifetime?.let { "'$it" } ?: ""} ${this.member.render(fullyQualified)}" } } + is RustType.Option -> "${this.name}<${this.member.render(fullyQualified)}>" is RustType.Box -> "${this.name}<${this.member.render(fullyQualified)}>" is RustType.Dyn -> "${this.name} ${this.member.render(fullyQualified)}" @@ -299,6 +299,7 @@ fun RustType.asDeref(): RustType = when (this) { } else { this } + is RustType.Box -> RustType.Reference(null, member) is RustType.String -> RustType.Opaque("str") is RustType.Vec -> RustType.Slice(member) @@ -325,47 +326,43 @@ fun RustType.isCopy(): Boolean = when (this) { } enum class Visibility { - PRIVATE, - PUBCRATE, - PUBLIC; + PRIVATE, PUBCRATE, PUBLIC; companion object { - fun publicIf(condition: Boolean, ifNot: Visibility): Visibility = - if (condition) { - PUBLIC - } else { - ifNot - } + fun publicIf(condition: Boolean, ifNot: Visibility): Visibility = if (condition) { + PUBLIC + } else { + ifNot + } } - fun toRustQualifier(): String = - when (this) { - PRIVATE -> "" - PUBCRATE -> "pub(crate)" - PUBLIC -> "pub" - } + fun toRustQualifier(): String = when (this) { + PRIVATE -> "" + PUBCRATE -> "pub(crate)" + PUBLIC -> "pub" + } } /** * Meta information about a Rust construction (field, struct, or enum). */ data class RustMetadata( - val derives: Attribute.Derives = Attribute.Derives.Empty, + val derives: Set = setOf(), val additionalAttributes: List = listOf(), val visibility: Visibility = Visibility.PRIVATE, ) { - fun withDerives(vararg newDerive: RuntimeType): RustMetadata = - this.copy(derives = derives.copy(derives = derives.derives + newDerive)) + fun withDerives(vararg newDerives: RuntimeType): RustMetadata = + this.copy(derives = derives + newDerives) fun withoutDerives(vararg withoutDerives: RuntimeType) = - this.copy(derives = derives.copy(derives = derives.derives - withoutDerives.toSet())) - - private fun attributes(): List = additionalAttributes + derives + this.copy(derives = derives - withoutDerives.toSet()) fun renderAttributes(writer: RustWriter): RustMetadata { - attributes().forEach { + additionalAttributes.forEach { it.render(writer) } + Attribute(derive(derives)).render(writer) + return this } @@ -385,145 +382,163 @@ data class RustMetadata( renderVisibility(writer) } + /** + * If `true`, the Rust symbol that this metadata references derives a `Debug` implementation. + * If `false`, then it doesn't. + */ + fun hasDebugDerive(): Boolean { + return derives.contains(RuntimeType.Debug) + } + companion object { val TestModule = RustMetadata( visibility = Visibility.PRIVATE, additionalAttributes = listOf( - Attribute.Cfg("test"), + Attribute.CfgTest, ), ) } } +data class Argument(val argument: String, val value: String, val type: String) + +/** + * AttributeKind differentiates between the two kinds of attribute macros: inner and outer. + * See the variant docs for more info, and the official Rust [Attribute Macro](https://doc.rust-lang.org/reference/attributes.html) + * for even MORE info. + */ +enum class AttributeKind { + /** + * Inner attributes, written with a bang (!) after the hash (#), apply to the item that the attribute is declared within. + */ + Inner, + + /** + * Outer attributes, written without the bang after the hash, apply to the thing that follows the attribute. + */ + Outer +} + /** * [Attributes](https://doc.rust-lang.org/reference/attributes.html) are general free form metadata * that are interpreted by the compiler. * * For example: * ```rust - * * #[derive(Clone, PartialEq, Serialize)] // <-- this is an attribute * #[serde(serialize_with = "abc")] // <-- this is an attribute * struct Abc { * a: i64 * } + * ``` */ -sealed class Attribute { - abstract fun render(writer: RustWriter) +class Attribute(val inner: Writable) { + constructor(str: String) : this(writable(str)) + constructor(runtimeType: RuntimeType) : this(runtimeType.writable) + + fun render(writer: RustWriter, attributeKind: AttributeKind = AttributeKind.Outer) { + // Writing "#[]" with nothing inside it is meaningless + if (inner.isNotEmpty()) { + when (attributeKind) { + AttributeKind.Inner -> writer.rust("##![#W]", inner) + AttributeKind.Outer -> writer.rust("##[#W]", inner) + } + } + } companion object { - val AllowDeadCode = Custom("allow(dead_code)") - val AllowDeprecated = Custom("allow(deprecated)") - val AllowUnused = Custom("allow(unused)") - val AllowUnusedMut = Custom("allow(unused_mut)") - val DocHidden = Custom("doc(hidden)") - val DocInline = Custom("doc(inline)") + val AllowClippyBoxedLocal = Attribute(allow("clippy::boxed_local")) + val AllowClippyLetAndReturn = Attribute(allow("clippy::let_and_return")) + val AllowClippyNeedlessBorrow = Attribute(allow("clippy::needless_borrow")) + val AllowClippyNewWithoutDefault = Attribute(allow("clippy::new_without_default")) + val AllowClippyUnnecessaryWraps = Attribute(allow("clippy::unnecessary_wraps")) + val AllowClippyUselessConversion = Attribute(allow("clippy::useless_conversion")) + val AllowClippyUnnecessaryLazyEvaluations = Attribute(allow("clippy::unnecessary_lazy_evaluations")) + val AllowDeadCode = Attribute(allow("dead_code")) + val AllowDeprecated = Attribute(allow("deprecated")) + val AllowIrrefutableLetPatterns = Attribute(allow("irrefutable_let_patterns")) + val AllowUnreachableCode = Attribute(allow("unreachable_code")) + val AllowUnused = Attribute(allow("unused")) + val AllowUnusedImports = Attribute(allow("unused_imports")) + val AllowUnusedMut = Attribute(allow("unused_mut")) + val AllowUnusedVariables = Attribute(allow("unused_variables")) + val CfgTest = Attribute(cfg("test")) + val DenyMissingDocs = Attribute(deny("missing_docs")) + val DocHidden = Attribute(doc("hidden")) + val DocInline = Attribute(doc("inline")) + val Test = Attribute("test") + val TokioTest = Attribute(RuntimeType.Tokio.resolve("test").writable) /** * [non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute) * indicates that more fields may be added in the future */ - val NonExhaustive = Custom("non_exhaustive") - } + val NonExhaustive = Attribute("non_exhaustive") - data class Deprecated(val since: String?, val note: String?) : Attribute() { - override fun render(writer: RustWriter) { - writer.raw("#[deprecated") - if (since != null || note != null) { - writer.raw("(") - if (since != null) { - writer.raw("""since = "$since"""") - - if (note != null) { - writer.raw(", ") - } - } + /** + * Mark the following type as deprecated. If you know why and in what version something was deprecated, then + * using [deprecated] is preferred. + */ + val Deprecated = Attribute("deprecated") - if (note != null) { - writer.raw("""note = "$note"""") - } - writer.raw(")") + private fun macroWithArgs(name: String, vararg args: RustWriter.() -> Unit): Writable = { + // Macros that require args can't be empty + if (args.isNotEmpty()) { + rustInline("$name(#W)", args.toList().join(", ")) } - writer.raw("]") } - } - data class Derives(val derives: Set) : Attribute() { - override fun render(writer: RustWriter) { - if (derives.isEmpty()) { - return + private fun macroWithArgs(name: String, vararg args: String): Writable = { + // Macros that require args can't be empty + if (args.isNotEmpty()) { + rustInline("$name(${args.joinToString(", ")})") } - writer.raw("#[derive(") - derives.sortedBy { it.path }.forEach { derive -> - writer.writeInline("#T, ", derive) - } - writer.write(")]") } - companion object { - val Empty = Derives(setOf()) - } - } + fun all(vararg attrMacros: Writable): Writable = macroWithArgs("all", *attrMacros) + + fun allow(lints: Collection): Writable = macroWithArgs("allow", *lints.toTypedArray()) + fun allow(vararg lints: String): Writable = macroWithArgs("allow", *lints) + fun deny(vararg lints: String): Writable = macroWithArgs("deny", *lints) + fun any(vararg attrMacros: Writable): Writable = macroWithArgs("any", *attrMacros) + fun cfg(vararg attrMacros: Writable): Writable = macroWithArgs("cfg", *attrMacros) + fun cfg(vararg attrMacros: String): Writable = macroWithArgs("cfg", *attrMacros) + fun doc(vararg attrMacros: Writable): Writable = macroWithArgs("doc", *attrMacros) + fun doc(str: String): Writable = macroWithArgs("doc", writable(str)) + fun not(vararg attrMacros: Writable): Writable = macroWithArgs("not", *attrMacros) + + fun deprecated(since: String? = null, note: String? = null): Writable { + val optionalFields = mutableListOf() + if (!note.isNullOrEmpty()) { + optionalFields.add(pair("note" to note.dq())) + } - /** - * A custom Attribute - * - * [annotation] represents the body of the attribute, e.g. `cfg(foo)` in `#[cfg(foo)]` - * If [container] is set, this attribute refers to its container rather than its successor. This generates `#![cfg(foo)]` - * - * Finally, any symbols listed will be imported when this attribute is rendered. This enables using attributes like - * `#[serde(Serialize)]` where `Serialize` is actually a symbol that must be imported. - */ - data class Custom( - val annotation: String, - val symbols: List = listOf(), - val container: Boolean = false, - ) : Attribute() { - override fun render(writer: RustWriter) { - val bang = if (container) "!" else "" - writer.raw("#$bang[$annotation]") - symbols.forEach { - try { - writer.addDependency(it.dependency) - } catch (ex: Exception) { - PANIC("failed to add dependency for RuntimeType $it") - } + if (!since.isNullOrEmpty()) { + optionalFields.add(pair("since" to since.dq())) } - } - companion object { - /** - * Renders a - * [`#[deprecated]`](https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute) - * attribute. - */ - fun deprecated(note: String? = null, since: String? = null): Custom { - val builder = StringBuilder() - builder.append("deprecated") - - if (note != null && since != null) { - builder.append("(note = ${note.dq()}, since = ${since.dq()})") - } else if (note != null) { - builder.append("(note = ${note.dq()})") - } else if (since != null) { - builder.append("(since = ${since.dq()})") - } else { - // No-op. Rustc would emit a default message. + return { + rustInline("deprecated") + if (optionalFields.isNotEmpty()) { + rustInline("(#W)", optionalFields.join(", ")) } - return Custom(builder.toString()) } } - } - data class Cfg(val cond: String) : Attribute() { - override fun render(writer: RustWriter) { - writer.raw("#[cfg($cond)]") + fun derive(vararg runtimeTypes: RuntimeType): Writable = { + // Empty derives are meaningless + if (runtimeTypes.isNotEmpty()) { + // Sorted derives look nicer than unsorted, and it makes test output easier to predict + val writables = runtimeTypes.sortedBy { it.path }.map { it.writable }.join(", ") + rustInline("derive(#W)", writables) + } } - companion object { - fun feature(feature: String) = Cfg("feature = ${feature.dq()}") + fun derive(runtimeTypes: Collection): Writable = derive(*runtimeTypes.toTypedArray()) + + fun pair(pair: Pair): Writable = { + val (key, value) = pair + rustInline("$key = $value") } } } - -data class Argument(val argument: String, val value: String, val type: String) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt index 9f3ed975e..59f9c5c40 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt @@ -22,6 +22,7 @@ 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.core.rustlang.Attribute.Companion.deprecated import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.isOptional import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.ValueExpression @@ -147,6 +148,16 @@ fun > T.rust( this.write(contents.trim(), *args) } +/** + * Convenience wrapper that tells Intellij that the contents of this block are Rust + */ +fun RustWriter.rustInline( + @Language("Rust", prefix = "macro_rules! foo { () => {{ ", suffix = "}}}") contents: String, + vararg args: Any, +) { + this.writeInline(contents, *args) +} + /* rewrite #{foo} to #{foo:T} (the smithy template format) */ private fun transformTemplate(template: String, scope: Array>, trim: Boolean = true): String { check(scope.distinctBy { it.first.lowercase() }.size == scope.size) { "Duplicate cased keys not supported" } @@ -324,7 +335,7 @@ fun RustWriter.deprecatedShape(shape: Shape): RustWriter { val note = deprecatedTrait.message.orNull() val since = deprecatedTrait.since.orNull() - Attribute.Custom.deprecated(note, since).render(this) + Attribute(deprecated(since, note)).render(this) return this } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/Writable.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/Writable.kt index df3b66e6b..b17eb3b03 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/Writable.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/Writable.kt @@ -25,6 +25,8 @@ fun Writable.isEmpty(): Boolean { return writer.toString() == RustWriter.root().toString() } +fun Writable.isNotEmpty(): Boolean = !this.isEmpty() + operator fun Writable.plus(other: Writable): Writable { val first = this return writable { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt index 7d29b3c06..1ad33d9e9 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt @@ -229,6 +229,7 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) val PercentEncoding = CargoDependency.PercentEncoding.toType() val PrettyAssertions = CargoDependency.PrettyAssertions.toType() val Regex = CargoDependency.Regex.toType() + val Tokio = CargoDependency.Tokio.toType() val TokioStream = CargoDependency.TokioStream.toType() val Tower = CargoDependency.Tower.toType() val Tracing = CargoDependency.Tracing.toType() 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 ac2bd6398..4f6f095e9 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 @@ -72,7 +72,7 @@ abstract class SymbolMetadataProvider(private val base: RustSymbolProvider) : Wr /** * The base metadata supports a list of attributes that are used by generators to decorate code. - * By default we apply #[non_exhaustive] only to client structures since model changes should + * By default, we apply ```#[non_exhaustive]``` only to client structures since model changes should * be considered as breaking only when generating server code. */ class BaseSymbolMetadataProvider( @@ -88,15 +88,15 @@ class BaseSymbolMetadataProvider( // shape; any sensitive descendant should still be printed as redacted. shape.members().any { it.getMemberTrait(model, SensitiveTrait::class.java).isPresent } - val setOfDerives = if (isSensitive) { - defaultDerives.toSet() - RuntimeType.Debug + val derives = if (isSensitive) { + defaultDerives - RuntimeType.Debug } else { - defaultDerives.toSet() + defaultDerives } return RustMetadata( - Attribute.Derives(setOfDerives), - additionalAttributes = additionalAttributes, - visibility = Visibility.PUBLIC, + derives, + additionalAttributes, + Visibility.PUBLIC, ) } @@ -137,31 +137,28 @@ class BaseSymbolMetadataProvider( override fun enumMeta(stringShape: StringShape): RustMetadata { return containerDefault(stringShape).withDerives( - RuntimeType.std.resolve("hash::Hash"), - ).withDerives( - // enums can be eq because they can only contain ints and strings - RuntimeType.std.resolve("cmp::Eq"), - // enums can be Ord because they can only contain ints and strings - RuntimeType.std.resolve("cmp::PartialOrd"), - RuntimeType.std.resolve("cmp::Ord"), + RuntimeType.Hash, + // enums can be Eq because they can only contain ints and strings + RuntimeType.Eq, + // enums can be PartialOrd/Ord because they can only contain ints and strings + RuntimeType.PartialOrd, + RuntimeType.Ord, ) } companion object { private val defaultDerives by lazy { - with(RuntimeType) { - listOf(Debug, PartialEq, Clone) - } + setOf(RuntimeType.Debug, RuntimeType.PartialEq, RuntimeType.Clone) } } } -private const val MetaKey = "meta" +private const val META_KEY = "meta" fun Symbol.Builder.meta(rustMetadata: RustMetadata?): Symbol.Builder { - return this.putProperty(MetaKey, rustMetadata) + return this.putProperty(META_KEY, rustMetadata) } -fun Symbol.expectRustMetadata(): RustMetadata = this.getProperty(MetaKey, RustMetadata::class.java).orElseThrow { +fun Symbol.expectRustMetadata(): RustMetadata = this.getProperty(META_KEY, RustMetadata::class.java).orElseThrow { CodegenException( "Expected $this to have metadata attached but it did not. ", ) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt index 0fc88f7a1..a06ff50a2 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt @@ -6,6 +6,8 @@ package software.amazon.smithy.rust.codegen.core.smithy.customizations import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.allow +import software.amazon.smithy.rust.codegen.core.rustlang.AttributeKind import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection @@ -68,13 +70,13 @@ class AllowLintsCustomization( override fun section(section: LibRsSection) = when (section) { is LibRsSection.Attributes -> writable { rustcLints.forEach { - Attribute.Custom("allow($it)", container = true).render(this) + Attribute(allow(it)).render(this, AttributeKind.Inner) } clippyLints.forEach { - Attribute.Custom("allow(clippy::$it)", container = true).render(this) + Attribute(allow("clippy::$it")).render(this, AttributeKind.Inner) } rustdocLints.forEach { - Attribute.Custom("allow(rustdoc::$it)", container = true).render(this) + Attribute(allow("rustdoc::$it")).render(this, AttributeKind.Inner) } // add a newline at the end this.write("") diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index b612ca19f..69aca4563 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -10,6 +10,8 @@ import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.core.rustlang.RustType @@ -113,7 +115,9 @@ class BuilderGenerator( private val structureSymbol = symbolProvider.toSymbol(shape) private val builderSymbol = shape.builderSymbol(symbolProvider) private val baseDerives = structureSymbol.expectRustMetadata().derives - private val builderDerives = baseDerives.derives.intersect(setOf(RuntimeType.Debug, RuntimeType.PartialEq, RuntimeType.Clone)) + RuntimeType.Default + + // Filter out any derive that isn't Debug, PartialEq, or Clone. Then add a Default derive + private val builderDerives = baseDerives.filter { it == RuntimeType.Debug || it == RuntimeType.PartialEq || it == RuntimeType.Clone } + RuntimeType.Default private val builderName = "Builder" fun render(writer: RustWriter) { @@ -122,7 +126,7 @@ class BuilderGenerator( writer.withInlineModule(shape.builderSymbol(symbolProvider).module()) { // Matching derives to the main structure + `Default` since we are a builder and everything is optional. renderBuilder(this) - if (!builderDerives.contains(RuntimeType.Debug)) { + if (!structureSymbol.expectRustMetadata().hasDebugDerive()) { renderDebugImpl(this) } } @@ -203,7 +207,7 @@ class BuilderGenerator( private fun renderBuilder(writer: RustWriter) { writer.docs("A builder for #D.", structureSymbol) - baseDerives.copy(derives = builderDerives).render(writer) + Attribute(derive(builderDerives)).render(writer) writer.rustBlock("pub struct $builderName") { for (member in members) { val memberName = symbolProvider.toMemberName(member) 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 b5c4d1ace..ec8f3505e 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 @@ -57,7 +57,7 @@ class EnumMemberModel(private val definition: EnumDefinition, private val symbol private fun renderDeprecated(writer: RustWriter) { if (definition.isDeprecated) { - Attribute.Custom.deprecated().render(writer) + Attribute.Deprecated.render(writer) } } 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 5f4e9ffb9..7e88d3d1f 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 @@ -153,7 +153,7 @@ open class StructureGenerator( } renderStructureImpl() - if (!containerMeta.derives.derives.contains(RuntimeType.Debug)) { + if (!containerMeta.hasDebugDerive()) { renderDebugImpl() } } 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 15615f606..69cd25f2e 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 @@ -67,7 +67,7 @@ class UnionGenerator( renderUnion(unionSymbol) renderImplBlock(unionSymbol) - if (!unionSymbol.expectRustMetadata().derives.derives.contains(RuntimeType.Debug)) { + if (!containerMeta.hasDebugDerive()) { if (shape.hasTrait()) { renderFullyRedactedDebugImpl() } else { @@ -110,7 +110,7 @@ class UnionGenerator( val variantName = symbolProvider.toMemberName(member) if (sortedMembers.size == 1) { - Attribute.Custom("allow(irrefutable_let_patterns)").render(this) + Attribute.AllowIrrefutableLetPatterns.render(this) } writer.renderAsVariant(member, variantName, funcNamePart, unionSymbol, memberSymbol) rust("/// Returns true if this is a [`$variantName`](#T::$variantName).", unionSymbol) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/OperationErrorGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/OperationErrorGenerator.kt index 7e5bf08b7..69f1ad863 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/OperationErrorGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/OperationErrorGenerator.kt @@ -77,7 +77,7 @@ class OperationErrorGenerator( operationSymbol: Symbol, ) { val meta = RustMetadata( - derives = Attribute.Derives(setOf(RuntimeType.Debug)), + derives = setOf(RuntimeType.Debug), additionalAttributes = listOf(Attribute.NonExhaustive), visibility = Visibility.PUBLIC, ) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index b2d9ad065..a8567c4db 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -213,7 +213,7 @@ fun RustWriter.unitTest( fun RustWriter.unitTest( name: String, vararg args: Any, - attribute: Attribute = Attribute.Custom("test"), + attribute: Attribute = Attribute.Test, async: Boolean = false, block: Writable, ): RustWriter { @@ -225,7 +225,7 @@ fun RustWriter.unitTest( } fun RustWriter.tokioTest(name: String, vararg args: Any, block: Writable) { - unitTest(name, attribute = TokioTest, async = true, block = block, args = args) + unitTest(name, attribute = Attribute.TokioTest, async = true, block = block, args = args) } /** 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 40f001432..6c9310a30 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 @@ -11,7 +11,6 @@ import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute -import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency 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.smithy.BaseSymbolMetadataProvider @@ -111,5 +110,3 @@ fun StructureShape.renderWithModelBuilder( modelBuilder.renderConvenienceMethod(this) } } - -val TokioTest = Attribute.Custom("tokio::test", listOf(CargoDependency.Tokio.toType())) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustTypeTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustTypeTest.kt index 0191ee5c9..41e0c1006 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustTypeTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustTypeTest.kt @@ -8,6 +8,15 @@ package software.amazon.smithy.rust.codegen.core.rustlang import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.Test +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.all +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.any +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.cfg +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.deny +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.doc +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.not +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.util.dq internal class RustTypesTest { private fun forInputExpectOutput(t: Writable, expectedOutput: String) { @@ -140,4 +149,60 @@ internal class RustTypesTest { type.render(false) shouldBe "Box>>" type.render(true) shouldBe "std::boxed::Box>>" } + + @Test + fun `attribute macros from strings render properly`() { + val attributeMacro = Attribute( + Attribute.cfg( + Attribute.all( + Attribute.pair("feature" to "unstable".dq()), + Attribute.any( + Attribute.pair("feature" to "serialize".dq()), + Attribute.pair("feature" to "deserialize".dq()), + ), + ), + ), + ) + forInputExpectOutput(writable { attributeMacro.render(this) }, "#[cfg(all(feature = \"unstable\", any(feature = \"serialize\", feature = \"deserialize\")))]\n") + } + + @Test + fun `attribute macros render writers properly`() { + val attributeMacro = Attribute( + cfg( + all( + // Normally we'd use the `pair` fn to define these but this is a test + writable { rustInline("""feature = "unstable"""") }, + writable { rustInline("""feature = "serialize"""") }, + writable { rustInline("""feature = "deserialize"""") }, + ), + ), + ) + forInputExpectOutput(writable { attributeMacro.render(this) }, "#[cfg(all(feature = \"unstable\", feature = \"serialize\", feature = \"deserialize\"))]\n") + } + + @Test + fun `attribute macros render nothing when empty`() { + // All of these attributes require arguments. If none are supplied, then they shouldn't render at all + val attributeMacro = Attribute(cfg(all(any(doc(not(deny())))))) + forInputExpectOutput(writable { attributeMacro.render(this) }, "") + } + + @Test + fun `derive attribute macros render properly`() { + val attributeMacro = Attribute( + derive( + RuntimeType.Clone, + RuntimeType.Debug, + RuntimeType.StdError, + ), + ) + forInputExpectOutput(writable { attributeMacro.render(this) }, "#[derive(std::clone::Clone, std::error::Error, std::fmt::Debug)]\n") + } + + @Test + fun `derive attribute macros don't render when empty`() { + val attributeMacro = Attribute(derive()) + forInputExpectOutput(writable { attributeMacro.render(this) }, "") + } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt index a78ccecd6..86d48a260 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt @@ -14,6 +14,7 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.SetShape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.deprecated import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.compileAndRun @@ -107,44 +108,44 @@ class RustWriterTest { @Test fun `attributes with comments when using rust`() { val sut = RustWriter.forModule("lib") - Attribute.Custom("foo").render(sut) - sut.rust("// heres an attribute") - sut.toString().shouldContain("#[foo]// heres an attribute") + Attribute("foo").render(sut) + sut.rust(" // here's an attribute") + sut.toString().shouldContain("#[foo]\n// here's an attribute") } @Test fun `attributes with comments when using docs`() { val sut = RustWriter.forModule("lib") - Attribute.Custom("foo").render(sut) - sut.docs("heres an attribute") - sut.toString().shouldContain("#[foo]\n/// heres an attribute") + Attribute("foo").render(sut) + sut.docs("here's an attribute") + sut.toString().shouldContain("#[foo]\n/// here's an attribute") } @Test fun `deprecated attribute without any field`() { val sut = RustWriter.forModule("lib") - Attribute.Custom.deprecated().render(sut) + Attribute.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) + Attribute(deprecated(note = "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) + Attribute(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) + Attribute(deprecated("1.2.3", "custom")).render(sut) sut.toString() shouldContain "#[deprecated(note = \"custom\", since = \"1.2.3\")]" } 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 870abefdc..37d73291e 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 @@ -13,7 +13,6 @@ 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.RustWriter -import software.amazon.smithy.rust.codegen.core.rustlang.raw 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.smithy.ModelsModule @@ -115,7 +114,7 @@ class StructureGeneratorTest { val project = TestWorkspace.testProject() val provider = testSymbolProvider(model) - project.lib { rust("##![allow(deprecated)]") } + project.lib { Attribute.AllowDeprecated.render(this) } project.withModule(ModelsModule) { val innerGenerator = StructureGenerator(model, provider, this, inner) innerGenerator.render() @@ -127,7 +126,7 @@ class StructureGeneratorTest { // By putting the test in another module, it can't access the struct // fields if they are private project.unitTest { - raw("#[test]") + Attribute.Test.render(this) rustBlock("fn test_public_fields()") { write( """ @@ -238,7 +237,7 @@ class StructureGeneratorTest { val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.lib { - Attribute.Custom("deny(missing_docs)").render(this) + Attribute.DenyMissingDocs.render(this) } project.withModule(ModelsModule) { StructureGenerator(model, provider, this, model.lookup("com.test#Inner")).render() diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ServiceErrorGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ServiceErrorGeneratorTest.kt index 355527432..746927d13 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ServiceErrorGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ServiceErrorGeneratorTest.kt @@ -10,6 +10,7 @@ import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.AttributeKind import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget @@ -80,7 +81,7 @@ internal class ServiceErrorGeneratorTest { ) rustCrate.lib { - Attribute.AllowDeprecated.copy(container = true).render(this) + Attribute.AllowDeprecated.render(this, AttributeKind.Inner) } rustCrate.withModule(RustModule.Error) { for (operation in model.operationShapes) { diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt index c4542c102..90bdcc6e4 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt @@ -29,7 +29,7 @@ class PythonServerEnumGenerator( shape: StringShape, ) : ServerEnumGenerator(codegenContext, writer, shape) { - private val pyo3Symbols = listOf(PythonServerCargoDependency.PyO3.toType()) + private val pyO3 = PythonServerCargoDependency.PyO3.toType() override fun render() { renderPyClass() @@ -38,11 +38,11 @@ class PythonServerEnumGenerator( } private fun renderPyClass() { - Attribute.Custom("pyo3::pyclass", symbols = pyo3Symbols).render(writer) + Attribute(pyO3.resolve("pyclass")).render(writer) } private fun renderPyO3Methods() { - Attribute.Custom("pyo3::pymethods", symbols = pyo3Symbols).render(writer) + Attribute(pyO3.resolve("pymethods")).render(writer) writer.rustTemplate( """ impl $enumName { diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerStructureGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerStructureGenerator.kt index 468c1c531..436d956fa 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerStructureGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerStructureGenerator.kt @@ -15,6 +15,7 @@ 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.render import software.amazon.smithy.rust.codegen.core.rustlang.rust +import software.amazon.smithy.rust.codegen.core.rustlang.rustInlineTemplate 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.RustSymbolProvider @@ -35,26 +36,41 @@ class PythonServerStructureGenerator( private val shape: StructureShape, ) : StructureGenerator(model, symbolProvider, writer, shape) { - private val pyo3Symbols = listOf(PythonServerCargoDependency.PyO3.toType()) + private val pyO3 = PythonServerCargoDependency.PyO3.toType() override fun renderStructure() { if (shape.hasTrait()) { - Attribute.Custom("pyo3::pyclass(extends = pyo3::exceptions::PyException)", symbols = pyo3Symbols).render(writer) + Attribute( + writable { + rustInlineTemplate( + "#{pyclass}(extends = #{PyException})", + "pyclass" to pyO3.resolve("pyclass"), + "PyException" to pyO3.resolve("exceptions::PyException"), + ) + }, + ).render(writer) } else { - Attribute.Custom("pyo3::pyclass", symbols = pyo3Symbols).render(writer) + Attribute(pyO3.resolve("pyclass")).render(writer) } super.renderStructure() renderPyO3Methods() } - override fun renderStructureMember(writer: RustWriter, member: MemberShape, memberName: String, memberSymbol: Symbol) { - Attribute.Custom("pyo3(get, set)", symbols = pyo3Symbols).render(writer) + override fun renderStructureMember( + writer: RustWriter, + member: MemberShape, + memberName: String, + memberSymbol: Symbol, + ) { + writer.addDependency(PythonServerCargoDependency.PyO3) + // Above, we manually add dependency since we can't use a `RuntimeType` below + Attribute("pyo3(get, set)").render(writer) super.renderStructureMember(writer, member, memberName, memberSymbol) } private fun renderPyO3Methods() { - Attribute.Custom("allow(clippy::new_without_default)").render(writer) - Attribute.Custom("pyo3::pymethods", symbols = pyo3Symbols).render(writer) + Attribute.AllowClippyNewWithoutDefault.render(writer) + Attribute(pyO3.resolve("pymethods")).render(writer) writer.rustTemplate( """ impl $name { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstraintViolationSymbolProvider.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstraintViolationSymbolProvider.kt index 4e7b5ab6c..c01112ed8 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstraintViolationSymbolProvider.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstraintViolationSymbolProvider.kt @@ -8,7 +8,6 @@ package software.amazon.smithy.rust.codegen.server.smithy import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.StructureShape -import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustType import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.locatedIn @@ -31,7 +30,7 @@ class PubCrateConstraintViolationSymbolProvider( return baseSymbol } val baseRustType = baseSymbol.rustType() - val oldModule = baseSymbol.module() as RustModule.LeafModule + val oldModule = baseSymbol.module() val newModule = oldModule.copy(name = oldModule.name + "_internal") return baseSymbol.toBuilder() .rustType(RustType.Opaque(baseRustType.name, newModule.fullyQualifiedPath())) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGenerator.kt index e3ef8ec2b..acaee289a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGenerator.kt @@ -61,7 +61,7 @@ class ConstrainedBlobGenerator( Visibility.PUBCRATE } val constrainedTypeMetadata = RustMetadata( - Attribute.Derives(setOf(RuntimeType.Debug, RuntimeType.Clone, RuntimeType.PartialEq)), + setOf(RuntimeType.Debug, RuntimeType.Clone, RuntimeType.PartialEq), visibility = constrainedTypeVisibility, ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGenerator.kt index 2e472607d..9d8aeb1e4 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGenerator.kt @@ -74,7 +74,7 @@ class ConstrainedCollectionGenerator( val constraintViolation = constraintViolationSymbolProvider.toSymbol(shape) val constrainedTypeVisibility = Visibility.publicIf(publicConstrainedTypes, Visibility.PUBCRATE) val constrainedTypeMetadata = RustMetadata( - Attribute.Derives(setOf(RuntimeType.Debug, RuntimeType.Clone, RuntimeType.PartialEq)), + setOf(RuntimeType.Debug, RuntimeType.Clone, RuntimeType.PartialEq), visibility = constrainedTypeVisibility, ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGenerator.kt index 48cd34205..a97bf3da7 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGenerator.kt @@ -63,7 +63,7 @@ class ConstrainedMapGenerator( val constrainedTypeVisibility = Visibility.publicIf(publicConstrainedTypes, Visibility.PUBCRATE) val constrainedTypeMetadata = RustMetadata( - Attribute.Derives(setOf(RuntimeType.Debug, RuntimeType.Clone, RuntimeType.PartialEq)), + setOf(RuntimeType.Debug, RuntimeType.Clone, RuntimeType.PartialEq), visibility = constrainedTypeVisibility, ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGenerator.kt index ce3ee6aaa..6e85ac5c8 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGenerator.kt @@ -82,15 +82,15 @@ class ConstrainedNumberGenerator( Visibility.PUBCRATE } val constrainedTypeMetadata = RustMetadata( - Attribute.Derives( - setOf( - RuntimeType.Debug, - RuntimeType.Clone, - RuntimeType.PartialEq, - RuntimeType.Eq, - RuntimeType.Hash, - ), + + setOf( + RuntimeType.Debug, + RuntimeType.Clone, + RuntimeType.PartialEq, + RuntimeType.Eq, + RuntimeType.Hash, ), + visibility = constrainedTypeVisibility, ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt index 88bebc505..9ee0c6c28 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt @@ -74,7 +74,7 @@ class ConstrainedStringGenerator( Visibility.PUBCRATE } val constrainedTypeMetadata = RustMetadata( - Attribute.Derives(setOf(RuntimeType.Debug, RuntimeType.Clone, RuntimeType.PartialEq, RuntimeType.Eq, RuntimeType.Hash)), + setOf(RuntimeType.Debug, RuntimeType.Clone, RuntimeType.PartialEq, RuntimeType.Eq, RuntimeType.Hash), visibility = constrainedTypeVisibility, ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolations.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolations.kt index 4d4efc4c7..55eae76c5 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolations.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolations.kt @@ -10,6 +10,7 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Visibility import software.amazon.smithy.rust.codegen.core.rustlang.docs @@ -66,7 +67,7 @@ class ServerBuilderConstraintViolations( "Attempted to render constraint violations for the builder for structure shape ${shape.id}, but calculation of the constraint violations resulted in no variants" } - Attribute.Derives(setOf(RuntimeType.Debug, RuntimeType.PartialEq)).render(writer) + Attribute(derive(RuntimeType.Debug, RuntimeType.PartialEq)).render(writer) writer.docs("Holds one variant for each of the ways the builder can fail.") if (nonExhaustive) Attribute.NonExhaustive.render(writer) val constraintViolationSymbolName = constraintViolationSymbolProvider.toSymbol(shape).name diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGenerator.kt index d42671780..27bfa69d3 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGenerator.kt @@ -12,6 +12,7 @@ import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.RustType import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Visibility @@ -185,9 +186,10 @@ class ServerBuilderGenerator( // Matching derives to the main structure, - `PartialEq` (see class documentation for why), + `Default` // since we are a builder and everything is optional. val baseDerives = structureSymbol.expectRustMetadata().derives - val builderDerives = baseDerives.derives.intersect(setOf(RuntimeType.Debug, RuntimeType.Clone)) + RuntimeType.Default - baseDerives.copy(derives = builderDerives).render(writer) - writer.rustBlock("pub${ if (visibility == Visibility.PUBCRATE) " (crate)" else "" } struct Builder") { + // Filter out any derive that isn't Debug or Clone. Then add a Default derive + val builderDerives = baseDerives.filter { it == RuntimeType.Debug || it == RuntimeType.Clone } + RuntimeType.Default + Attribute(derive(builderDerives)).render(writer) + writer.rustBlock("${visibility.toRustQualifier()} struct Builder") { members.forEach { renderBuilderMember(this, it) } } @@ -204,7 +206,7 @@ class ServerBuilderGenerator( renderBuildFn(this) } - if (!builderDerives.contains(RuntimeType.Debug)) { + if (!structureSymbol.expectRustMetadata().hasDebugDerive()) { renderImplDebugForBuilder(writer) } } @@ -325,7 +327,7 @@ class ServerBuilderGenerator( // to the heap. However, that will make the builder take in a value whose type does not exactly match the // shape member's type. // We don't want to introduce API asymmetry just for this particular case, so we disable the lint. - Attribute.Custom("allow(clippy::boxed_local)").render(writer) + Attribute.AllowClippyBoxedLocal.render(writer) } writer.rustBlock("pub fn $memberName(mut self, input: ${symbol.rustType().render()}) -> Self") { withBlock("self.$memberName = ", "; self") { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt index 3e03a9d1a..b30252a8a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt @@ -9,6 +9,8 @@ import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Visibility import software.amazon.smithy.rust.codegen.core.rustlang.conditionalBlock @@ -115,8 +117,9 @@ class ServerBuilderGeneratorWithoutPublicConstrainedTypes( // Matching derives to the main structure, - `PartialEq` (to be consistent with [ServerBuilderGenerator]), + `Default` // since we are a builder and everything is optional. val baseDerives = structureSymbol.expectRustMetadata().derives - val derives = baseDerives.derives.intersect(setOf(RuntimeType.Debug, RuntimeType.Clone)) + RuntimeType.Default - baseDerives.copy(derives = derives).render(writer) + // Filter out any derive that isn't Debug or Clone. Then add a Default derive + val derives = baseDerives.filter { it == RuntimeType.Debug || it == RuntimeType.Clone } + RuntimeType.Default + Attribute(derive(derives)).render(writer) writer.rustBlock("pub struct Builder") { members.forEach { renderBuilderMember(this, it) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt index 893f4d14f..1a55cb887 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt @@ -5,7 +5,6 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.shapes.StringShape -import software.amazon.smithy.rust.codegen.core.rustlang.RustModule 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 @@ -43,9 +42,7 @@ open class ServerEnumGenerator( ) override fun renderFromForStr() { - writer.withInlineModule( - constraintViolationSymbol.module() as RustModule.LeafModule, - ) { + writer.withInlineModule(constraintViolationSymbol.module()) { rustTemplate( """ ##[derive(Debug, PartialEq)] diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGenerator.kt index 0d2a98290..44048276d 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGenerator.kt @@ -8,7 +8,6 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.StructureShape -import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Visibility @@ -44,7 +43,7 @@ open class ServerOperationErrorGenerator( operationSymbol: Symbol, ) { val meta = RustMetadata( - derives = Attribute.Derives(setOf(RuntimeType.Debug)), + derives = setOf(RuntimeType.Debug), visibility = Visibility.PUBLIC, ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationRegistryGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationRegistryGenerator.kt index fe7905914..10b11978d 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationRegistryGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationRegistryGenerator.kt @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.DependencyScope import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords @@ -202,7 +203,7 @@ ${operationImplementationStubs(operations)} * This is an enum deriving `Debug` and implementing `Display` and `std::error::Error`. */ private fun renderOperationRegistryBuilderError(writer: RustWriter) { - Attribute.Derives(setOf(RuntimeType.Debug)).render(writer) + Attribute(derive(RuntimeType.Debug)).render(writer) writer.rustTemplate( """ pub enum $operationRegistryErrorName { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 1625b5697..b5da3fd00 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.deprecated import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords @@ -263,7 +264,7 @@ open class ServerServiceGenerator( RustMetadata( visibility = Visibility.PUBLIC, additionalAttributes = listOf( - Attribute.Deprecated("0.52.0", "This module exports the deprecated `OperationRegistry`. Use the service builder exported from your root crate."), + Attribute(deprecated("0.52.0", "This module exports the deprecated `OperationRegistry`. Use the service builder exported from your root crate.")), ), ), """ diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt index af97976ae..72655675a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt @@ -10,6 +10,7 @@ import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.derive import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Visibility import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -134,7 +135,7 @@ class UnconstrainedUnionGenerator( modelsModuleWriter.withInlineModule( constraintViolationSymbol.module(), ) { - Attribute.Derives(setOf(RuntimeType.Debug, RuntimeType.PartialEq)).render(this) + Attribute(derive(RuntimeType.Debug, RuntimeType.PartialEq)).render(this) rustBlock("pub${if (constraintViolationVisibility == Visibility.PUBCRATE) " (crate)" else ""} enum $constraintViolationName") { constraintViolations().forEach { renderConstraintViolation(this, it) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt index 955696b31..cad378617 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt @@ -25,6 +25,7 @@ import software.amazon.smithy.protocoltests.traits.HttpRequestTestsTrait import software.amazon.smithy.protocoltests.traits.HttpResponseTestCase import software.amazon.smithy.protocoltests.traits.HttpResponseTestsTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.allow import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords @@ -42,7 +43,6 @@ 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.generators.protocol.ProtocolSupport import software.amazon.smithy.rust.codegen.core.smithy.transformers.allErrors -import software.amazon.smithy.rust.codegen.core.testutil.TokioTest import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.getTrait import software.amazon.smithy.rust.codegen.core.util.hasStreamingMember @@ -179,7 +179,7 @@ class ServerProtocolTestGenerator( PROTOCOL_TEST_HELPER_MODULE_NAME, RustMetadata( additionalAttributes = listOf( - Attribute.Cfg("test"), + Attribute.CfgTest, Attribute.AllowDeadCode, ), visibility = Visibility.PUBCRATE, @@ -257,8 +257,8 @@ class ServerProtocolTestGenerator( "server_${operationName.toSnakeCase()}_test", RustMetadata( additionalAttributes = listOf( - Attribute.Cfg("test"), - Attribute.Custom("allow(unreachable_code, unused_variables)"), + Attribute.CfgTest, + Attribute(allow("unreachable_code", "unused_variables")), ), visibility = Visibility.PRIVATE, ), @@ -365,7 +365,7 @@ class ServerProtocolTestGenerator( testModuleWriter.rust("Test ID: ${testCase.id}") testModuleWriter.newlinePrefix = "" - TokioTest.render(testModuleWriter) + Attribute.TokioTest.render(testModuleWriter) if (expectFail(testCase)) { testModuleWriter.writeWithNoFormatting("#[should_panic]") diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt index f6b5c51c5..390eab302 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt @@ -393,7 +393,7 @@ private class ServerHttpBoundProtocolTraitImplGenerator( val inputSymbol = symbolProvider.toSymbol(inputShape) return RuntimeType.forInlineFun(fnName, operationDeserModule) { - Attribute.Custom("allow(clippy::unnecessary_wraps)").render(this) + Attribute.AllowClippyUnnecessaryWraps.render(this) // The last conversion trait bound is needed by the `hyper::body::to_bytes(body).await?` call. rustBlockTemplate( """ @@ -428,7 +428,7 @@ private class ServerHttpBoundProtocolTraitImplGenerator( val outputSymbol = symbolProvider.toSymbol(outputShape) return RuntimeType.forInlineFun(fnName, operationSerModule) { - Attribute.Custom("allow(clippy::unnecessary_wraps)").render(this) + Attribute.AllowClippyUnnecessaryWraps.render(this) // Note we only need to take ownership of the output in the case that it contains streaming members. // However, we currently always take ownership here, but worth noting in case in the future we want @@ -459,7 +459,7 @@ private class ServerHttpBoundProtocolTraitImplGenerator( val fnName = "serialize_${operationShape.id.name.toSnakeCase()}_error" val errorSymbol = operationShape.errorSymbol(symbolProvider) return RuntimeType.forInlineFun(fnName, operationSerModule) { - Attribute.Custom("allow(clippy::unnecessary_wraps)").render(this) + Attribute.AllowClippyUnnecessaryWraps.render(this) rustBlockTemplate( "pub fn $fnName(error: &#{E}) -> std::result::Result<#{SmithyHttpServer}::response::Response, #{ResponseRejection}>", *codegenScope, -- GitLab