From 7c7bd778e78774e92af1448324c4a6b9223d41a3 Mon Sep 17 00:00:00 2001 From: JordonPhillips Date: Fri, 8 May 2020 16:30:52 -0700 Subject: [PATCH] Update namespace handling This updates and fixes the way namespacing is handled, particularly with regard to aliasing. Previously a SymbolReference was being created to represent the namespace, but that isn't right since a namespace isn't an individually referenceable entity. Now the symbol itself controls how its namespace should be referenced. This ends up being much more concise to define as an added bonus. --- .../smithy/go/codegen/CodegenUtils.java | 15 ++++ .../smithy/go/codegen/GoDependency.java | 19 +++-- .../GoStackStepMiddlewareGenerator.java | 78 ++++++++----------- .../amazon/smithy/go/codegen/GoWriter.java | 33 +++++++- .../smithy/go/codegen/StructureGenerator.java | 3 + .../amazon/smithy/go/codegen/SymbolUtils.java | 74 +++++++++++------- .../smithy/go/codegen/SymbolVisitor.java | 20 ++--- 7 files changed, 142 insertions(+), 100 deletions(-) diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenUtils.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenUtils.java index 3968a60ea..f348df527 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenUtils.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenUtils.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.logging.Logger; import software.amazon.smithy.codegen.core.CodegenException; +import software.amazon.smithy.codegen.core.Symbol; import software.amazon.smithy.utils.StringUtils; /** @@ -97,6 +98,20 @@ public static String getDefaultPackageImportName(String packageName) { return packageName.substring(packageName.lastIndexOf('/') + 1); } + /** + * Gets the alias to use when referencing the given symbol outside of its namespace. + * + *

The default value is the last path component of the symbol's namespace. + * + * @param symbol The symbol whose whose namespace alias should be retrieved. + * @return The alias of the symbol's namespace. + */ + public static String getSymbolNamespaceAlias(Symbol symbol) { + return symbol.getProperty(SymbolUtils.NAMESPACE_ALIAS, String.class) + .filter(StringUtils::isNotBlank) + .orElse(CodegenUtils.getDefaultPackageImportName(symbol.getNamespace())); + } + /** * Detects if an annotated mediatype indicates JSON contents. * diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoDependency.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoDependency.java index c7ba75be8..dd818fa56 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoDependency.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoDependency.java @@ -27,23 +27,25 @@ public enum GoDependency implements SymbolDependencyContainer { // The version in the stdlib dependencies should reflect the minimum Go version. // The values aren't currently used, but they could potentially used to dynamically // set the minimum go version. - BIG("stdlib", "", "math/big", "1.14"), - TIME("stdlib", "", "time", "1.14"), - FMT("stdlib", "", "fmt", "1.14"), - CONTEXT("stdlib", "", "context", "1.14"), + BIG("stdlib", "", "math/big", null, "1.14"), + TIME("stdlib", "", "time", null, "1.14"), + FMT("stdlib", "", "fmt", null, "1.14"), + CONTEXT("stdlib", "", "context", null, "1.14"), - SMITHY("dependency", "github.com/awslabs/smithy-go", "github.com/awslabs/smithy-go", "v0.0.1"), + SMITHY("dependency", "github.com/awslabs/smithy-go", "github.com/awslabs/smithy-go", + "smithy", "v0.0.1"), SMITHY_HTTP_TRANSPORT("dependency", "github.com/awslabs/smithy-go", - "github.com/awslabs/smithy-go/transport/http", "v0.0.1"), + "github.com/awslabs/smithy-go/transport/http", "smithyhttp", "v0.0.1"), SMITHY_MIDDLEWARE("dependency", "github.com/awslabs/smithy-go", - "github.com/awslabs/smithy-go/middleware", "v0.0.1"); + "github.com/awslabs/smithy-go/middleware", null, "v0.0.1"); public final String sourcePath; public final String importPath; + public final String alias; public final String version; public final SymbolDependency dependency; - GoDependency(String type, String sourcePath, String importPath, String version) { + GoDependency(String type, String sourcePath, String importPath, String alias, String version) { this.dependency = SymbolDependency.builder() .dependencyType(type) .packageName(sourcePath) @@ -52,6 +54,7 @@ public enum GoDependency implements SymbolDependencyContainer { this.sourcePath = sourcePath; this.importPath = importPath; this.version = version; + this.alias = alias; } @Override diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoStackStepMiddlewareGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoStackStepMiddlewareGenerator.java index d3613878e..9cd014451 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoStackStepMiddlewareGenerator.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoStackStepMiddlewareGenerator.java @@ -16,30 +16,22 @@ package software.amazon.smithy.go.codegen; import java.util.function.BiConsumer; - import software.amazon.smithy.codegen.core.Symbol; -import software.amazon.smithy.codegen.core.SymbolReference; /** * Helper for generating stack step middleware. */ public final class GoStackStepMiddlewareGenerator { - private static final SymbolReference CONTEXT_TYPE = SymbolReference.builder() - .symbol(SymbolUtils.createValueSymbolBuilder("context.Context") - .addReference(SymbolUtils.createNamespaceReference(GoDependency.CONTEXT)) - .build()) - .build(); - private static final SymbolReference METADATA_TYPE = SymbolReference.builder() - .symbol(SymbolUtils.createValueSymbolBuilder("middleware.Metadata") - .addReference(SymbolUtils.createNamespaceReference(GoDependency.SMITHY_MIDDLEWARE)) - .build()) - .build(); + private static final Symbol CONTEXT_TYPE = SymbolUtils.createValueSymbolBuilder( + "Context", GoDependency.CONTEXT).build(); + private static final Symbol METADATA_TYPE = SymbolUtils.createValueSymbolBuilder( + "Metadata", GoDependency.SMITHY_MIDDLEWARE).build(); private final Symbol middlewareSymbol; private final String handleMethodName; - private final SymbolReference inputType; - private final SymbolReference outputType; - private final SymbolReference handlerType; + private final Symbol inputType; + private final Symbol outputType; + private final Symbol handlerType; /** * Creates a new middleware generator with the given builder definition. @@ -63,9 +55,9 @@ public GoStackStepMiddlewareGenerator(Builder builder) { public static GoStackStepMiddlewareGenerator createSerializeStepMiddleware(String identifier) { return createMiddleware(identifier, "HandleSerialize", - createSmithyMiddlewarePackageReference("middleware.SerializeInput"), - createSmithyMiddlewarePackageReference("middleware.SerializeOutput"), - createSmithyMiddlewarePackageReference("middleware.SerializeHandler")); + SymbolUtils.createValueSymbolBuilder("SerializeInput", GoDependency.SMITHY_MIDDLEWARE).build(), + SymbolUtils.createValueSymbolBuilder("SerializeOutput", GoDependency.SMITHY_MIDDLEWARE).build(), + SymbolUtils.createValueSymbolBuilder("SerializeHandler", GoDependency.SMITHY_MIDDLEWARE).build()); } /** @@ -77,9 +69,9 @@ public static GoStackStepMiddlewareGenerator createSerializeStepMiddleware(Strin public static GoStackStepMiddlewareGenerator createDeserializeStepMiddleware(String identifier) { return createMiddleware(identifier, "HandleDeserialize", - createSmithyMiddlewarePackageReference("middleware.DeserializeInput"), - createSmithyMiddlewarePackageReference("middleware.DeserializeOutput"), - createSmithyMiddlewarePackageReference("middleware.DeserializeHandler")); + SymbolUtils.createValueSymbolBuilder("DeserializeInput", GoDependency.SMITHY_MIDDLEWARE).build(), + SymbolUtils.createValueSymbolBuilder("DeserializeOutput", GoDependency.SMITHY_MIDDLEWARE).build(), + SymbolUtils.createValueSymbolBuilder("DeserializeHandler", GoDependency.SMITHY_MIDDLEWARE).build()); } /** @@ -95,9 +87,9 @@ public static GoStackStepMiddlewareGenerator createDeserializeStepMiddleware(Str public static GoStackStepMiddlewareGenerator createMiddleware( String identifier, String handlerMethodName, - SymbolReference inputType, - SymbolReference outputType, - SymbolReference handlerType + Symbol inputType, + Symbol outputType, + Symbol handlerType ) { return builder() .identifier(identifier) @@ -211,7 +203,7 @@ public Symbol getMiddlewareSymbol() { * * @return the input type symbol reference. */ - public SymbolReference getInputType() { + public Symbol getInputType() { return inputType; } @@ -220,7 +212,7 @@ public SymbolReference getInputType() { * * @return the output type symbol reference. */ - public SymbolReference getOutputType() { + public Symbol getOutputType() { return outputType; } @@ -229,45 +221,37 @@ public SymbolReference getOutputType() { * * @return the handler type symbol reference. */ - public SymbolReference getHandlerType() { + public Symbol getHandlerType() { return handlerType; } /** - * Get the context type symbol reference. + * Get the context type symbol. * - * @return the context type symbol reference. + * @return the context type symbol. */ - public static SymbolReference getContextType() { + public static Symbol getContextType() { return CONTEXT_TYPE; } /** - * Get the middleware metadata type symbol reference. + * Get the middleware metadata type symbol. * - * @return the middleware metadata type symbol reference. + * @return the middleware metadata type symbol. */ - public static SymbolReference getMiddlewareMetadataType() { + public static Symbol getMiddlewareMetadataType() { return METADATA_TYPE; } - private static SymbolReference createSmithyMiddlewarePackageReference(String typeName) { - return SymbolReference.builder() - .symbol(SymbolUtils.createValueSymbolBuilder(typeName) - .addReference(SymbolUtils.createNamespaceReference(GoDependency.SMITHY_MIDDLEWARE)) - .build()) - .build(); - } - /** * Builds a {@link GoStackStepMiddlewareGenerator}. */ public static class Builder { private String identifier; private String handleMethodName; - private SymbolReference inputType; - private SymbolReference outputType; - private SymbolReference handlerType; + private Symbol inputType; + private Symbol outputType; + private Symbol handlerType; /** * Builds the middleware generator. @@ -306,7 +290,7 @@ public Builder identifier(String identifier) { * @param inputType the symbol reference to the input type. * @return the builder. */ - public Builder inputType(SymbolReference inputType) { + public Builder inputType(Symbol inputType) { this.inputType = inputType; return this; } @@ -317,7 +301,7 @@ public Builder inputType(SymbolReference inputType) { * @param outputType the symbol reference to the output type. * @return the builder. */ - public Builder outputType(SymbolReference outputType) { + public Builder outputType(Symbol outputType) { this.outputType = outputType; return this; } @@ -328,7 +312,7 @@ public Builder outputType(SymbolReference outputType) { * @param handlerType the symbol reference to the handler type. * @return the builder. */ - public Builder handlerType(SymbolReference handlerType) { + public Builder handlerType(Symbol handlerType) { this.handlerType = handlerType; return this; } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoWriter.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoWriter.java index 85614300c..2928bb964 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoWriter.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoWriter.java @@ -71,7 +71,7 @@ public GoWriter(String fullPackageName) { public GoWriter addUseImports(SymbolContainer container) { for (Symbol symbol : container.getSymbols()) { addImport(symbol, - CodegenUtils.getDefaultPackageImportName(symbol.getNamespace()), + CodegenUtils.getSymbolNamespaceAlias(symbol), SymbolReference.ContextOption.USE); } return this; @@ -88,6 +88,17 @@ public GoWriter addUseImports(SymbolReference symbolReference) { return addImport(symbolReference.getSymbol(), symbolReference.getAlias(), SymbolReference.ContextOption.USE); } + /** + * Adds and imports the given dependency. + * + * @param goDependency The GoDependency to import. + * @return Returns the writer. + */ + public GoWriter addUseImports(GoDependency goDependency) { + dependencies.addAll(goDependency.getDependencies()); + return addImport(goDependency.importPath, goDependency.alias); + } + /** * Imports a symbol if necessary using a package alias and list of context options. * @@ -110,7 +121,7 @@ public GoWriter addImport(Symbol symbol, String packageAlias, SymbolReference.Co // Always add dependencies. dependencies.addAll(symbol.getDependencies()); - if (!symbol.getNamespace().isEmpty() && !symbol.getNamespace().equals(fullPackageName)) { + if (isExternalNamespace(symbol.getNamespace())) { addImport(symbol.getNamespace(), packageAlias); } @@ -121,6 +132,10 @@ public GoWriter addImport(Symbol symbol, String packageAlias, SymbolReference.Co return this; } + private boolean isExternalNamespace(String namespace) { + return !StringUtils.isBlank(namespace) && !namespace.equals(fullPackageName); + } + void addImportReferences(Symbol symbol, SymbolReference.ContextOption... options) { for (SymbolReference reference : symbol.getReferences()) { for (SymbolReference.ContextOption option : options) { @@ -254,6 +269,9 @@ public String apply(Object type, String indent) { if (type instanceof Symbol) { Symbol typeSymbol = (Symbol) type; addUseImports(typeSymbol); + if (isExternalNamespace(typeSymbol.getNamespace())) { + return formatWithNamespace(typeSymbol); + } return typeSymbol.getName(); } else if (type instanceof SymbolReference) { SymbolReference typeSymbol = (SymbolReference) type; @@ -264,6 +282,13 @@ public String apply(Object type, String indent) { "Invalid type provided to $T. Expected a Symbol, but found `" + type + "`"); } } + + private String formatWithNamespace(Symbol symbol) { + if (StringUtils.isEmpty(symbol.getNamespace())) { + return symbol.getName(); + } + return String.format("%s.%s", CodegenUtils.getSymbolNamespaceAlias(symbol), symbol.getName()); + } } /** @@ -283,10 +308,10 @@ public String apply(Object type, String indent) { private boolean isPointer(Object type) { if (type instanceof Symbol) { Symbol typeSymbol = (Symbol) type; - return typeSymbol.getProperty("pointable", Boolean.class).orElse(false); + return typeSymbol.getProperty(SymbolUtils.POINTABLE, Boolean.class).orElse(false); } else if (type instanceof SymbolReference) { SymbolReference typeSymbol = (SymbolReference) type; - return typeSymbol.getProperty("pointable", Boolean.class).orElse(false); + return typeSymbol.getProperty(SymbolUtils.POINTABLE, Boolean.class).orElse(false); } else { throw new CodegenException( "Invalid type provided to $P. Expected a Symbol, but found `" + type + "`"); diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/StructureGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/StructureGenerator.java index 07262b6ba..115071da3 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/StructureGenerator.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/StructureGenerator.java @@ -80,6 +80,9 @@ private void renderErrorStructure() { Symbol structureSymbol = symbolProvider.toSymbol(shape); String interfaceName = structureSymbol.getName() + "Interface"; + writer.addUseImports(GoDependency.SMITHY); + writer.addUseImports(GoDependency.FMT); + ErrorTrait errorTrait = shape.expectTrait(ErrorTrait.class); // Write out the interface for the error diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SymbolUtils.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SymbolUtils.java index de0c72f2e..19946c760 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SymbolUtils.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SymbolUtils.java @@ -16,13 +16,16 @@ package software.amazon.smithy.go.codegen; import software.amazon.smithy.codegen.core.Symbol; -import software.amazon.smithy.codegen.core.SymbolReference; import software.amazon.smithy.model.shapes.Shape; /** * Common symbol utility building functions. */ public final class SymbolUtils { + + public static final String POINTABLE = "pointable"; + public static final String NAMESPACE_ALIAS = "namespaceAlias"; + private SymbolUtils() { } @@ -34,7 +37,7 @@ private SymbolUtils() { */ public static Symbol.Builder createValueSymbolBuilder(String typeName) { return Symbol.builder() - .putProperty("pointable", false) + .putProperty(POINTABLE, false) .name(typeName); } @@ -46,7 +49,7 @@ public static Symbol.Builder createValueSymbolBuilder(String typeName) { */ public static Symbol.Builder createPointableSymbolBuilder(String typeName) { return Symbol.builder() - .putProperty("pointable", true) + .putProperty(POINTABLE, true) .name(typeName); } @@ -119,37 +122,54 @@ public static Symbol.Builder createValueSymbolBuilder(Shape shape, String typeNa } /** - * Create a symbol reference for a dependency. + * Create a pointable symbol builder. + * + * @param shape the shape that the type is for. + * @param typeName the name of the type. + * @param namespace the namespace of the type. + * @return the symbol builder. + */ + public static Symbol.Builder createPointableSymbolBuilder(Shape shape, String typeName, GoDependency namespace) { + return setImportedNamespace(createPointableSymbolBuilder(shape, typeName), namespace); + } + + /** + * Create a value symbol builder. + * + * @param shape the shape that the type is for. + * @param typeName the name of the type. + * @param namespace the namespace of the type. + * @return the symbol builder. + */ + public static Symbol.Builder createValueSymbolBuilder(Shape shape, String typeName, GoDependency namespace) { + return setImportedNamespace(createValueSymbolBuilder(shape, typeName), namespace); + } + + /** + * Create a pointable symbol builder. * - * @param dependency the dependency to represent as a symbol reference. - * @return the symbol reference. + * @param typeName the name of the type. + * @param namespace the namespace of the type. + * @return the symbol builder. */ - public static SymbolReference createNamespaceReference(GoDependency dependency) { - String namespace = dependency.importPath; - return createNamespaceReference(dependency, CodegenUtils.getDefaultPackageImportName(namespace)); + public static Symbol.Builder createPointableSymbolBuilder(String typeName, GoDependency namespace) { + return setImportedNamespace(createPointableSymbolBuilder(typeName), namespace); } /** - * Create a symbol reference for a dependency. + * Create a value symbol builder. * - * @param dependency the dependency to represent as a symbol reference. - * @param alias the alias to refer to the namespace. - * @return the symbol reference. + * @param typeName the name of the type. + * @param namespace the namespace of the type. + * @return the symbol builder. */ - public static SymbolReference createNamespaceReference(GoDependency dependency, String alias) { - // Go generally imports an entire package under a single name, which defaults to the last - // part of the package name path. So we need to create a symbol for that namespace to reference. - String namespace = dependency.importPath; - Symbol namespaceSymbol = Symbol.builder() - // We're not referencing a particular symbol from the namespace, so we leave the name blank. - .name("") - .putProperty("namespaceSymbol", true) - .namespace(namespace, "/") + public static Symbol.Builder createValueSymbolBuilder(String typeName, GoDependency namespace) { + return setImportedNamespace(createValueSymbolBuilder(typeName), namespace); + } + + private static Symbol.Builder setImportedNamespace(Symbol.Builder builder, GoDependency dependency) { + return builder.namespace(dependency.importPath, ".") .addDependency(dependency) - .build(); - return SymbolReference.builder() - .symbol(namespaceSymbol) - .alias(alias) - .build(); + .putProperty(NAMESPACE_ALIAS, dependency.alias); } } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SymbolVisitor.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SymbolVisitor.java index 1c24a7f45..8fcb8dfb7 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SymbolVisitor.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/SymbolVisitor.java @@ -274,9 +274,7 @@ public Symbol floatShape(FloatShape shape) { @Override public Symbol documentShape(DocumentShape shape) { - return SymbolUtils.createValueSymbolBuilder(shape, "smithy.Document") - .addReference(SymbolUtils.createNamespaceReference(GoDependency.SMITHY, "smithy")) - .build(); + return SymbolUtils.createValueSymbolBuilder(shape, "Document", GoDependency.SMITHY).build(); } @Override @@ -286,18 +284,16 @@ public Symbol doubleShape(DoubleShape shape) { @Override public Symbol bigIntegerShape(BigIntegerShape shape) { - return createBigSymbol(shape, "big.Int"); + return createBigSymbol(shape, "Int"); } @Override public Symbol bigDecimalShape(BigDecimalShape shape) { - return createBigSymbol(shape, "big.Float"); + return createBigSymbol(shape, "Float"); } private Symbol createBigSymbol(Shape shape, String symbolName) { - return SymbolUtils.createPointableSymbolBuilder(shape, symbolName) - .addReference(SymbolUtils.createNamespaceReference(GoDependency.BIG)) - .build(); + return SymbolUtils.createPointableSymbolBuilder(shape, symbolName, GoDependency.BIG).build(); } @Override @@ -337,9 +333,7 @@ public Symbol structureShape(StructureShape shape) { String name = getDefaultShapeName(shape); Symbol.Builder builder = SymbolUtils.createPointableSymbolBuilder(shape, name, typesPackageName); if (shape.hasTrait(ErrorTrait.ID)) { - builder.definitionFile("./types/errors.go") - .addReference(SymbolUtils.createNamespaceReference(GoDependency.SMITHY, "smithy")) - .addReference(SymbolUtils.createNamespaceReference(GoDependency.FMT)); + builder.definitionFile("./types/errors.go"); } else { builder.definitionFile("./types/types.go"); } @@ -363,8 +357,6 @@ public Symbol memberShape(MemberShape shape) { @Override public Symbol timestampShape(TimestampShape shape) { - return SymbolUtils.createPointableSymbolBuilder(shape, "time.Time") - .addReference(SymbolUtils.createNamespaceReference(GoDependency.TIME)) - .build(); + return SymbolUtils.createPointableSymbolBuilder(shape, "Time", GoDependency.TIME).build(); } }