[lc] introduce KotlinAsJavaSupportBase with new common facade logic

^KT-53543
This commit is contained in:
Dmitry Gridin
2022-08-11 15:55:58 +02:00
committed by Space
parent 0ea041a1eb
commit 924dd38144
22 changed files with 206 additions and 329 deletions
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject
import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass
import org.jetbrains.kotlin.cli.jvm.compiler.builder.extraJvmDiagnosticsFromBackend
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
@@ -42,7 +43,7 @@ object CliExtraDiagnosticsProvider {
private fun calculateForFacade(file: KtFile): Diagnostics {
val project = file.project
val facadeFqName = JvmFileClassUtil.getFileClassInfoNoResolve(file).facadeClassFqName
val facadeFqName = file.javaFileFacadeFqName
val facadeCollection = KotlinAsJavaSupport.getInstance(project)
.findFilesForFacade(facadeFqName, GlobalSearchScope.allScope(project))
.ifEmpty { return Diagnostics.EMPTY }
@@ -10,10 +10,10 @@ import com.intellij.psi.PsiClass
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiSearchScopeUtil
import com.intellij.util.SmartList
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupportBase
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.classes.*
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.load.java.components.FilesByFacadeFqNameIndexer
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -25,32 +25,33 @@ import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
class CliKotlinAsJavaSupport(
private val project: Project,
private val traceHolder: CliTraceHolder
) : KotlinAsJavaSupport() {
override fun getFacadeClassesInPackage(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
return findFacadeFilesInPackage(packageFqName, scope)
.groupBy { it.javaFileFacadeFqName }
.mapNotNull { (facadeClassFqName, _) ->
KotlinLightClassFactory.createFacade(project, facadeClassFqName, scope)
}
}
override fun getFacadeNames(packageFqName: FqName, scope: GlobalSearchScope): Collection<String> {
return findFacadeFilesInPackage(packageFqName, scope)
.map { it.javaFileFacadeFqName.shortName().asString() }
}
private fun findFacadeFilesInPackage(
class CliKotlinAsJavaSupport(project: Project, private val traceHolder: CliTraceHolder) : KotlinAsJavaSupportBase<KtFile>(project) {
override fun findFilesForFacadeByPackage(
packageFqName: FqName,
scope: GlobalSearchScope
searchScope: GlobalSearchScope
) = traceHolder.bindingContext.get(FilesByFacadeFqNameIndexer.FACADE_FILES_BY_PACKAGE_NAME, packageFqName)
?.filter { PsiSearchScopeUtil.isInScope(scope, it) }
?.filter { PsiSearchScopeUtil.isInScope(searchScope, it) }
.orEmpty()
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
return listOfNotNull(KotlinLightClassFactory.createFacade(project, facadeFqName, scope))
override fun KtFile.findModule(): KtFile = this
override fun createInstanceOfDecompiledLightFacade(facadeFqName: FqName, files: List<KtFile>, module: KtFile): KtLightClassForFacade? {
error("Should not be called")
}
override fun createInstanceOfLightFacade(facadeFqName: FqName, files: List<KtFile>, module: KtFile): KtLightClassForFacade {
return LightClassGenerationSupport.getInstance(files.first().project).createUltraLightClassForFacade(facadeFqName, files)
}
override val KtFile.contentSearchScope: GlobalSearchScope get() = GlobalSearchScope.allScope(project)
override fun facadeIsApplicable(module: KtFile, file: KtFile): Boolean = !module.isCompiled
override fun findFilesForFacade(facadeFqName: FqName, searchScope: GlobalSearchScope): List<KtFile> {
if (facadeFqName.isRoot) return emptyList()
return traceHolder.bindingContext.get(FilesByFacadeFqNameIndexer.FACADE_FILES_BY_FQ_NAME, facadeFqName)?.filter {
PsiSearchScopeUtil.isInScope(searchScope, it)
}.orEmpty()
}
override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
@@ -59,24 +60,13 @@ class CliKotlinAsJavaSupport(
}
return findFilesForPackage(scriptFqName.parent(), scope).mapNotNull { file ->
file.script?.takeIf { it.fqName == scriptFqName }?.let { it -> getLightClassForScript(it) }
file.script?.takeIf { it.fqName == scriptFqName }?.let { getLightClassForScript(it) }
}
}
override fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
return emptyList()
}
override fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> = emptyList()
override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<KtFile> {
if (facadeFqName.isRoot) return emptyList()
return traceHolder.bindingContext.get(FilesByFacadeFqNameIndexer.FACADE_FILES_BY_FQ_NAME, facadeFqName)?.filter {
PsiSearchScopeUtil.isInScope(scope, it)
}.orEmpty()
}
override fun getFakeLightClass(classOrObject: KtClassOrObject): KtFakeLightClass =
KtDescriptorBasedFakeLightClass(classOrObject)
override fun getFakeLightClass(classOrObject: KtClassOrObject): KtFakeLightClass = KtDescriptorBasedFakeLightClass(classOrObject)
override fun findClassOrObjectDeclarationsInPackage(
packageFqName: FqName, searchScope: GlobalSearchScope
@@ -90,12 +80,11 @@ class CliKotlinAsJavaSupport(
}
}
}
return result
}
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean {
return !traceHolder.module.getPackage(fqName).isEmpty()
}
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean = !traceHolder.module.getPackage(fqName).isEmpty()
override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> {
val packageView = traceHolder.module.getPackage(fqn)
@@ -118,11 +107,11 @@ class CliKotlinAsJavaSupport(
}
}
override fun findFilesForPackage(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> {
return traceHolder.bindingContext.get(BindingContext.PACKAGE_TO_FILES, fqName)?.filter {
override fun findFilesForPackage(packageFqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> {
return traceHolder.bindingContext.get(BindingContext.PACKAGE_TO_FILES, packageFqName)?.filter {
PsiSearchScopeUtil.isInScope(searchScope, it)
}.orEmpty()
}
override fun createFacadeForSyntheticFile(facadeClassFqName: FqName, file: KtFile): PsiClass = error("Should not be called")
override fun createFacadeForSyntheticFile(file: KtFile): KtLightClassForFacade = error("Should not be called")
}
@@ -42,7 +42,6 @@ import com.intellij.util.lang.UrlClassLoader
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.classes.FacadeCache
import org.jetbrains.kotlin.asJava.classes.KotlinK1LightClassFactory
import org.jetbrains.kotlin.asJava.classes.KotlinLightClassFactory
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
@@ -717,7 +716,6 @@ class KotlinCoreEnvironment private constructor(
fun registerProjectServices(project: MockProject) {
with(project) {
registerService(KotlinJavaPsiFacade::class.java, KotlinJavaPsiFacade(this))
registerService(FacadeCache::class.java, FacadeCache(this))
registerService(ModuleAnnotationsResolver::class.java, CliModuleAnnotationsResolver())
}
}
@@ -735,7 +733,7 @@ class KotlinCoreEnvironment private constructor(
with(project) {
val traceHolder = CliTraceHolder()
val cliLightClassGenerationSupport = CliLightClassGenerationSupport(traceHolder, project)
val kotlinAsJavaSupport = CliKotlinAsJavaSupport(this, traceHolder)
val kotlinAsJavaSupport = CliKotlinAsJavaSupport(project, traceHolder)
registerService(LightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(CliLightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(KotlinAsJavaSupport::class.java, kotlinAsJavaSupport)
@@ -70,7 +70,7 @@ object JvmFileClassUtil {
if (jvmName == null && jvmPackageName == null) return null
val isMultifileClass = findAnnotationEntryOnFileNoResolve(file, JVM_MULTIFILE_CLASS_SHORT) != null
val isMultifileClass = file.isJvmMultifileClassFile
return ParsedJvmFileClassAnnotations(jvmName, jvmPackageName, isMultifileClass)
}
@@ -122,10 +122,12 @@ val KtFile.javaFileFacadeFqName: FqName
return facadeFqName
}
val KtFile.isJvmMultifileClassFile: Boolean
get() = JvmFileClassUtil.findAnnotationEntryOnFileNoResolve(this, JVM_MULTIFILE_CLASS_SHORT) != null
private val LOG = Logger.getInstance("JvmFileClassUtil")
fun KtDeclaration.isInsideJvmMultifileClassFile() =
JvmFileClassUtil.findAnnotationEntryOnFileNoResolve(containingKtFile, JVM_MULTIFILE_CLASS_SHORT) != null
fun KtDeclaration.isInsideJvmMultifileClassFile() = containingKtFile.isJvmMultifileClassFile
val FqName.internalNameWithoutInnerClasses: String
get() = JvmClassName.byFqNameWithoutInnerClasses(this).internalName
@@ -33,11 +33,7 @@ abstract class LightClassGenerationSupport {
ConstantExpressionEvaluator(moduleDescriptor, languageVersionSettings, expression.project)
}
internal fun canCreateUltraLightClassForFacade(files: Collection<KtFile>): Boolean = files.none { it.isScript() }
fun createUltraLightClassForFacade(facadeClassFqName: FqName, files: Collection<KtFile>): KtUltraLightClassForFacade? {
if (!canCreateUltraLightClassForFacade(files)) return null
fun createUltraLightClassForFacade(facadeClassFqName: FqName, files: Collection<KtFile>): KtUltraLightClassForFacade {
val filesToSupports: List<Pair<KtFile, KtUltraLightSupport>> = files.map {
it to getUltraLightClassSupport(it)
}
@@ -1,56 +0,0 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.asJava.classes
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.util.containers.SLRUCache
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.name.FqName
private data class FacadeCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
private data class ValueWrapper(val value: KtLightClassForFacade?) {
companion object {
val Null = ValueWrapper(null)
}
}
class FacadeCache(private val project: Project) {
private inner class FacadeCacheData {
val cache = object : SLRUCache<FacadeCacheKey, ValueWrapper>(20, 30) {
override fun createValue(key: FacadeCacheKey): ValueWrapper =
KotlinK1LightClassFactory.createFacadeNoCache(key.fqName, key.searchScope, project)
?.let { ValueWrapper(it) }
?: ValueWrapper.Null
}
}
private val cachedValue: CachedValue<FacadeCacheData> = CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result.create(
FacadeCacheData(),
KotlinModificationTrackerService.getInstance(project).outOfBlockModificationTracker
)
}, false
)
operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): KtLightClassForFacade? {
synchronized(cachedValue) {
return cachedValue.value.cache.get(FacadeCacheKey(qualifiedName, searchScope)).value
}
}
companion object {
fun getInstance(project: Project): FacadeCache {
return ServiceManager.getService(project, FacadeCache::class.java)
}
}
}
@@ -5,17 +5,12 @@
package org.jetbrains.kotlin.asJava.classes
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtScript
class KotlinK1LightClassFactory : KotlinLightClassFactory {
@@ -27,18 +22,6 @@ class KotlinK1LightClassFactory : KotlinLightClassFactory {
)
}
override fun createFacade(
project: Project,
facadeClassFqName: FqName,
searchScope: GlobalSearchScope,
): KtLightClassForFacade? = FacadeCache.getInstance(project)[facadeClassFqName, searchScope]
override fun createFacadeForSyntheticFile(facadeClassFqName: FqName, file: KtFile): KtLightClassForFacade {
return LightClassGenerationSupport.getInstance(file.project).run {
createUltraLightClassForFacade(facadeClassFqName, listOf(file)) ?: error { "Unable to create UL class for facade" }
}
}
override fun createScript(script: KtScript): KtLightClassForScript? = CachedValuesManager.getCachedValue(script) {
CachedValueProvider.Result.create(
createScriptNoCache(script),
@@ -54,9 +37,7 @@ class KotlinK1LightClassFactory : KotlinLightClassFactory {
return null
}
return LightClassGenerationSupport.getInstance(script.project).run {
createUltraLightClassForScript(script)
}
return LightClassGenerationSupport.getInstance(script.project).createUltraLightClassForScript(script)
}
fun createClassNoCache(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? {
@@ -70,22 +51,7 @@ class KotlinK1LightClassFactory : KotlinLightClassFactory {
return null
}
return LightClassGenerationSupport.getInstance(classOrObject.project).run {
createUltraLightClass(classOrObject)
}
}
fun createFacadeNoCache(fqName: FqName, searchScope: GlobalSearchScope, project: Project): KtLightClassForFacade? {
val sources = KotlinAsJavaSupport.getInstance(project)
.findFilesForFacade(fqName, searchScope)
.filterNot { it.isCompiled || it.isScript() }
if (sources.isEmpty()) return null
return LightClassGenerationSupport.getInstance(project).run {
if (!canCreateUltraLightClassForFacade(sources)) return null
createUltraLightClassForFacade(fqName, sources)
?: error("Unable to create UL class for facade: $fqName for ${sources.joinToString { it.virtualFilePath }}")
}
return LightClassGenerationSupport.getInstance(classOrObject.project).createUltraLightClass(classOrObject)
}
}
}