Skip to content

Commit

Permalink
Gracefully handle lambdas registered as extensions
Browse files Browse the repository at this point in the history
Signed-off-by: Paul Merlin <paul@gradle.com>
  • Loading branch information
eskatos committed Sep 17, 2019
1 parent f417ee1 commit fc6ecc5
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 3 deletions.
Expand Up @@ -1232,6 +1232,143 @@ class ProjectSchemaAccessorsIntegrationTest : AbstractPluginIntegrationTest() {
)
}

@Test
fun `accessors to local groovy closures extensions are typed Any`() {
requireGradleDistributionOnEmbeddedExecuter()

withDefaultSettings()
withFile("buildSrc/build.gradle", """
plugins {
id("groovy")
id("java-gradle-plugin")
}
dependencies {
implementation(localGroovy())
}
gradlePlugin {
plugins {
my {
id = "my"
implementationClass = "my.MyPlugin"
}
}
}
""".trimIndent())
withFile("buildSrc/src/main/groovy/my/MyPlugin.groovy", """
package my
import org.gradle.api.*
class MyPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.add("closureExtension", { String name ->
name.toUpperCase()
})
}
}
""")
withBuildScript("""
plugins {
my
}
inline fun <reified T> typeOf(value: T) = typeOf<T>()
println("closureExtension: " + typeOf(closureExtension))
val casted = closureExtension as groovy.lang.Closure<*>
println(casted.call("some"))
""")

build("help").apply {
assertOutputContains("closureExtension: java.lang.Object")
assertOutputContains("SOME")
}
}

@Test
fun `accessors to local kotlin lambda extensions are typed Any`() {
requireGradleDistributionOnEmbeddedExecuter()

withDefaultSettings()
withKotlinBuildSrc()
withFile("buildSrc/src/main/kotlin/my.gradle.kts", """
extensions.add("lambdaExtension", { name: String ->
name.toUpperCase()
})
""")
withBuildScript("""
plugins {
my
}
inline fun <reified T> typeOf(value: T) = typeOf<T>()
println("lambdaExtension: " + typeOf(lambdaExtension))
val casted = lambdaExtension as (String) -> String
println(casted.invoke("some"))
""")

build("help").apply {
assertOutputContains("lambdaExtension: java.lang.Object")
assertOutputContains("SOME")
}
}

@Test
fun `accessors to local java lambda extensions are typed Any`() {
requireGradleDistributionOnEmbeddedExecuter()

withDefaultSettings()
withFile("buildSrc/build.gradle", """
plugins {
id("java")
id("java-gradle-plugin")
}
gradlePlugin {
plugins {
my {
id = "my"
implementationClass = "my.MyPlugin"
}
}
}
""")
withFile("buildSrc/src/main/java/my/MyPlugin.java", """
package my;
import org.gradle.api.*;
import java.util.function.Function;
public class MyPlugin implements Plugin<Project> {
public void apply(Project project) {
Function<String, String> lambda = s -> s.toUpperCase();
project.getExtensions().add("lambdaExtension", lambda);
}
}
""")
withBuildScript("""
import java.util.function.Function
plugins {
my
}
inline fun <reified T> typeOf(value: T) = typeOf<T>()
println("lambdaExtension: " + typeOf(lambdaExtension))
val casted = lambdaExtension as Function<String, String>
println(casted.apply("some"))
""")

build("help").apply {
assertOutputContains("lambdaExtension: java.lang.Object")
assertOutputContains("SOME")
}
}

private
fun withBuildSrc(contents: FoldersDslExpression) {
withFolders {
Expand Down
Expand Up @@ -38,7 +38,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult

import kotlin.reflect.KClass
import kotlin.reflect.KVisibility
import kotlin.reflect.full.superclasses

import java.lang.reflect.Modifier


class DefaultProjectSchemaProvider : ProjectSchemaProvider {
Expand Down Expand Up @@ -149,8 +150,19 @@ val KClass<*>.firstKotlinPublicOrSelf

private
val KClass<*>.firstKotlinPublicOrNull: KClass<*>?
get() = takeIf { visibility == KVisibility.PUBLIC }
?: superclasses.firstNotNullResult { it.firstKotlinPublicOrNull }
get() = takeIf { isJavaPublic && isKotlinVisible && visibility == KVisibility.PUBLIC }
?: (java.superclass as Class<*>?)?.kotlin?.firstKotlinPublicOrNull
?: java.interfaces.firstNotNullResult { it.kotlin.firstKotlinPublicOrNull }


private
val KClass<*>.isJavaPublic
get() = Modifier.isPublic(java.modifiers)


private
val KClass<*>.isKotlinVisible: Boolean
get() = !java.isLocalClass && !java.isAnonymousClass && !java.isSynthetic


private
Expand Down

0 comments on commit fc6ecc5

Please sign in to comment.