[gradle] IDEA-363330 prevent NPE in SyntheticVersionCatalogAccessor: use a model of exact catalog

In the accessor, use GradleVersionCatalogModel (a model for a single catalog) instead of GradleVersionCatalogsModel (a model for multiple catalogs). The last one also gives access to libraries, plugins, bundles and versions - but the result is nullable. Accessing them with `!!` looks suspicious to me. Probably, it was a cause of NPE while <init> of the accessor. Anyway, the usage of GradleVersionCatalogModel looks better to me.

Code review: IJ-CR-153929
(cherry picked from commit b659570aa14e89654ece34d81f6771706760caf2)

GitOrigin-RevId: 5d8796f59f35302f6dd70a5292a8ac5c5562157e
This commit is contained in:
Nikita Biriukov
2024-12-24 18:34:34 +01:00
committed by intellij-monorepo-bot
parent 041c829211
commit 45d46461b3
3 changed files with 24 additions and 23 deletions

View File

@@ -20,7 +20,7 @@ class GradleDslVersionCatalogHandler : GradleVersionCatalogHandler {
@Deprecated("Doesn't work for included builds of a composite build", replaceWith = ReplaceWith("getVersionCatalogFiles(module)"))
override fun getVersionCatalogFiles(project: Project): Map<String, VirtualFile> {
return ProjectBuildModel.get(project).context.versionCatalogFiles.associate { it.catalogName to it.file } ?: emptyMap()
return ProjectBuildModel.get(project).context.versionCatalogFiles.associate { it.catalogName to it.file }
}
override fun getVersionCatalogFiles(module: Module): Map<String, VirtualFile> {
@@ -33,20 +33,21 @@ class GradleDslVersionCatalogHandler : GradleVersionCatalogHandler {
val scope = context.resolveScope
val module = ModuleUtilCore.findModuleForPsiElement(context) ?: return null
val buildModel = getBuildModel(module) ?: return null
val versionCatalogModel = buildModel.versionCatalogsModel
if (versionCatalogModel.getVersionCatalogModel(catalogName) == null) return null
return SyntheticVersionCatalogAccessor.create(project, scope, versionCatalogModel, catalogName)
val catalogs = buildModel.versionCatalogsModel
val catalogModel = catalogs.getVersionCatalogModel(catalogName) ?: return null
return SyntheticVersionCatalogAccessor.create(project, scope, catalogModel, catalogName)
}
override fun getAccessorsForAllCatalogs(context: PsiElement): Map<String, PsiClass> {
val project = context.project
val scope = context.resolveScope
val module = ModuleUtilCore.findModuleForPsiElement(context) ?: return emptyMap()
val catalogsModel = getBuildModel(module)?.versionCatalogsModel ?: return emptyMap()
val catalogs = getBuildModel(module)?.versionCatalogsModel ?: return emptyMap()
val result = mutableMapOf<String, PsiClass>()
catalogsModel.catalogNames().forEach { catalogName ->
val accessor = SyntheticVersionCatalogAccessor.create(project, scope, catalogsModel, catalogName)
accessor?.let { result.putIfAbsent(catalogName, accessor) }
for (catalogName in catalogs.catalogNames()) {
val catalogModel = catalogs.getVersionCatalogModel(catalogName) ?: continue
val accessor = SyntheticVersionCatalogAccessor.create(project, scope, catalogModel, catalogName) ?: continue
result.putIfAbsent(catalogName, accessor)
}
return result
}

View File

@@ -1,7 +1,7 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.plugins.gradle.service.resolve.static
import com.android.tools.idea.gradle.dsl.api.GradleVersionCatalogsModel
import com.android.tools.idea.gradle.dsl.api.GradleVersionCatalogModel
import com.android.tools.idea.gradle.dsl.api.ext.GradlePropertyModel
import com.intellij.lang.java.JavaLanguage
import com.intellij.lang.java.beans.PropertyKind
@@ -21,26 +21,26 @@ import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames
class SyntheticVersionCatalogAccessor(
project: Project,
scope: GlobalSearchScope,
model: GradleVersionCatalogsModel,
className: String,
model: GradleVersionCatalogModel,
catalogName: String,
delegate: PsiClass,
) : LightClass(delegate) {
private val libraries: Array<PsiMethod> =
SyntheticAccessorBuilder(project, scope, className, Kind.LIBRARY)
.buildMethods(this, model.libraries(className)!!.properties.let(::assembleTree), "")
SyntheticAccessorBuilder(project, scope, Kind.LIBRARY)
.buildMethods(this, model.libraries().properties.let(::assembleTree), "")
.toTypedArray()
private val plugins: PsiMethod = SyntheticAccessorBuilder(project, scope, className, Kind.PLUGIN)
.buildEnclosingMethod(this, model.plugins(className)!!.properties, "plugins")
private val plugins: PsiMethod = SyntheticAccessorBuilder(project, scope, Kind.PLUGIN)
.buildEnclosingMethod(this, model.plugins().properties, "plugins")
private val versions: PsiMethod = SyntheticAccessorBuilder(project, scope, className, Kind.VERSION)
.buildEnclosingMethod(this, model.versions(className)!!.properties, "versions")
private val versions: PsiMethod = SyntheticAccessorBuilder(project, scope, Kind.VERSION)
.buildEnclosingMethod(this, model.versions().properties, "versions")
private val bundles: PsiMethod = SyntheticAccessorBuilder(project, scope, className, Kind.BUNDLE)
.buildEnclosingMethod(this, model.bundles(className)!!.properties, "bundles")
private val bundles: PsiMethod = SyntheticAccessorBuilder(project, scope, Kind.BUNDLE)
.buildEnclosingMethod(this, model.bundles().properties, "bundles")
private val className = "LibrariesFor${StringUtil.capitalize(className)}"
private val className = "LibrariesFor${StringUtil.capitalize(catalogName)}"
override fun getMethods(): Array<PsiMethod> {
return libraries + arrayOf(plugins, versions, bundles)
@@ -57,7 +57,7 @@ class SyntheticVersionCatalogAccessor(
fun create(
project: Project,
scope: GlobalSearchScope,
model: GradleVersionCatalogsModel,
model: GradleVersionCatalogModel,
className: String,
): SyntheticVersionCatalogAccessor? {
val delegate = JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, scope) ?: return null
@@ -68,7 +68,7 @@ class SyntheticVersionCatalogAccessor(
LIBRARY("Library"), PLUGIN("Plugin"), BUNDLE("Bundle"), VERSION("Version")
}
private class SyntheticAccessorBuilder(val project: Project, val gradleScope: GlobalSearchScope, val className: String, val kind: Kind) {
private class SyntheticAccessorBuilder(val project: Project, val gradleScope: GlobalSearchScope, val kind: Kind) {
private fun buildSyntheticInnerClass(mapping: List<Tree>,
containingClass: PsiClass,

View File

@@ -35,7 +35,7 @@ class GradleVersionCatalogsCompletionTest : GradleCodeInsightTestCase() {
}
}
//@ParameterizedTest
@ParameterizedTest
@BaseGradleVersionSource
fun testCompletionForBundles(gradleVersion: GradleVersion) {
test(gradleVersion, BASE_VERSION_CATALOG_FIXTURE) {