From 6238efa3efdb6a40b6e68be8231e8e0d720cbc0a Mon Sep 17 00:00:00 2001 From: Nikita Biriukov Date: Thu, 27 Jun 2024 15:01:36 +0200 Subject: [PATCH] [gradle][kotlin] IDEA-354292 adds a run button for some other cases of task declaration - `val taskName by tasks.registering {}` - `val taskName by tasks.registering(Task::class) {}` - `var taskName by tasks.creating {}` - `var taskName by tasks.creating(Task::class) {}` GitOrigin-RevId: 0d90887e356d35a6f19dc76d62ecd9937cf1a916 --- .../gradleJava/run/kotlinGradleTaskUtils.kt | 29 +++++++++++++++---- ...nGradleTaskRunConfigurationProducerTest.kt | 14 ++++++--- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/run/kotlinGradleTaskUtils.kt b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/run/kotlinGradleTaskUtils.kt index fdae16b2f54f..c8b1d5e4544b 100644 --- a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/run/kotlinGradleTaskUtils.kt +++ b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/run/kotlinGradleTaskUtils.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.api.types.symbol import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.psi.psiUtil.getPossiblyQualifiedCallExpression import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.plugins.gradle.service.execution.GradleRunConfiguration import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_PROJECT @@ -35,10 +36,15 @@ internal fun isTaskNameCandidate(element: PsiElement): Boolean = ?.parent is KtCallExpression internal fun findTaskNameAround(element: PsiElement): String? { + return findTaskNameInSurroundingCallExpression(element) + ?: findTaskNameInSurroundingProperty(element) +} + +private fun findTaskNameInSurroundingCallExpression(element: PsiElement): String? { val callExpression = element.getParentOfType(false, KtScriptInitializer::class.java) ?: return null return analyze(callExpression) { - val resolveCall = callExpression.resolveToCall() ?: return null - val functionCall = resolveCall.singleFunctionCallOrNull() ?: return null + val resolvedCall = callExpression.resolveToCall() ?: return null + val functionCall = resolvedCall.singleFunctionCallOrNull() ?: return null if (!doesCustomizeTask(functionCall)) return null val nameArgument = functionCall.argumentMapping .filter { it.value.name.identifier == "name" } @@ -50,6 +56,21 @@ internal fun findTaskNameAround(element: PsiElement): String? { } } +private fun findTaskNameInSurroundingProperty(element: PsiElement): String? { + // A property element could contain e.g., `val taskName by tasks.registering{}` or `val taskName by tasks.creating{}` + val property = element.getParentOfType(false, KtScriptInitializer::class.java) ?: return null + // `tasks.registering{}` would be a delegateExpression for the example above + val delegateExpression = property.delegateExpression ?: return null + val callExpression = delegateExpression.getPossiblyQualifiedCallExpression() ?: return null + return analyze(callExpression) { + val resolvedCall = callExpression.resolveToCall() ?: return null + val functionCall = resolvedCall.singleFunctionCallOrNull() ?: return null + if (!doesCustomizeTask(functionCall)) return null + val taskName = property.symbol.name.identifier + taskName + } +} + private fun doesCustomizeTask(functionCall: KaFunctionCall<*>): Boolean { val callableId = functionCall.partiallyAppliedSymbol.symbol.callableId ?: return false val methodName = callableId.callableName.identifier @@ -66,11 +87,9 @@ private fun getReceiverClassFqName(functionCall: KaFunctionCall<*>): FqName? { return type?.symbol?.classId?.asSingleFqName() } - private fun isMethodOfTaskContainer(methodName: String, fqClassName: FqName) = fqClassName == FqName(GRADLE_API_TASK_CONTAINER) - && (methodName == "register" || methodName == "create" || methodName == "named") - + && methodName in setOf("register", "create", "named", "registering", "creating") private fun isMethodOfProject(methodName: String, fqClassName: FqName) = (methodName == "task") && (fqClassName == FqName(GRADLE_API_PROJECT) diff --git a/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/run/gradle/AbstractKotlinGradleTaskRunConfigurationProducerTest.kt b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/run/gradle/AbstractKotlinGradleTaskRunConfigurationProducerTest.kt index e604f0d43025..74e9a13b8b4d 100644 --- a/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/run/gradle/AbstractKotlinGradleTaskRunConfigurationProducerTest.kt +++ b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/run/gradle/AbstractKotlinGradleTaskRunConfigurationProducerTest.kt @@ -19,15 +19,21 @@ abstract class AbstractKotlinGradleTaskRunConfigurationProducerTest : AbstractKo @ParameterizedTest @AllGradleVersionsSource(""" + taskName : 'task("taskName") {}', + taskName : 'project.task("taskName") {}', + taskName : 'project.tasks.register("taskName") {}', taskName : 'tasks.register("taskName") {}', taskName : 'tasks.register("taskName") {}', taskName : 'getTasks().register("taskName") {}', - taskName : 'project.task("taskName") {}', - taskName : 'task("taskName") {}', taskName : 'tasks.create("taskName") {}', taskName : 'tasks.create("taskName") {}', - help : 'tasks.named("help") {}' + help : 'tasks.named("help") {}', + + taskName : 'val taskName by tasks.registering {}', + taskName : 'val taskName by tasks.registering(Task::class) {}', + taskName : 'var taskName by tasks.creating {}', + taskName : 'var taskName by tasks.creating(Task::class) {}' """) fun testTaskHasConfiguration(gradleVersion: GradleVersion, taskName: String, taskDefinition: String) { assumeThatKotlinDslScriptsModelImportIsSupported(gradleVersion) @@ -35,7 +41,7 @@ abstract class AbstractKotlinGradleTaskRunConfigurationProducerTest : AbstractKo writeTextAndCommit("build.gradle.kts", taskDefinition) runReadActionAndWait { val buildFile = getFile("build.gradle.kts") - val configurationFromContext = getConfiguration(buildFile, project, "\"$taskName\"") + val configurationFromContext = getConfiguration(buildFile, project, taskName) val taskConfiguration = assertInstanceOf(configurationFromContext.configuration) assertEquals(listOf(taskName), taskConfiguration.settings.taskNames) assertEquals("${project.name} [$taskName]", taskConfiguration.name)