aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/mkdocs-requirements.txt2
-rw-r--r--docs/changelog.md34
-rw-r--r--gradle.properties2
-rw-r--r--kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/CodeWriter.kt53
-rw-r--r--kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/MemberNameTest.kt25
5 files changed, 83 insertions, 33 deletions
diff --git a/.github/workflows/mkdocs-requirements.txt b/.github/workflows/mkdocs-requirements.txt
index 924ec277..0a47aae7 100644
--- a/.github/workflows/mkdocs-requirements.txt
+++ b/.github/workflows/mkdocs-requirements.txt
@@ -6,7 +6,7 @@ lunr==0.7.0.post1
MarkupSafe==2.1.5
mkdocs==1.6.0
mkdocs-macros-plugin==1.0.5
-mkdocs-material==9.5.21
+mkdocs-material==9.5.25
mkdocs-material-extensions==1.3.1
Pygments==2.18.0
pymdown-extensions==10.8.1
diff --git a/docs/changelog.md b/docs/changelog.md
index 2ba3014b..668118ad 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -3,23 +3,37 @@ Change Log
## Unreleased
+## Version 1.17.0
+
+Thanks to [@jisungbin][jisungbin], [@hfhbd][hfhbd], [@evant][evant], [@sgjesse][sgjesse], [@sebek64][sebek64] for
+contributing to this release.
+
+_2024-05-24_
+
+* Change: kotlinx-metadata 0.9.0. Note that the `KotlinClassMetadata.read` is deprecated in 0.9.0 and replaced with
+ `readStrict` (#1830).
+ * Note: we now also provide `lenient` parameters to map to the underlying `readStrict()` and `readLenient()` calls
+ (#1766).
+ * We have also removed various `Class`/`TypeElement`/`Metadata`-to-`KmClass` APIs from the public API, as these are
+ trivial to write now with kotlinx-metadata's newer APIs and allows us to focus the API surface area of this artifact
+ better (#1891).
* New: Supertype list wraps to one-per-line if the primary constructor spans multiple lines (#1866).
-* New: Extract `MemberSpecHolder` interface for constructs that can hold `PropertySpec`s and `FunSpec`s and their builders (#1877).
-* New: `joinToCode` variant which operates on any type, but requires a transform lambda to convert each element into a `CodeBlock`.
+* New: Extract `MemberSpecHolder` interface for constructs that can hold `PropertySpec`s and `FunSpec`s and their
+ builders (#1877).
+* New: `joinToCode` variant which operates on any type, but requires a transform lambda to convert each element into a
+ `CodeBlock` (#1874).
* New: Support annotation type arguments in `KSAnnotation.toAnnotationSpec()` (#1889).
* Fix: Prevent name clashes between a function in class and a function call in current scope (#1850).
* Fix: Fix extension function imports (#1814).
-* Fix: Omit implicit modifiers on FileSpec.scriptBuilder (#1813).
-* Fix: Fix trailing newline in PropertySpec (#1827).
-* Change: kotlinx-metadata 0.9.0. Note that the `KotlinClassMetadata .read` is deprecated in 0.9.0 and replaced with `readStrict` (#1830).
- * Note: we now also `lenient` parameters to map to the underlying `readStrict()` and `readLenient()` calls (#1766).
- * We have also removed various `Class`/`TypeElement`/`Metadata`-to-`KmClass` APIs from the public API, as these are trivial to write now with kotlinx-metadata's newer APIs and allows us to focus the API surface area of this artifact better (#1891).
+* Fix: Omit implicit modifiers on `FileSpec.scriptBuilder` (#1813).
+* Fix: Fix trailing newline in `PropertySpec` (#1827).
* Fix: `KSAnnotation.toAnnotationSpec` writes varargs in place instead of making them an array to work around a Kotlin
- issue with `OptIn` annotations (#1831).
+ issue with `OptIn` annotations (#1833).
* Fix: `MemberName`s without a package are now correctly imported (#1841)
* Fix: Throw if primary constructor delegates to other constructors (#1859).
* Fix: Aliased imports with nested class (#1876).
* Fix: Check for error types in `KSType.toClassName()` (#1890).
+* Fix: Support generating a single import for overloaded `MemberName`s (#1909).
## Version 1.16.0
@@ -803,3 +817,7 @@ _2017-05-16_
[takahirom]: https://github.com/takahirom
[mcarleio]: https://github.com/mcarleio
[gabrielittner]: https://github.com/gabrielittner
+ [jisungbin]: https://github.com/jisungbin
+ [hfhbd]: https://github.com/hfhbd
+ [sgjesse]: https://github.com/sgjesse
+ [sebek64]: https://github.com/sebek64
diff --git a/gradle.properties b/gradle.properties
index ecde9401..d3559edb 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,7 +1,7 @@
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
GROUP=com.squareup
-VERSION_NAME=1.17.0-SNAPSHOT
+VERSION_NAME=1.18.0-SNAPSHOT
POM_URL=https://github.com/square/kotlinpoet
POM_SCM_URL=https://github.com/square/kotlinpoet
diff --git a/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/CodeWriter.kt b/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/CodeWriter.kt
index 4bdd102c..8f959c70 100644
--- a/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/CodeWriter.kt
+++ b/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/CodeWriter.kt
@@ -59,7 +59,7 @@ internal class CodeWriter(
private val indent: String = DEFAULT_INDENT,
imports: Map<String, Import> = emptyMap(),
private val importedTypes: Map<String, ClassName> = emptyMap(),
- private val importedMembers: Map<String, MemberName> = emptyMap(),
+ private val importedMembers: Map<String, Set<MemberName>> = emptyMap(),
columnLimit: Int = 100,
) : Closeable {
private var out = LineWrapper(out, indent, columnLimit)
@@ -463,11 +463,11 @@ internal class CodeWriter(
fun lookupName(memberName: MemberName): String {
val simpleName = imports[memberName.canonicalName]?.alias ?: memberName.simpleName
// Match an imported member.
- val importedMember = importedMembers[simpleName]
- val found = importedMember == memberName
+ val importedMembers = importedMembers[simpleName] ?: emptySet()
+ val found = memberName in importedMembers
if (found && !isMethodNameUsedInCurrentContext(simpleName)) {
return simpleName
- } else if (importedMember != null && memberName.enclosingClassName != null) {
+ } else if (importedMembers.isNotEmpty() && memberName.enclosingClassName != null) {
val enclosingClassName = lookupName(memberName.enclosingClassName)
return "$enclosingClassName.$simpleName"
} else if (found) {
@@ -717,14 +717,14 @@ internal class CodeWriter(
)
emitStep(importsCollector)
val generatedImports = mutableMapOf<String, Import>()
- val suggestedTypeImports = importsCollector.suggestedTypeImports()
+ val importedTypes = importsCollector.suggestedTypeImports()
.generateImports(
generatedImports,
computeCanonicalName = ClassName::canonicalName,
capitalizeAliases = true,
referencedNames = importsCollector.referencedNames,
)
- val suggestedMemberImports = importsCollector.suggestedMemberImports()
+ val importedMembers = importsCollector.suggestedMemberImports()
.generateImports(
generatedImports,
computeCanonicalName = MemberName::canonicalName,
@@ -737,8 +737,8 @@ internal class CodeWriter(
out = out,
indent = indent,
imports = memberImports + generatedImports.filterKeys { it !in memberImports },
- importedTypes = suggestedTypeImports,
- importedMembers = suggestedMemberImports,
+ importedTypes = importedTypes.mapValues { it.value.single() },
+ importedMembers = importedMembers,
)
}
@@ -747,31 +747,38 @@ internal class CodeWriter(
computeCanonicalName: T.() -> String,
capitalizeAliases: Boolean,
referencedNames: Set<String>,
- ): Map<String, T> {
- return flatMap { (simpleName, qualifiedNames) ->
- if (qualifiedNames.size == 1 && simpleName !in referencedNames) {
- listOf(simpleName to qualifiedNames.first()).also {
- val canonicalName = qualifiedNames.first().computeCanonicalName()
- generatedImports[canonicalName] = Import(canonicalName)
- }
+ ): Map<String, Set<T>> {
+ val imported = mutableMapOf<String, Set<T>>()
+ forEach { (simpleName, qualifiedNames) ->
+ val canonicalNamesToQualifiedNames = qualifiedNames.associateBy { it.computeCanonicalName() }
+ if (canonicalNamesToQualifiedNames.size == 1 && simpleName !in referencedNames) {
+ val canonicalName = canonicalNamesToQualifiedNames.keys.single()
+ generatedImports[canonicalName] = Import(canonicalName)
+
+ // For types, qualifiedNames should consist of a single name, for which an import will be generated. For
+ // members, there can be more than one qualified name mapping to a single simple name, e.g. overloaded
+ // functions declared in the same package. In these cases, a single import will suffice for all of them.
+ imported[simpleName] = qualifiedNames
} else {
- generateImportAliases(simpleName, qualifiedNames, computeCanonicalName, capitalizeAliases)
+ generateImportAliases(simpleName, canonicalNamesToQualifiedNames, capitalizeAliases)
.onEach { (alias, qualifiedName) ->
val canonicalName = qualifiedName.computeCanonicalName()
generatedImports[canonicalName] = Import(canonicalName, alias)
+
+ imported[alias] = setOf(qualifiedName)
}
}
- }.toMap()
+ }
+ return imported
}
private fun <T> generateImportAliases(
simpleName: String,
- qualifiedNames: Set<T>,
- canonicalName: T.() -> String,
+ canonicalNamesToQualifiedNames: Map<String, T>,
capitalizeAliases: Boolean,
): List<Pair<String, T>> {
- val canonicalNameSegments = qualifiedNames.associateWith { qualifiedName ->
- qualifiedName.canonicalName().split('.')
+ val canonicalNameSegmentsToQualifiedNames = canonicalNamesToQualifiedNames.mapKeys { (canonicalName, _) ->
+ canonicalName.split('.')
.dropLast(1) // Last segment of the canonical name is the simple name, drop it to avoid repetition.
.filter { it != "Companion" }
.map { it.replaceFirstChar(Char::uppercaseChar) }
@@ -779,10 +786,10 @@ internal class CodeWriter(
val aliasNames = mutableMapOf<String, T>()
var segmentsToUse = 0
// Iterate until we have unique aliases for all names.
- while (aliasNames.size != qualifiedNames.size) {
+ while (aliasNames.size != canonicalNamesToQualifiedNames.size) {
segmentsToUse += 1
aliasNames.clear()
- for ((qualifiedName, segments) in canonicalNameSegments) {
+ for ((segments, qualifiedName) in canonicalNameSegmentsToQualifiedNames) {
val aliasPrefix = segments.takeLast(min(segmentsToUse, segments.size))
.joinToString(separator = "")
.replaceFirstChar { if (!capitalizeAliases) it.lowercaseChar() else it }
diff --git a/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/MemberNameTest.kt b/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/MemberNameTest.kt
index b680aaac..04eaa536 100644
--- a/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/MemberNameTest.kt
+++ b/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/MemberNameTest.kt
@@ -657,4 +657,29 @@ class MemberNameTest {
""".trimIndent(),
)
}
+
+ // https://github.com/square/kotlinpoet/issues/1907
+ @Test fun `extension and non-extension MemberName clash`() {
+ val file = FileSpec.builder("com.squareup.tacos", "Tacos")
+ .addFunction(
+ FunSpec.builder("main")
+ .addStatement("println(%M(Taco()))", MemberName("com.squareup.wrappers", "wrap"))
+ .addStatement("println(Taco().%M())", MemberName("com.squareup.wrappers", "wrap", isExtension = true))
+ .build(),
+ )
+ .build()
+ assertThat(file.toString()).isEqualTo(
+ """
+ package com.squareup.tacos
+
+ import com.squareup.wrappers.wrap
+
+ public fun main() {
+ println(wrap(Taco()))
+ println(Taco().wrap())
+ }
+
+ """.trimIndent(),
+ )
+ }
}