Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent name clashes between a function in class and a function call in current scope. #1850

Merged
merged 3 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,68 @@ class MemberNameTest {
)
}

@Test fun importedMemberClassFunctionNameDontClashForParameterValue() {
fun createBuildFunc(params: List<String>): 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")))
ivk1800 marked this conversation as resolved.
Show resolved Hide resolved
.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")
Expand Down