diff --git a/docs/changelog.md b/docs/changelog.md index 785d5fac49..f6917c419b 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -3,6 +3,7 @@ Change Log ## Unreleased +* 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). diff --git a/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/CodeWriter.kt b/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/CodeWriter.kt index 4921c59a9f..4fdd3b625a 100644 --- a/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/CodeWriter.kt +++ b/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/CodeWriter.kt @@ -464,11 +464,14 @@ internal class CodeWriter constructor( val simpleName = imports[memberName.canonicalName]?.alias ?: memberName.simpleName // Match an imported member. val importedMember = importedMembers[simpleName] - if (importedMember == memberName) { + val found = importedMember == memberName + if (found && !isMethodNameUsedInCurrentContext(simpleName)) { return simpleName } else if (importedMember != null && memberName.enclosingClassName != null) { val enclosingClassName = lookupName(memberName.enclosingClassName) return "$enclosingClassName.$simpleName" + } else if (found) { + return simpleName } // If the member is in the same package, we're done. diff --git a/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/MemberNameTest.kt b/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/MemberNameTest.kt index 83fb870daa..4ff7122e5e 100644 --- a/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/MemberNameTest.kt +++ b/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/MemberNameTest.kt @@ -322,6 +322,68 @@ class MemberNameTest { ) } + @Test fun importedMemberClassFunctionNameDontClashForParameterValue() { + fun createBuildFunc(params: List): FunSpec { + val tacoClassname = ClassName.bestGuess("com.squareup.tacos.Taco") + val bodyCodeBlock = CodeBlock.builder() + .add("return %T", tacoClassname) + .apply { + val paramsBlock = params.map { paramName -> + val paramValue = ClassName( + packageName = "com.squareup", + simpleNames = listOf("Fridge"), + ).member("meat") + CodeBlock.of("$paramName = %L", CodeBlock.of("%M { }", paramValue)) + } + .map { block -> CodeBlock.of("%L", block) } + .joinToCode(prefix = "(", suffix = ")") + add(paramsBlock) + } + .build() + return FunSpec.builder("build") + .returns(tacoClassname) + .addCode(bodyCodeBlock) + .build() + } + + val spec = FileSpec.builder("com.squareup.tacos", "Tacos") + .addType( + TypeSpec.classBuilder("DeliciousTaco") + .addFunction(createBuildFunc(listOf("deliciousMeat"))) + .addFunction(FunSpec.builder("deliciousMeat").build()) + .build(), + ) + .addType( + TypeSpec.classBuilder("TastelessTaco") + .addFunction(createBuildFunc(listOf("meat"))) + .addFunction(FunSpec.builder("meat").build()) + .build(), + ) + val source = spec.build() + assertThat(source.toString()).isEqualTo( + """ + |package com.squareup.tacos + | + |import com.squareup.Fridge.meat + | + |public class DeliciousTaco { + | public fun build(): Taco = Taco(deliciousMeat = meat { }) + | + | public fun deliciousMeat() { + | } + |} + | + |public class TastelessTaco { + | public fun build(): Taco = Taco(meat = com.squareup.Fridge.meat { }) + | + | public fun meat() { + | } + |} + | + """.trimMargin(), + ) + } + @Test fun memberNameAliases() { val createSquareTaco = MemberName("com.squareup.tacos", "createTaco") val createTwitterTaco = MemberName("com.twitter.tacos", "createTaco")