mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] KTIJ-33536 improve pluginId gradle reference resolution
- Refactor `AbstractKotlinGradleReferenceProvider` for cleaner callable ID resolution. - Add validation for plugin ID references in `KotlinGradlePluginReferenceProvider`. Space-RevId: d8c74cde694f4d1a26b994021faeff84dca3c202 Merge-request: IJ-MR-188765 Merged-by: Vlad Koshkin <Vladislav.Koshkin@jetbrains.com> GitOrigin-RevId: 2195094d9b0282ed8bc3e361e05c3fc3e5ac87c1
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ab4a557c86
commit
6561f4fb44
+1
-2
@@ -34,8 +34,7 @@ abstract class AbstractKotlinGradleReferenceProvider: ImplicitReferenceProvider
|
||||
val callExpression = element?.getParentOfType<KtCallExpression>(true, KtDeclarationWithBody::class.java) ?: return null
|
||||
return allowAnalysisOnEdt {
|
||||
analyze(callExpression) {
|
||||
val singleFunctionCallOrNull = callExpression.resolveToCall()?.singleFunctionCallOrNull()
|
||||
singleFunctionCallOrNull?.symbol?.callableId
|
||||
callExpression.resolveToCall()?.singleFunctionCallOrNull()?.symbol?.callableId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+66
-7
@@ -1,24 +1,83 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.gradleCodeInsightCommon
|
||||
|
||||
import com.intellij.lang.parameterInfo.ParameterInfoUtils.findParentOfType
|
||||
import com.intellij.model.psi.PsiSymbolReference
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisOnEdt
|
||||
import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisOnEdt
|
||||
import org.jetbrains.kotlin.analysis.api.resolution.singleFunctionCallOrNull
|
||||
import org.jetbrains.kotlin.analysis.api.resolution.singleVariableAccessCall
|
||||
import org.jetbrains.kotlin.analysis.api.resolution.symbol
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.plugins.gradle.service.resolve.GradlePluginReference
|
||||
|
||||
private val GRADLE_DSL_ID: Name = Name.identifier("id")
|
||||
private val PLUGIN_DEPENDENCIES_SPEC = FqName("PluginDependenciesSpec")
|
||||
|
||||
private val KOTLIN_PROJECT_SCRIPT_TEMPLATE = FqName("KotlinProjectScriptTemplate")
|
||||
private val PLUGINS: Name = Name.identifier("plugins")
|
||||
|
||||
class KotlinGradlePluginReferenceProvider : AbstractKotlinGradleReferenceProvider() {
|
||||
@OptIn(KaAllowAnalysisOnEdt::class)
|
||||
override fun getImplicitReference(
|
||||
element: PsiElement,
|
||||
offsetInElement: Int
|
||||
): PsiSymbolReference? {
|
||||
val text = getTextFromLiteralEntry(element.parent) ?: return null
|
||||
val callableId = analyzeSurroundingCallExpression(element.parent) ?: return null
|
||||
if (callableId.packageName != GRADLE_DSL_PACKAGE || callableId.callableName != GRADLE_DSL_ID) return null
|
||||
|
||||
val length = element.textRange.length
|
||||
return GradlePluginReference(element, TextRange(0, length), text)
|
||||
): PsiSymbolReference? = when (element) {
|
||||
is KtNameReferenceExpression -> createFromNameReference(element)
|
||||
is KtCallExpression -> createFromCall(element)
|
||||
else -> null
|
||||
}
|
||||
|
||||
@OptIn(KaAllowAnalysisOnEdt::class)
|
||||
private fun createFromCall(element: KtCallExpression): GradlePluginReference? {
|
||||
val maybePluginId = getSingleFunctionCallableId(element)
|
||||
if (maybePluginId == null || !maybePluginId.isPluginId()) return null
|
||||
|
||||
val literal = PsiTreeUtil.findChildOfType(element, KtLiteralStringTemplateEntry::class.java) ?: return null
|
||||
val range = TextRange(0, literal.textRange.length)
|
||||
|
||||
return GradlePluginReference(literal, range, literal.text)
|
||||
}
|
||||
|
||||
@OptIn(KaAllowAnalysisOnEdt::class)
|
||||
private fun createFromNameReference(element: KtNameReferenceExpression): GradlePluginReference? {
|
||||
val parentCallExpression = findParentOfType(element, KtCallExpression::class.java) ?: return null
|
||||
val maybePluginsSection = getSingleFunctionCallableId(parentCallExpression)
|
||||
if (maybePluginsSection == null || !maybePluginsSection.isPluginsSection()) return null
|
||||
|
||||
val pluginCallableId = getSingleVariableCallableId(element)
|
||||
if (pluginCallableId == null || pluginCallableId.packageName != GRADLE_DSL_PACKAGE) return null
|
||||
|
||||
val range = TextRange(0, element.textRange.length)
|
||||
return GradlePluginReference(element, range, pluginCallableId.callableName.identifier)
|
||||
}
|
||||
|
||||
@OptIn(KaAllowAnalysisOnEdt::class)
|
||||
private fun getSingleFunctionCallableId(callExpression: KtCallExpression) = allowAnalysisOnEdt {
|
||||
analyze(callExpression) {
|
||||
callExpression.resolveToCall()?.singleFunctionCallOrNull()?.symbol?.callableId
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(KaAllowAnalysisOnEdt::class)
|
||||
private fun getSingleVariableCallableId(nameReferenceExpression: KtNameReferenceExpression) = allowAnalysisOnEdt {
|
||||
analyze(nameReferenceExpression) {
|
||||
nameReferenceExpression.resolveToCall()?.singleVariableAccessCall()?.symbol?.callableId
|
||||
}
|
||||
}
|
||||
|
||||
private fun CallableId.isPluginsSection(): Boolean =
|
||||
callableName == PLUGINS && className == KOTLIN_PROJECT_SCRIPT_TEMPLATE
|
||||
|
||||
private fun CallableId.isPluginId(): Boolean =
|
||||
callableName == GRADLE_DSL_ID && (packageName == GRADLE_DSL_PACKAGE || className == PLUGIN_DEPENDENCIES_SPEC)
|
||||
}
|
||||
+42
-17
@@ -20,7 +20,7 @@ import org.junit.jupiter.params.ParameterizedTest
|
||||
@GradleProjectTestApplication
|
||||
@AssertKotlinPluginMode
|
||||
@TestRoot("idea/tests/testData/")
|
||||
@TestDataPath("\$CONTENT_ROOT")
|
||||
@TestDataPath($$"$CONTENT_ROOT")
|
||||
@TestMetadata("../../../idea/tests/testData/gradle/navigation/composite")
|
||||
class K2GradleBuildLogicPluginNavigationTest : AbstractKotlinGradleNavigationTest() {
|
||||
@ParameterizedTest
|
||||
@@ -37,31 +37,56 @@ class K2GradleBuildLogicPluginNavigationTest : AbstractKotlinGradleNavigationTes
|
||||
verifyFileShouldStayTheSame(gradleVersion)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
@TestMetadata("testNavigationToBacktickedSettingsPluginFromSettingsGradleKts.test")
|
||||
fun testNavigationToBacktickedSettingsPluginFromSettingsGradleKts(gradleVersion: GradleVersion) {
|
||||
verifyNavigationFromCaretToExpected(gradleVersion)
|
||||
}
|
||||
|
||||
override val myFixture = FIXTURE_WITH_SETTINGS_PLUGIN
|
||||
|
||||
companion object {
|
||||
private val FIXTURE_WITH_SETTINGS_PLUGIN: GradleTestFixtureBuilder =
|
||||
GradleTestFixtureBuilder.create("GradleKotlinFixture") { gradleVersion ->
|
||||
withSettingsFile(gradleVersion, gradleDsl = GradleDsl.KOTLIN) {
|
||||
setProjectName("GradleKotlinFixture")
|
||||
}
|
||||
withBuildFile(gradleVersion, gradleDsl = GradleDsl.KOTLIN) {
|
||||
"""
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
""".trimIndent()
|
||||
withBuildFile(gradleVersion, "buildSrc", gradleDsl = GradleDsl.KOTLIN) {
|
||||
withKotlinDsl()
|
||||
}
|
||||
|
||||
withSettingsFile(gradleVersion, "custom", gradleDsl = GradleDsl.KOTLIN) {}
|
||||
withBuildFile(gradleVersion, "custom", gradleDsl = GradleDsl.KOTLIN) {
|
||||
"""
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
withFile(
|
||||
"buildSrc/src/main/kotlin/my-conventions.gradle.kts", """
|
||||
val fromBuildSrc = "my-conventions.gradle.kts"
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
withBuildFile(gradleVersion, gradleDsl = GradleDsl.KOTLIN) {
|
||||
withPlugin {
|
||||
code("`my-conventions`")
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
withFile("custom/src/main/kotlin/custom.settings.settings.gradle.kts", "")
|
||||
|
||||
withSettingsFile(gradleVersion, gradleDsl = GradleDsl.KOTLIN) {
|
||||
addCode("""
|
||||
pluginManagement {
|
||||
includeBuild("custom")
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("custom.settings")
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
withBuildFile(gradleVersion, "custom", gradleDsl = GradleDsl.KOTLIN) {
|
||||
withKotlinDsl()
|
||||
}
|
||||
|
||||
withFile(
|
||||
"custom/src/main/kotlin/custom.settings.settings.gradle.kts", """
|
||||
val fromCustomSettingsPlugin = "custom.settings.settings.gradle.kts"
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// FILE: build.gradle.kts
|
||||
// "EXPECTED-NAVIGATION-SUBSTRING": "val fromBuildSrc = "my-conventions.gradle.kts""
|
||||
plugins {
|
||||
`my-<caret>conventions`
|
||||
}
|
||||
+1
-4
@@ -1,8 +1,5 @@
|
||||
// FILE: settings.gradle.kts
|
||||
// "EXPECTED-NAVIGATION-SUBSTRING": "println("custom")"
|
||||
// "EXPECTED-NAVIGATION-SUBSTRING": "val fromCustomSettingsPlugin = "custom.settings.settings.gradle.kts""
|
||||
plugins {
|
||||
id("custom<caret>.settings")
|
||||
}
|
||||
|
||||
// FILE: custom/src/main/kotlin/custom.settings.settings.gradle.kts
|
||||
println("custom")
|
||||
|
||||
-3
@@ -3,6 +3,3 @@
|
||||
plugins {
|
||||
id("custom<caret>.settings")
|
||||
}
|
||||
|
||||
// FILE: custom/src/main/kotlin/custom.settings.settings.gradle.kts
|
||||
println("custom")
|
||||
Reference in New Issue
Block a user