Skip to content

Commit c43e95e

Browse files
authored
fix(codegen): allow symbol provider to give a fully qualified name hint that takes precedence (#868)
1 parent 6f68ac0 commit c43e95e

File tree

6 files changed

+61
-7
lines changed

6 files changed

+61
-7
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "a646a910-2f13-4231-aa51-a5feb2e335a2",
3+
"type": "bugfix",
4+
"description": "Add fully qualified name hint for collection types",
5+
"issues": [
6+
"awslabs/smithy-kotlin#867"
7+
]
8+
}

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinSymbolProvider.kt

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package software.amazon.smithy.kotlin.codegen.core
66

77
import software.amazon.smithy.codegen.core.*
88
import software.amazon.smithy.kotlin.codegen.KotlinSettings
9+
import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes
910
import software.amazon.smithy.kotlin.codegen.lang.kotlinReservedWords
1011
import software.amazon.smithy.kotlin.codegen.model.*
1112
import software.amazon.smithy.kotlin.codegen.utils.dq
@@ -148,23 +149,31 @@ class KotlinSymbolProvider(private val model: Model, private val settings: Kotli
148149

149150
override fun listShape(shape: ListShape): Symbol {
150151
val reference = toSymbol(shape.member)
151-
val valueType = if (shape.hasTrait<SparseTrait>()) "${reference.name}?" else reference.name
152+
val valueSuffix = if (shape.hasTrait<SparseTrait>()) "?" else ""
153+
val valueType = "${reference.name}$valueSuffix"
154+
val fullyQualifiedValueType = "${reference.fullName}$valueSuffix"
152155
return createSymbolBuilder(shape, "List<$valueType>", nullable = true)
153156
.addReferences(reference)
157+
.putProperty(SymbolProperty.FULLY_QUALIFIED_NAME_HINT, "List<$fullyQualifiedValueType>")
154158
.putProperty(SymbolProperty.MUTABLE_COLLECTION_FUNCTION, "mutableListOf<$valueType>")
155159
.putProperty(SymbolProperty.IMMUTABLE_COLLECTION_FUNCTION, "listOf<$valueType>")
156160
.build()
157161
}
158162

159163
override fun mapShape(shape: MapShape): Symbol {
160164
val reference = toSymbol(shape.value)
161-
val valueType = if (shape.hasTrait<SparseTrait>()) "${reference.name}?" else reference.name
165+
val valueSuffix = if (shape.hasTrait<SparseTrait>()) "?" else ""
166+
val valueType = "${reference.name}$valueSuffix"
167+
val fullyQualifiedValueType = "${reference.fullName}$valueSuffix"
162168

163-
return createSymbolBuilder(shape, "Map<String, $valueType>", nullable = true)
169+
val keyType = KotlinTypes.String.name
170+
val fullyQualifiedKeyType = KotlinTypes.String.fullName
171+
return createSymbolBuilder(shape, "Map<$keyType, $valueType>", nullable = true)
164172
.addReferences(reference)
165-
.putProperty(SymbolProperty.MUTABLE_COLLECTION_FUNCTION, "mutableMapOf<String, $valueType>")
166-
.putProperty(SymbolProperty.IMMUTABLE_COLLECTION_FUNCTION, "mapOf<String, $valueType>")
167-
.putProperty(SymbolProperty.ENTRY_EXPRESSION, "Map.Entry<String, $valueType>")
173+
.putProperty(SymbolProperty.FULLY_QUALIFIED_NAME_HINT, "Map<$fullyQualifiedKeyType, $fullyQualifiedValueType>")
174+
.putProperty(SymbolProperty.MUTABLE_COLLECTION_FUNCTION, "mutableMapOf<$keyType, $valueType>")
175+
.putProperty(SymbolProperty.IMMUTABLE_COLLECTION_FUNCTION, "mapOf<$keyType, $valueType>")
176+
.putProperty(SymbolProperty.ENTRY_EXPRESSION, "Map.Entry<$keyType, $valueType>")
168177
.build()
169178
}
170179

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinWriter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ private class KotlinSymbolFormatter(
296296
is Symbol -> {
297297
// writer will omit unnecessary same package imports and dedupe
298298
writer.addImport(type)
299-
return if (fullyQualifiedPredicate(type)) type.fullName else type.name
299+
return if (fullyQualifiedPredicate(type)) (type.fullNameHint ?: type.fullName) else type.name
300300
}
301301
else -> throw CodegenException("Invalid type provided for #T. Expected a Symbol, but found `$type`")
302302
}

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/model/SymbolExt.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ object SymbolProperty {
4747

4848
// Denotes the symbol is a reference to a static member of an object (e.g. of an object or companion object)
4949
const val OBJECT_REF: String = "objectRef"
50+
51+
// Adds a property to give a hint at what the fully qualified name should be. Used by #Q symbol formatter to
52+
// give symbols fine-grained control over their fully qualified name (e.g. collections with generics can fully
53+
// qualify the generic type)
54+
const val FULLY_QUALIFIED_NAME_HINT: String = "fullyQualifiedNameHint"
5055
}
5156

5257
/**
@@ -217,3 +222,9 @@ val Symbol.isObjectRef: Boolean
217222
*/
218223
val Symbol.objectRef: Symbol?
219224
get() = getProperty(SymbolProperty.OBJECT_REF, Symbol::class.java).getOrNull()
225+
226+
/**
227+
* Get the fully qualified name hint if one is set
228+
*/
229+
val Symbol.fullNameHint: String?
230+
get() = getProperty(SymbolProperty.FULLY_QUALIFIED_NAME_HINT, String::class.java).getOrNull()

codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinWriterTest.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package software.amazon.smithy.kotlin.codegen.core
88
import io.kotest.matchers.string.shouldNotContain
99
import software.amazon.smithy.kotlin.codegen.integration.SectionId
1010
import software.amazon.smithy.kotlin.codegen.integration.SectionKey
11+
import software.amazon.smithy.kotlin.codegen.model.SymbolProperty
1112
import software.amazon.smithy.kotlin.codegen.model.buildSymbol
1213
import software.amazon.smithy.kotlin.codegen.test.TestModelDefault
1314
import software.amazon.smithy.kotlin.codegen.test.shouldContainOnlyOnceWithDiff
@@ -309,4 +310,20 @@ class KotlinWriterTest {
309310
contents.shouldNotContain("import com.test.Foo")
310311
contents.shouldContainWithDiff("import com.test.subpkg.Bar")
311312
}
313+
314+
@Test
315+
fun itFavorsFullNameHint() {
316+
val unit = KotlinWriter("com.test")
317+
318+
val symbol = buildSymbol {
319+
name = "Foo"
320+
namespace = "com.test"
321+
properties { set(SymbolProperty.FULLY_QUALIFIED_NAME_HINT, "baz.quux.Foo") }
322+
}
323+
324+
unit.write("val foo = #Q", symbol)
325+
326+
val contents = unit.toString()
327+
contents.shouldContainWithDiff("baz.quux.Foo")
328+
}
312329
}

codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/core/SymbolProviderTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import software.amazon.smithy.kotlin.codegen.KotlinCodegenPlugin
1313
import software.amazon.smithy.kotlin.codegen.core.KotlinDependency.Companion.CORE
1414
import software.amazon.smithy.kotlin.codegen.model.defaultValue
1515
import software.amazon.smithy.kotlin.codegen.model.expectShape
16+
import software.amazon.smithy.kotlin.codegen.model.fullNameHint
1617
import software.amazon.smithy.kotlin.codegen.model.isNullable
1718
import software.amazon.smithy.kotlin.codegen.model.traits.SYNTHETIC_NAMESPACE
1819
import software.amazon.smithy.kotlin.codegen.test.*
@@ -459,6 +460,10 @@ class SymbolProviderTest {
459460

460461
// collections should contain a reference to the member type
461462
assertEquals("Record", sparseListSymbol.references[0].symbol.name)
463+
464+
// check the fully qualified name hint is set
465+
assertEquals("List<foo.bar.model.Record>", listSymbol.fullNameHint)
466+
assertEquals("List<foo.bar.model.Record?>", sparseListSymbol.fullNameHint)
462467
}
463468

464469
@Test
@@ -520,6 +525,10 @@ class SymbolProviderTest {
520525

521526
// collections should contain a reference to the member type
522527
assertEquals("Record", sparseMapSymbol.references[0].symbol.name)
528+
529+
// check the fully qualified name hint is set
530+
assertEquals("Map<kotlin.String, com.test.model.Record>", mapSymbol.fullNameHint)
531+
assertEquals("Map<kotlin.String, com.test.model.Record?>", sparseMapSymbol.fullNameHint)
523532
}
524533

525534
@DisplayName("creates bigNumbers")

0 commit comments

Comments
 (0)