mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-04 23:39:07 +07:00
[gradle] Enable find usages and references in version catalog toml files
GitOrigin-RevId: 093c10b45b965b1167a1d766a7f67c2c2ac1e22b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
496e6115ec
commit
019151b7ad
@@ -30,6 +30,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.jps.model.impl" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.properties.psi" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.toml" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.gradle.analysis" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="kotlinx-coroutines-jdk8" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<!--<elementDescriptionProvider implementation="org.jetbrains.plugins.gradle.toml.navigation.VersionCatalogDescriptionProvider"/>-->
|
||||
<!--<findUsagesHandlerFactory implementation="org.jetbrains.plugins.gradle.toml.findUsages.GradleVersionCatalogFindUsagesFactory"/>-->
|
||||
<!--<psi.referenceContributor language="TOML"-->
|
||||
<!-- implementation="org.jetbrains.plugins.gradle.toml.navigation.VersionCatalogReferenceContributor"/>-->
|
||||
<findUsagesHandlerFactory implementation="org.jetbrains.plugins.gradle.toml.findUsages.GradleVersionCatalogFindUsagesFactory"/>
|
||||
<psi.referenceContributor language="TOML"
|
||||
implementation="org.jetbrains.plugins.gradle.toml.navigation.VersionCatalogReferenceContributor"/>
|
||||
<!--<renameInputValidator implementation="org.jetbrains.plugins.gradle.toml.navigation.VersionCatalogRenameInputValidator"/>-->
|
||||
|
||||
<!--<typedHandler implementation="org.jetbrains.plugins.gradle.toml.completion.VersionCatalogTypedHandler" id="tomlVersionCatalogAuto"/>-->
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gradle.config
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.plugins.gradle.codeInspection.GradleInspectionBundle
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
|
||||
class GradleBuildscriptSearchScope(project: Project) : GlobalSearchScope(project) {
|
||||
override fun contains(file: VirtualFile): Boolean {
|
||||
return GradleConstants.EXTENSION == file.extension || file.name.endsWith(GradleConstants.KOTLIN_DSL_SCRIPT_EXTENSION)
|
||||
}
|
||||
override fun isSearchInModuleContent(aModule: Module) = true
|
||||
override fun isSearchInLibraries() = false
|
||||
|
||||
override fun getDisplayName(): String {
|
||||
return GradleInspectionBundle.message("gradle.buildscript.search.scope")
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementFinder
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.search.UseScopeEnlarger
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
@@ -45,13 +44,7 @@ class GradleUseScopeEnlarger : UseScopeEnlarger() {
|
||||
if (!isInBuildSrc(project, virtualFile) && !isInGradleDistribution(project, virtualFile)) return null
|
||||
|
||||
|
||||
return object : GlobalSearchScope(element.project) {
|
||||
override fun contains(file: VirtualFile): Boolean {
|
||||
return GradleConstants.EXTENSION == file.extension || file.name.endsWith(GradleConstants.KOTLIN_DSL_SCRIPT_EXTENSION)
|
||||
}
|
||||
override fun isSearchInModuleContent(aModule: Module) = true
|
||||
override fun isSearchInLibraries() = false
|
||||
}
|
||||
return GradleBuildscriptSearchScope(element.project)
|
||||
}
|
||||
|
||||
private fun isInGradleDistribution(project: Project, file: VirtualFile) : Boolean {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gradle.toml.findUsages
|
||||
|
||||
import com.intellij.find.findUsages.FindUsagesHandler
|
||||
import com.intellij.find.findUsages.FindUsagesHandlerFactory
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.toml.lang.psi.TomlKeySegment
|
||||
|
||||
class GradleVersionCatalogFindUsagesFactory : FindUsagesHandlerFactory() {
|
||||
override fun canFindUsages(element: PsiElement): Boolean {
|
||||
return element is TomlKeySegment
|
||||
}
|
||||
|
||||
override fun createFindUsagesHandler(element: PsiElement, forHighlightUsages: Boolean): FindUsagesHandler {
|
||||
if (forHighlightUsages) {
|
||||
return FindUsagesHandler.NULL_HANDLER
|
||||
}
|
||||
return GradleVersionCatalogFindUsagesHandler(element as TomlKeySegment)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gradle.toml.findUsages
|
||||
|
||||
import com.intellij.find.findUsages.FindUsagesHandler
|
||||
import com.intellij.find.findUsages.FindUsagesOptions
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.plugins.gradle.codeInspection.GradleInspectionBundle
|
||||
import org.jetbrains.plugins.gradle.config.GradleBuildscriptSearchScope
|
||||
import org.toml.lang.psi.TomlKeySegment
|
||||
|
||||
class GradleVersionCatalogFindUsagesHandler(private val tomlElement: TomlKeySegment) : FindUsagesHandler(tomlElement) {
|
||||
|
||||
override fun getFindUsagesOptions(dataContext: DataContext?): FindUsagesOptions {
|
||||
val superOptions = super.getFindUsagesOptions(dataContext)
|
||||
superOptions.searchScope = VersionCatalogSearchScope(tomlElement)
|
||||
return superOptions
|
||||
}
|
||||
|
||||
private class VersionCatalogSearchScope(context: PsiElement) : GlobalSearchScope(context.project) {
|
||||
private val buildscriptScope = GradleBuildscriptSearchScope(context.project)
|
||||
private val tomlScope = fileScope(context.containingFile)
|
||||
|
||||
override fun contains(file: VirtualFile): Boolean = buildscriptScope.contains(file) || tomlScope.contains(file)
|
||||
|
||||
override fun isSearchInModuleContent(aModule: Module): Boolean = buildscriptScope.isSearchInModuleContent(aModule)
|
||||
|
||||
override fun isSearchInLibraries(): Boolean = buildscriptScope.isSearchInLibraries
|
||||
|
||||
override fun getDisplayName(): String {
|
||||
return GradleInspectionBundle.message("gradle.version.catalog.search.scope")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gradle.toml.navigation
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.patterns.ElementPattern
|
||||
import com.intellij.patterns.PatternCondition
|
||||
import com.intellij.patterns.PlatformPatterns
|
||||
import com.intellij.patterns.PsiElementPattern
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.util.ProcessingContext
|
||||
import com.intellij.util.asSafely
|
||||
import org.jetbrains.plugins.gradle.toml.getVersions
|
||||
import org.toml.lang.psi.TomlInlineTable
|
||||
import org.toml.lang.psi.TomlKeyValue
|
||||
import org.toml.lang.psi.TomlLiteral
|
||||
import org.toml.lang.psi.TomlValue
|
||||
|
||||
class VersionCatalogReferenceContributor : PsiReferenceContributor() {
|
||||
|
||||
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||
registrar.registerReferenceProvider(versionRefPattern, VersionCatalogReferenceProvider())
|
||||
}
|
||||
}
|
||||
|
||||
internal val refKeyValuePattern: PsiElementPattern.Capture<TomlKeyValue> = PlatformPatterns
|
||||
.psiElement(TomlKeyValue::class.java)
|
||||
.with(RefPatternCondition())
|
||||
internal val versionRefPattern: ElementPattern<TomlValue> = PlatformPatterns
|
||||
.psiElement(TomlValue::class.java)
|
||||
.withParent(refKeyValuePattern)
|
||||
|
||||
private class RefPatternCondition : PatternCondition<TomlKeyValue>("'ref' key value") {
|
||||
override fun accepts(t: TomlKeyValue, context: ProcessingContext?): Boolean {
|
||||
val segments = t.key.segments
|
||||
if (segments.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
if (segments.last().name != "ref") {
|
||||
return false
|
||||
}
|
||||
if (segments.size == 1) {
|
||||
return t.parent?.asSafely<TomlInlineTable>()?.parent?.asSafely<TomlKeyValue>()
|
||||
?.takeIf { it.key.segments.lastOrNull()?.name == "version" } != null
|
||||
} else {
|
||||
return segments.asReversed()[1].name == "version"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class VersionCatalogReferenceProvider : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
|
||||
if (element !is TomlLiteral) {
|
||||
return emptyArray()
|
||||
}
|
||||
val text = StringUtil.unquoteString(element.text)
|
||||
return arrayOf(VersionCatalogVersionReference(element, text))
|
||||
}
|
||||
|
||||
private class VersionCatalogVersionReference(literal: TomlLiteral, val text: String) : PsiReferenceBase<TomlLiteral>(literal) {
|
||||
override fun resolve(): PsiElement? {
|
||||
val versions = getVersions(element)
|
||||
return versions.find { it.name == text }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
166
plugins/gradle/java/src/toml/util.kt
Normal file
166
plugins/gradle/java/src/toml/util.kt
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gradle.toml
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.childrenOfType
|
||||
import com.intellij.util.asSafely
|
||||
import com.intellij.util.containers.tail
|
||||
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames
|
||||
import org.jetbrains.plugins.gradle.service.resolve.VersionCatalogsLocator
|
||||
import org.jetbrains.plugins.gradle.service.resolve.getVersionCatalogFiles
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils
|
||||
import org.toml.lang.psi.*
|
||||
import org.toml.lang.psi.ext.name
|
||||
|
||||
internal fun getVersions(context: PsiElement) : List<TomlKeySegment> {
|
||||
val file = context.containingFile.asSafely<TomlFile>() ?: return emptyList()
|
||||
val targetTable = file.childrenOfType<TomlTable>().find { it.header.key?.name == "versions" } ?: return emptyList()
|
||||
return targetTable.childrenOfType<TomlKeyValue>().mapNotNull { it.key.segments.singleOrNull() }
|
||||
}
|
||||
|
||||
|
||||
internal fun String.getVersionCatalogParts() : List<String> = split("_", "-")
|
||||
|
||||
internal fun findTomlFile(context: PsiElement, name: String) : TomlFile? {
|
||||
val file = getVersionCatalogFiles(context.project)[name] ?: return null
|
||||
return PsiManager.getInstance(context.project).findFile(file)?.asSafely<TomlFile>()
|
||||
}
|
||||
|
||||
private fun findTomlFileDynamically(context: PsiElement, name: String): VirtualFile? {
|
||||
val module = context.containingFile?.originalFile?.virtualFile?.let {
|
||||
ProjectFileIndex.getInstance(context.project).getModuleForFile(it)
|
||||
} ?: return null
|
||||
val tomlPath = context.project.service<VersionCatalogsLocator>().getVersionCatalogsForModule(module)[name] ?: return null
|
||||
return VfsUtil.findFile(tomlPath, false)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param method a method within a synthetic version catalog accessor class. The method must not return an accessor (i.e. it should be a leaf method).
|
||||
* @param context a context element within any gradle buildscript.
|
||||
* @return an element within TOML file, that describes [method]
|
||||
*/
|
||||
fun findOriginInTomlFile(method: PsiMethod, context: PsiElement): PsiElement? {
|
||||
val containingClasses = mutableListOf(method.containingClass ?: return null)
|
||||
while (containingClasses.last().containingClass != null) {
|
||||
containingClasses.add(containingClasses.last().containingClass!!)
|
||||
}
|
||||
containingClasses.reverse()
|
||||
val name = containingClasses.first().name?.substringAfter(LIBRARIES_FOR_PREFIX) ?: return null
|
||||
val toml = listOf(StringUtil.decapitalize(name), name).firstNotNullOfOrNull { findTomlFile(context, it) }
|
||||
?: return null
|
||||
val tomlVisitor = TomlVersionCatalogVisitor(containingClasses.tail(), method)
|
||||
toml.accept(tomlVisitor)
|
||||
return tomlVisitor.resolveTarget
|
||||
}
|
||||
|
||||
private class TomlVersionCatalogVisitor(containingClasses: List<PsiClass>, val targetMethod: PsiMethod) : TomlRecursiveVisitor() {
|
||||
private val containingClasses: MutableList<PsiClass> = ArrayList(containingClasses)
|
||||
var resolveTarget: PsiElement? = null
|
||||
|
||||
override fun visitTable(element: TomlTable) {
|
||||
val headerKind = element.header.key?.segments?.singleOrNull()?.name?.getTomlHeaderKind() ?: return
|
||||
val firstClass = containingClasses.firstOrNull()
|
||||
if (firstClass != null) {
|
||||
val firstClassKind = firstClass.getTomlHeaderKind() ?: return
|
||||
if (headerKind != firstClassKind) {
|
||||
return
|
||||
}
|
||||
if (targetMethod.returnType?.asSafely<PsiClassType>()?.resolve()?.qualifiedName != GradleCommonClassNames.GRADLE_API_PROVIDER_PROVIDER) {
|
||||
return
|
||||
}
|
||||
return resolveAsComponent(element.entries)
|
||||
}
|
||||
else {
|
||||
when (targetMethod.name) {
|
||||
METHOD_GET_PLUGINS -> if (headerKind == TomlHeaderKind.PLUGINS) resolveTarget = element else return
|
||||
METHOD_GET_BUNDLES -> if (headerKind == TomlHeaderKind.BUNDLES) resolveTarget = element else return
|
||||
METHOD_GET_VERSIONS -> if (headerKind == TomlHeaderKind.VERSIONS) resolveTarget = element else return
|
||||
else -> if (headerKind == TomlHeaderKind.LIBRARIES) resolveAsComponent(element.entries) else return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveAsComponent(values: List<TomlKeyValue>) {
|
||||
val camelCasedName = getCapitalizedAccessorName(targetMethod)
|
||||
for (tomlEntry in values) {
|
||||
val keyName =
|
||||
tomlEntry.key.segments.firstOrNull()?.name?.getVersionCatalogParts()?.joinToString("", transform = StringUtil::capitalize)
|
||||
?: continue
|
||||
if (camelCasedName == keyName) {
|
||||
resolveTarget = tomlEntry
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getCapitalizedAccessorName(method: PsiMethod): String? {
|
||||
val propertyName = GroovyPropertyUtils.getPropertyName(method) ?: return null
|
||||
val methodFinalPart = GroovyPropertyUtils.capitalize(propertyName)
|
||||
val methodParts = method.containingClass?.takeUnless { it.name?.startsWith(
|
||||
LIBRARIES_FOR_PREFIX) == true }?.name?.trimAccessorName()
|
||||
return (methodParts ?: "") + methodFinalPart
|
||||
}
|
||||
|
||||
|
||||
private fun String.trimAccessorName(): String {
|
||||
for (suffix in listOf(BUNDLE_ACCESSORS_SUFFIX,
|
||||
LIBRARY_ACCESSORS_SUFFIX,
|
||||
PLUGIN_ACCESSORS_SUFFIX,
|
||||
VERSION_ACCESSORS_SUFFIX)) {
|
||||
if (endsWith(suffix)) return substringBeforeLast(suffix)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
private enum class TomlHeaderKind {
|
||||
VERSIONS,
|
||||
BUNDLES,
|
||||
LIBRARIES,
|
||||
PLUGINS
|
||||
}
|
||||
|
||||
private fun PsiClass.getTomlHeaderKind(): TomlHeaderKind? {
|
||||
val name = name ?: return null
|
||||
return when {
|
||||
name.endsWith(VERSION_ACCESSORS_SUFFIX) -> TomlHeaderKind.VERSIONS
|
||||
name.endsWith(BUNDLE_ACCESSORS_SUFFIX) -> TomlHeaderKind.BUNDLES
|
||||
name.endsWith(PLUGIN_ACCESSORS_SUFFIX) -> TomlHeaderKind.PLUGINS
|
||||
name.endsWith(LIBRARY_ACCESSORS_SUFFIX) -> TomlHeaderKind.LIBRARIES
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.getTomlHeaderKind(): TomlHeaderKind? =
|
||||
when (this) {
|
||||
TOML_TABLE_VERSIONS -> TomlHeaderKind.VERSIONS
|
||||
TOML_TABLE_LIBRARIES -> TomlHeaderKind.LIBRARIES
|
||||
TOML_TABLE_BUNDLES -> TomlHeaderKind.BUNDLES
|
||||
TOML_TABLE_PLUGINS -> TomlHeaderKind.PLUGINS
|
||||
else -> null
|
||||
}
|
||||
|
||||
private const val TOML_TABLE_VERSIONS = "versions"
|
||||
private const val TOML_TABLE_LIBRARIES = "libraries"
|
||||
private const val TOML_TABLE_BUNDLES = "bundles"
|
||||
private const val TOML_TABLE_PLUGINS = "plugins"
|
||||
|
||||
private const val METHOD_GET_PLUGINS = "getPlugins"
|
||||
private const val METHOD_GET_VERSIONS = "getVersions"
|
||||
private const val METHOD_GET_BUNDLES = "getBundles"
|
||||
|
||||
|
||||
internal const val BUNDLE_ACCESSORS_SUFFIX = "BundleAccessors"
|
||||
internal const val LIBRARY_ACCESSORS_SUFFIX = "LibraryAccessors"
|
||||
internal const val PLUGIN_ACCESSORS_SUFFIX = "PluginAccessors"
|
||||
internal const val VERSION_ACCESSORS_SUFFIX = "VersionAccessors"
|
||||
|
||||
internal const val LIBRARIES_FOR_PREFIX = "LibrariesFor"
|
||||
@@ -31,7 +31,7 @@ class GradleCompletionTest : GradleCodeInsightTestCase() {
|
||||
@BaseGradleVersionSource
|
||||
fun testGrayOutForeignCompletionElement(gradleVersion: GradleVersion) {
|
||||
testJavaProject(gradleVersion) {
|
||||
testCompletion("repositories { mavenCentral { go<caret> } }") {
|
||||
testCompletion("build.gradle", "repositories { mavenCentral { go<caret> } }") {
|
||||
var hasGoogle = false
|
||||
for (element in it) {
|
||||
if (element.lookupString != "google") {
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gradle.dsl.versionCatalogs
|
||||
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.plugins.gradle.testFramework.GradleCodeInsightTestCase
|
||||
import org.jetbrains.plugins.gradle.testFramework.GradleTestFixtureBuilder
|
||||
import org.jetbrains.plugins.gradle.testFramework.annotations.BaseGradleVersionSource
|
||||
import org.jetbrains.plugins.gradle.testFramework.util.withSettingsFile
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
|
||||
import org.junit.jupiter.api.Assertions.assertInstanceOf
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.toml.lang.psi.TomlFile
|
||||
import org.toml.lang.psi.TomlKeyValue
|
||||
import org.toml.lang.psi.TomlTable
|
||||
|
||||
class GradleVersionCatalogsResolveTest : GradleCodeInsightTestCase() {
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testNavigationToTomlFile(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
testGotoDefinition("lib<caret>s") {
|
||||
assertInstanceOf(TomlFile::class.java, it)
|
||||
assertTrue((it as TomlFile).name == "libs.versions.toml")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testNavigationToTomlFile2(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
testGotoDefinition("lib<caret>s2") {
|
||||
assertInstanceOf(GroovyPsiElement::class.java, it)
|
||||
assertTrue(it.parentOfType<GrMethodCall>(true)!!.resolveMethod()!!.name == "libs2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testNavigationToCustomCatalog(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
testGotoDefinition("lib<caret>s3") {
|
||||
assertInstanceOf(GroovyPsiElement::class.java, it)
|
||||
assertTrue(it.parentOfType<GrMethodCall>(true)!!.resolveMethod()!!.name == "libs3")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testNavigationToTomlEntry(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
testGotoDefinition("libs.groovy.cor<caret>e") {
|
||||
assertInstanceOf(TomlKeyValue::class.java, it)
|
||||
assertTrue((it as TomlKeyValue).key.text == "groovy-core")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testNavigationToTomlEntry2(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
testGotoDefinition("libs.groo<caret>vy.core") {
|
||||
assertInstanceOf(TomlKeyValue::class.java, it)
|
||||
assertTrue((it as TomlKeyValue).key.text == "groovy-core")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testNavigationToTomlTable(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
testGotoDefinition("libs.bun<caret>dles") {
|
||||
assertInstanceOf(TomlTable::class.java, it)
|
||||
assertTrue((it as TomlTable).header.text == "[bundles]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testNavigationToLibraryInSettings(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
testGotoDefinition("libs3.foo.bar.ba<caret>z") {
|
||||
assertInstanceOf(GroovyPsiElement::class.java, it)
|
||||
assertTrue(it.parentOfType<GrMethodCall>(true)!!.argumentList.expressionArguments[0].text == "\"foo.bar.baz\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testNavigationToLibraryInSettings2(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
testGotoDefinition("libs3.foo.nn.m<caret>m") {
|
||||
assertInstanceOf(GroovyPsiElement::class.java, it)
|
||||
assertTrue(it.parentOfType<GrMethodCall>(true)!!.argumentList.expressionArguments[0].text == "\"foo-nn-mm\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testNavigationWithCapitalLetters(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
testGotoDefinition("libs2.getCheck().getCapital().getLe<caret>tter()") {
|
||||
assertInstanceOf(TomlKeyValue::class.java, it)
|
||||
assertTrue((it as TomlKeyValue).key.text == "check-Capital-Letter")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val BASE_VERSION_CATALOG_FIXTURE = GradleTestFixtureBuilder
|
||||
.create("GradleVersionCatalogs-completion") {
|
||||
withSettingsFile {
|
||||
setProjectName("GradleVersionCatalogs-completion")
|
||||
enableFeaturePreview("VERSION_CATALOGS")
|
||||
addCode("""
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
libs2 {
|
||||
from(files("gradle/my.toml"))
|
||||
}
|
||||
libs3 {
|
||||
library("foo.bar.baz", "org.apache.groovy:groovy:4.0.0")
|
||||
library("foo-nn-mm", "org.apache.groovy:groovy:4.0.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
withFile("gradle/libs.versions.toml", /* language=TOML */ """
|
||||
[versions]
|
||||
groovy = "3.0.5"
|
||||
checkstyle = "8.37"
|
||||
|
||||
[libraries]
|
||||
groovy-core = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" }
|
||||
groovy-json = { module = "org.codehaus.groovy:groovy-json", version.ref = "groovy" }
|
||||
groovy-nio = { module = "org.codehaus.groovy:groovy-nio", version.ref = "groovy" }
|
||||
commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = { strictly = "[3.8, 4.0[", prefer="3.9" } }
|
||||
|
||||
[bundles]
|
||||
groovy = ["groovy-core", "groovy-json", "groovy-nio"]
|
||||
|
||||
[plugins]
|
||||
jmh = { id = "me.champeau.jmh", version = "0.6.5" }
|
||||
""".trimIndent())
|
||||
withFile("gradle/my.toml", /* language=TOML */ """
|
||||
[libraries]
|
||||
aa-bb-cc = { module = "org.apache.groovy:groovy", version = "4.0.0" }
|
||||
check-Capital-Letter = { module = "org.apache.groovy:groovy", version = "4.0.0" }
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.plugins.gradle.dsl.versionCatalogs
|
||||
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.testFramework.runInEdtAndWait
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.plugins.gradle.testFramework.GradleCodeInsightTestCase
|
||||
import org.jetbrains.plugins.gradle.testFramework.GradleTestFixtureBuilder
|
||||
import org.jetbrains.plugins.gradle.testFramework.annotations.BaseGradleVersionSource
|
||||
import org.jetbrains.plugins.gradle.testFramework.util.withSettingsFile
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase
|
||||
import org.junit.jupiter.api.Assertions.assertNotNull
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.toml.lang.psi.TomlFile
|
||||
|
||||
class GradleVersionCatalogsFindUsagesTest : GradleCodeInsightTestCase() {
|
||||
|
||||
private fun testVersionCatalogFindUsages(version: GradleVersion, versionCatalogText: String, buildGradleText: String,
|
||||
checker: (Collection<PsiReference>) -> Unit) {
|
||||
checkCaret(versionCatalogText)
|
||||
test(version, BASE_VERSION_CATALOG_FIXTURE) {
|
||||
val versionCatalog = findOrCreateFile("gradle/libs.versions.toml", versionCatalogText)
|
||||
findOrCreateFile("build.gradle", buildGradleText)
|
||||
runInEdtAndWait {
|
||||
codeInsightFixture.configureFromExistingVirtualFile(versionCatalog)
|
||||
val elementAtCaret = codeInsightFixture.elementAtCaret
|
||||
assertNotNull(elementAtCaret)
|
||||
val usages = ReferencesSearch.search(elementAtCaret).findAll()
|
||||
checker(usages)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testHasUsages(gradleVersion: GradleVersion) {
|
||||
testVersionCatalogFindUsages(gradleVersion, """
|
||||
[libraries]
|
||||
groov<caret>y-core = "org.codehaus.groovy:groovy:2.7.3"
|
||||
""".trimIndent(), """
|
||||
libs.groovy.core
|
||||
""".trimIndent()) {
|
||||
assert(it.isNotEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testHasNoUsages(gradleVersion: GradleVersion) {
|
||||
testVersionCatalogFindUsages(gradleVersion, """
|
||||
[versions]
|
||||
foo = "4.7.6"
|
||||
[libraries]
|
||||
groov<caret>y-core = "org.codehaus.groovy:groovy:2.7.3"
|
||||
aaa-bbb = { group = "org.apache.groovy", name = "groovy", version.ref = "groovy" }
|
||||
""".trimIndent(), """
|
||||
libs.groovy
|
||||
""".trimIndent()) {
|
||||
assert(it.isEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testFindUsagesOfVersion(gradleVersion: GradleVersion) {
|
||||
testVersionCatalogFindUsages(gradleVersion, """
|
||||
[versions]
|
||||
fo<caret>o = "4.7.6"
|
||||
[libraries]
|
||||
aaa-bbb = { group = "org.apache.groovy", name = "groovy", version.ref = "foo" }
|
||||
""".trimIndent(), """
|
||||
libs.versions.foo
|
||||
""".trimIndent()) { refs ->
|
||||
assertNotNull(refs.find { it.element.containingFile is GroovyFileBase })
|
||||
assertNotNull(refs.find { it.element.containingFile is TomlFile })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private val BASE_VERSION_CATALOG_FIXTURE = GradleTestFixtureBuilder
|
||||
.create("GradleVersionCatalogs-find-usages-bare") {
|
||||
withSettingsFile {
|
||||
setProjectName("GradleVersionCatalogs-find-usages-bare")
|
||||
enableFeaturePreview("VERSION_CATALOGS")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,7 @@ abstract class GradleCodeInsightTestCase : GradleCodeInsightBaseTestCase(), Expr
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCaret(expression: String) {
|
||||
protected fun checkCaret(expression: String) {
|
||||
assertTrue("<caret>" in expression, "Please define caret position in build script.")
|
||||
}
|
||||
|
||||
@@ -59,20 +59,21 @@ abstract class GradleCodeInsightTestCase : GradleCodeInsightBaseTestCase(), Expr
|
||||
}
|
||||
}
|
||||
|
||||
fun testCompletion(expression: String, checker: (Array<LookupElement>) -> Unit) {
|
||||
fun testCompletion(fileName: String, expression: String, checker: (Array<LookupElement>) -> Unit) {
|
||||
checkCaret(expression)
|
||||
val file = findOrCreateFile("build.gradle", expression)
|
||||
val file = findOrCreateFile(fileName, expression)
|
||||
runInEdtAndWait {
|
||||
codeInsightFixture.configureFromExistingVirtualFile(file)
|
||||
checker(codeInsightFixture.completeBasic())
|
||||
}
|
||||
}
|
||||
|
||||
fun testCompletion(expression: String, vararg completionCandidates: String) = testCompletion(expression) {
|
||||
fun testCompletion(expression: String, vararg completionCandidates: String, orderDependent: Boolean = true) = testCompletion("build.gradle", expression) {
|
||||
val lookup = listOf(*it)
|
||||
var startIndex = 0
|
||||
for (candidate in completionCandidates) {
|
||||
val newIndex = lookup.subList(startIndex, lookup.size).indexOfFirst { it.lookupString == candidate }
|
||||
val fromIndex = if (orderDependent) startIndex else 0
|
||||
val newIndex = lookup.subList(fromIndex, lookup.size).indexOfFirst { it.lookupString == candidate }
|
||||
assertTrue(newIndex != -1, "Element '$candidate' must be in the lookup")
|
||||
startIndex = newIndex + 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user