[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
This commit is contained in:
Nikita Biriukov
2024-06-27 15:01:36 +02:00
committed by intellij-monorepo-bot
parent 4e2ea6ba8c
commit 6238efa3ef
2 changed files with 34 additions and 9 deletions

View File

@@ -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<KtCallExpression>(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<KtProperty>(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)

View File

@@ -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<Task>("taskName") {}',
taskName : 'getTasks().register("taskName") {}',
taskName : 'project.task("taskName") {}',
taskName : 'task("taskName") {}',
taskName : 'tasks.create("taskName") {}',
taskName : 'tasks.create<Task>("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<GradleRunConfiguration>(configurationFromContext.configuration)
assertEquals(listOf(taskName), taskConfiguration.settings.taskNames)
assertEquals("${project.name} [$taskName]", taskConfiguration.name)