KT-63096 [LL] Make KotlinStaticAnnotationsResolver more correct

By using `KotlinDeclarationProvider`, it can now check that the
annotation is actually present in the scope
This commit is contained in:
Roman Golyshev
2023-11-06 18:37:19 +01:00
committed by teamcity
parent a1155204c7
commit 2f50267d3f
3 changed files with 28 additions and 6 deletions
@@ -72,7 +72,7 @@ object AnalysisApiBaseTestServiceRegistrar: AnalysisApiTestServiceRegistrar() {
testServices.environmentManager.getProjectEnvironment()
).distinct()
project.apply {
registerService(KotlinAnnotationsResolverFactory::class.java, KotlinStaticAnnotationsResolverFactory(allSourceKtFiles))
registerService(KotlinAnnotationsResolverFactory::class.java, KotlinStaticAnnotationsResolverFactory(project, allSourceKtFiles))
val filter = BuiltInDefinitionFile.FILTER_OUT_CLASSES_EXISTING_AS_JVM_CLASS_FILES
val ktFilesForBinaries: List<KtFile>
@@ -5,22 +5,33 @@
package org.jetbrains.kotlin.analysis.providers.impl
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.providers.KotlinAnnotationsResolver
import org.jetbrains.kotlin.analysis.providers.KotlinAnnotationsResolverFactory
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.filterIsInstanceAnd
/**
* This implementation works only for fully-qualified annotations usages, and does not check if they resolve somewhere.
* This implementation works only for FQN annotations usages (`@foo.Bar` instead of `@Bar`).
* It does not perform the full resolve of the annotation call, but it checks whether the annotation
* with such FQN is present in the [scope] with [KotlinDeclarationProvider].
*
* Required for the test infrastructure.
* Required for and used only in the test infrastructure.
*/
private class KotlinStaticAnnotationsResolver(
private val project: Project,
ktFiles: Collection<KtFile>,
scope: GlobalSearchScope
) : KotlinAnnotationsResolver {
private val declarationProvider: KotlinDeclarationProvider by lazy {
project.createDeclarationProvider(scope, contextualModule = null)
}
private val filesInScope = ktFiles.filter { scope.contains(it.virtualFile) }
private val allDeclarations: List<KtDeclaration> by lazy {
@@ -54,12 +65,23 @@ private class KotlinStaticAnnotationsResolver(
return declaration.annotationEntries.asSequence()
.mapNotNull { it.typeReference?.text }
.map { ClassId.topLevel(FqName(it)) }
.filter { it.resolveToAnnotation() != null }
.toSet()
}
private fun ClassId.resolveToAnnotation(): KtClass? {
val classes = declarationProvider.getAllClassesByClassId(this)
val annotations = classes.filterIsInstanceAnd<KtClass> { it.isAnnotation() }
return annotations.singleOrNull()
}
}
public class KotlinStaticAnnotationsResolverFactory(private val files: Collection<KtFile>) : KotlinAnnotationsResolverFactory {
public class KotlinStaticAnnotationsResolverFactory(
private val project: Project,
private val files: Collection<KtFile>,
) : KotlinAnnotationsResolverFactory {
override fun createAnnotationResolver(searchScope: GlobalSearchScope): KotlinAnnotationsResolver {
return KotlinStaticAnnotationsResolver(files, searchScope)
return KotlinStaticAnnotationsResolver(project, files, searchScope)
}
}
@@ -125,7 +125,7 @@ public class StandaloneAnalysisAPISessionBuilder(
registerService(KotlinModificationTrackerFactory::class.java, KotlinStaticModificationTrackerFactory::class.java)
registerService(KotlinGlobalModificationService::class.java, KotlinStaticGlobalModificationService::class.java)
registerService(KotlinAnnotationsResolverFactory::class.java, KotlinStaticAnnotationsResolverFactory(sourceKtFiles))
registerService(KotlinAnnotationsResolverFactory::class.java, KotlinStaticAnnotationsResolverFactory(this, sourceKtFiles))
registerService(KotlinResolutionScopeProvider::class.java, KotlinByModulesResolutionScopeProvider::class.java)
val declarationProviderFactory = KotlinStaticDeclarationProviderFactory(
this,