Split LightClassGenerationSupport into separate entities
LightClassGenerationSupport:
Includes utilities related to generating light classes
Primary client of this service are KtLight* implementation classes
KotlinAsJavaSupport:
Provides APIs to transform kotlin code into Psi* entities
Primary client of this service is JavaElementFinder
This commit is contained in:
+114
-100
@@ -25,6 +25,7 @@ import com.intellij.util.Function
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
||||
import org.jetbrains.kotlin.asJava.LightClassBuilder
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder
|
||||
@@ -63,28 +64,12 @@ import kotlin.properties.Delegates
|
||||
|
||||
* To mitigate this, CliLightClassGenerationSupport hold a trace that is shared between the analyzer and JetLightClasses
|
||||
*/
|
||||
class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSupport(), CodeAnalyzerInitializer {
|
||||
private val psiManager = PsiManager.getInstance(project)
|
||||
private var bindingContext: BindingContext by Delegates.notNull()
|
||||
private var module: ModuleDescriptor by Delegates.notNull()
|
||||
|
||||
|
||||
override fun initialize(trace: BindingTrace, module: ModuleDescriptor, codeAnalyzer: KotlinCodeAnalyzer) {
|
||||
this.bindingContext = trace.bindingContext
|
||||
this.module = module
|
||||
|
||||
if (trace !is CliBindingTrace) {
|
||||
throw IllegalArgumentException("Shared trace is expected to be subclass of ${CliBindingTrace::class.java.simpleName} class")
|
||||
}
|
||||
|
||||
trace.setKotlinCodeAnalyzer(codeAnalyzer)
|
||||
}
|
||||
|
||||
class CliLightClassGenerationSupport(private val traceHolder: CliTraceHolder) : LightClassGenerationSupport() {
|
||||
override fun createDataHolderForClass(
|
||||
classOrObject: KtClassOrObject, builder: LightClassBuilder
|
||||
): LightClassDataHolder.ForClass {
|
||||
//force resolve companion for light class generation
|
||||
bindingContext.get(BindingContext.CLASS, classOrObject)?.companionObjectDescriptor
|
||||
traceHolder.bindingContext.get(BindingContext.CLASS, classOrObject)?.companionObjectDescriptor
|
||||
|
||||
val (stub, bindingContext, diagnostics) = builder(getContext())
|
||||
|
||||
@@ -106,96 +91,33 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
|
||||
return LightClassDataHolderImpl(stub, diagnostics)
|
||||
}
|
||||
|
||||
private fun getContext(): LightClassConstructionContext = LightClassConstructionContext(bindingContext, module)
|
||||
|
||||
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> {
|
||||
return ResolveSessionUtils.getClassDescriptorsByFqName(module, fqName).mapNotNull {
|
||||
val element = DescriptorToSourceUtils.getSourceFromDescriptor(it)
|
||||
if (element is KtClassOrObject && PsiSearchScopeUtil.isInScope(searchScope, element)) {
|
||||
element
|
||||
}
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
override fun findFilesForPackage(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> {
|
||||
return bindingContext.get(BindingContext.PACKAGE_TO_FILES, fqName)?.filter {
|
||||
PsiSearchScopeUtil.isInScope(searchScope, it)
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
override fun findClassOrObjectDeclarationsInPackage(
|
||||
packageFqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> {
|
||||
val files = findFilesForPackage(packageFqName, searchScope)
|
||||
val result = SmartList<KtClassOrObject>()
|
||||
for (file in files) {
|
||||
for (declaration in file.declarations) {
|
||||
if (declaration is KtClassOrObject) {
|
||||
result.add(declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean {
|
||||
return !module.getPackage(fqName).isEmpty()
|
||||
}
|
||||
|
||||
override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> {
|
||||
val packageView = module.getPackage(fqn)
|
||||
val members = packageView.memberScope.getContributedDescriptors(DescriptorKindFilter.PACKAGES, MemberScope.ALL_NAME_FILTER)
|
||||
return ContainerUtil.mapNotNull(members, object : Function<DeclarationDescriptor, FqName> {
|
||||
override fun `fun`(member: DeclarationDescriptor): FqName? {
|
||||
if (member is PackageViewDescriptor) {
|
||||
return member.fqName
|
||||
}
|
||||
return null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? = KtLightClassForSourceDeclaration.create(classOrObject)
|
||||
|
||||
override fun getLightClassForScript(script: KtScript): KtLightClassForScript? = KtLightClassForScript.create(script)
|
||||
private fun getContext(): LightClassConstructionContext = LightClassConstructionContext(traceHolder.bindingContext, traceHolder.module)
|
||||
|
||||
override fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor? {
|
||||
return bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)
|
||||
return traceHolder.bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)
|
||||
}
|
||||
|
||||
override fun analyze(element: KtElement) = bindingContext
|
||||
override fun analyze(element: KtElement) = traceHolder.bindingContext
|
||||
|
||||
override fun analyzeWithContent(element: KtClassOrObject) = bindingContext
|
||||
override fun analyzeWithContent(element: KtClassOrObject) = traceHolder.bindingContext
|
||||
}
|
||||
|
||||
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
val filesForFacade = findFilesForFacade(facadeFqName, scope)
|
||||
if (filesForFacade.isEmpty()) return emptyList()
|
||||
class CliTraceHolder : CodeAnalyzerInitializer {
|
||||
var bindingContext: BindingContext by Delegates.notNull()
|
||||
private set
|
||||
var module: ModuleDescriptor by Delegates.notNull()
|
||||
private set
|
||||
|
||||
return listOfNotNull<PsiClass>(
|
||||
KtLightClassForFacade.createForFacade(psiManager, facadeFqName, scope, filesForFacade))
|
||||
}
|
||||
|
||||
override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
if (scriptFqName.isRoot) {
|
||||
return emptyList()
|
||||
override fun initialize(trace: BindingTrace, module: ModuleDescriptor, codeAnalyzer: KotlinCodeAnalyzer) {
|
||||
this.bindingContext = trace.bindingContext
|
||||
this.module = module
|
||||
|
||||
if (trace !is CliBindingTrace) {
|
||||
throw IllegalArgumentException("Shared trace is expected to be subclass of ${CliBindingTrace::class.java.simpleName} class")
|
||||
}
|
||||
|
||||
return findFilesForPackage(scriptFqName.parent(), scope).mapNotNull { file ->
|
||||
file.script?.takeIf { it.fqName == scriptFqName }?.let { it -> getLightClassForScript(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
//
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<KtFile> {
|
||||
if (facadeFqName.isRoot) return emptyList()
|
||||
|
||||
return bindingContext.get(FilesByFacadeFqNameIndexer.FACADE_FILES_BY_FQ_NAME, facadeFqName)?.filter {
|
||||
PsiSearchScopeUtil.isInScope(scope, it)
|
||||
} ?: emptyList()
|
||||
trace.setKotlinCodeAnalyzer(codeAnalyzer)
|
||||
}
|
||||
|
||||
override fun createTrace(): BindingTraceContext {
|
||||
@@ -245,6 +167,14 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CliKotlinAsJavaSupport(
|
||||
project: Project,
|
||||
private val traceHolder: CliTraceHolder
|
||||
): KotlinAsJavaSupport() {
|
||||
private val psiManager = PsiManager.getInstance(project)
|
||||
|
||||
override fun getFacadeClassesInPackage(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
return findFacadeFilesInPackage(packageFqName, scope)
|
||||
@@ -260,7 +190,91 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
|
||||
private fun findFacadeFilesInPackage(
|
||||
packageFqName: FqName,
|
||||
scope: GlobalSearchScope
|
||||
) = bindingContext.get(FilesByFacadeFqNameIndexer.FACADE_FILES_BY_PACKAGE_NAME, packageFqName)
|
||||
) = traceHolder.bindingContext.get(FilesByFacadeFqNameIndexer.FACADE_FILES_BY_PACKAGE_NAME, packageFqName)
|
||||
?.filter { PsiSearchScopeUtil.isInScope(scope, it) }
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
val filesForFacade = findFilesForFacade(facadeFqName, scope)
|
||||
if (filesForFacade.isEmpty()) return emptyList()
|
||||
|
||||
return listOfNotNull<PsiClass>(
|
||||
KtLightClassForFacade.createForFacade(psiManager, facadeFqName, scope, filesForFacade))
|
||||
}
|
||||
|
||||
override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
if (scriptFqName.isRoot) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return findFilesForPackage(scriptFqName.parent(), scope).mapNotNull { file ->
|
||||
file.script?.takeIf { it.fqName == scriptFqName }?.let { it -> getLightClassForScript(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
//
|
||||
return 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)
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
|
||||
override fun findClassOrObjectDeclarationsInPackage(
|
||||
packageFqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> {
|
||||
val files = findFilesForPackage(packageFqName, searchScope)
|
||||
val result = SmartList<KtClassOrObject>()
|
||||
for (file in files) {
|
||||
for (declaration in file.declarations) {
|
||||
if (declaration is KtClassOrObject) {
|
||||
result.add(declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean {
|
||||
return !traceHolder.module.getPackage(fqName).isEmpty()
|
||||
}
|
||||
|
||||
override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> {
|
||||
val packageView = traceHolder.module.getPackage(fqn)
|
||||
val members = packageView.memberScope.getContributedDescriptors(DescriptorKindFilter.PACKAGES, MemberScope.ALL_NAME_FILTER)
|
||||
return ContainerUtil.mapNotNull(members, object : Function<DeclarationDescriptor, FqName> {
|
||||
override fun `fun`(member: DeclarationDescriptor): FqName? {
|
||||
if (member is PackageViewDescriptor) {
|
||||
return member.fqName
|
||||
}
|
||||
return null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? = KtLightClassForSourceDeclaration.create(classOrObject)
|
||||
|
||||
override fun getLightClassForScript(script: KtScript): KtLightClassForScript? = KtLightClassForScript.create(script)
|
||||
|
||||
|
||||
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtClassOrObject> {
|
||||
return ResolveSessionUtils.getClassDescriptorsByFqName(traceHolder.module, fqName).mapNotNull {
|
||||
val element = DescriptorToSourceUtils.getSourceFromDescriptor(it)
|
||||
if (element is KtClassOrObject && PsiSearchScopeUtil.isInScope(searchScope, element)) {
|
||||
element
|
||||
}
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
override fun findFilesForPackage(fqName: FqName, searchScope: GlobalSearchScope): Collection<KtFile> {
|
||||
return traceHolder.bindingContext.get(BindingContext.PACKAGE_TO_FILES, fqName)?.filter {
|
||||
PsiSearchScopeUtil.isInScope(searchScope, it)
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ import com.intellij.psi.util.JavaClassSupers
|
||||
import com.intellij.util.io.URLUtil
|
||||
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.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||
@@ -130,17 +131,20 @@ class KotlinCoreEnvironment private constructor(
|
||||
with (project) {
|
||||
registerService(CoreJavaFileManager::class.java, ServiceManager.getService(this, JavaFileManager::class.java) as CoreJavaFileManager)
|
||||
|
||||
val cliLightClassGenerationSupport = CliLightClassGenerationSupport(this)
|
||||
val traceHolder = CliTraceHolder()
|
||||
val cliLightClassGenerationSupport = CliLightClassGenerationSupport(traceHolder)
|
||||
val kotlinAsJavaSupport = CliKotlinAsJavaSupport(this, traceHolder)
|
||||
registerService(LightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
|
||||
registerService(CliLightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
|
||||
registerService(CodeAnalyzerInitializer::class.java, cliLightClassGenerationSupport)
|
||||
registerService(KotlinAsJavaSupport::class.java, kotlinAsJavaSupport)
|
||||
registerService(CodeAnalyzerInitializer::class.java, traceHolder)
|
||||
|
||||
registerService(ExternalAnnotationsManager::class.java, MockExternalAnnotationsManager())
|
||||
registerService(InferredAnnotationsManager::class.java, MockInferredAnnotationsManager())
|
||||
|
||||
val area = Extensions.getArea(this)
|
||||
|
||||
area.getExtensionPoint(PsiElementFinder.EP_NAME).registerExtension(JavaElementFinder(this, cliLightClassGenerationSupport))
|
||||
area.getExtensionPoint(PsiElementFinder.EP_NAME).registerExtension(JavaElementFinder(this, kotlinAsJavaSupport))
|
||||
area.getExtensionPoint(PsiElementFinder.EP_NAME).registerExtension(
|
||||
PsiElementFinderImpl(this, ServiceManager.getService(this, JavaFileManager::class.java)))
|
||||
}
|
||||
|
||||
+1
-1
@@ -374,7 +374,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
|
||||
project,
|
||||
sourceFiles,
|
||||
CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace(),
|
||||
CliTraceHolder.NoScopeRecordCliBindingTrace(),
|
||||
environment.configuration,
|
||||
environment::createPackagePartProvider,
|
||||
sourceModuleSearchScope = scope
|
||||
|
||||
+2
-5
@@ -17,8 +17,8 @@
|
||||
package org.jetbrains.kotlin.cli.jvm.javac
|
||||
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.findFacadeClass
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.javac.JavacWrapperKotlinResolver
|
||||
import org.jetbrains.kotlin.javac.resolve.MockKotlinField
|
||||
@@ -47,7 +47,7 @@ class JavacWrapperKotlinResolverImpl(private val lightClassGenerationSupport: Li
|
||||
}
|
||||
|
||||
override fun findField(classOrObject: KtClassOrObject, name: String): JavaField? {
|
||||
val lightClass = classOrObject.getLightClass() ?: return null
|
||||
val lightClass = classOrObject.toLightClass() ?: return null
|
||||
|
||||
return lightClass.allFields.find { it.name == name}?.let(::MockKotlinField)
|
||||
}
|
||||
@@ -57,7 +57,4 @@ class JavacWrapperKotlinResolverImpl(private val lightClassGenerationSupport: Li
|
||||
|
||||
return lightClass.allFields.find { it.name == name}?.let(::MockKotlinField)
|
||||
}
|
||||
|
||||
private fun KtClassOrObject.getLightClass(): KtLightClass? = lightClassGenerationSupport.getLightClass(this)
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.cli.common.repl.CompiledReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.common.repl.ILineId
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplHistory
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.CliTraceHolder
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
|
||||
import org.jetbrains.kotlin.container.get
|
||||
@@ -56,7 +56,7 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
|
||||
|
||||
val module: ModuleDescriptorImpl
|
||||
|
||||
val trace: BindingTraceContext = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
|
||||
val trace: BindingTraceContext = CliTraceHolder.NoScopeRecordCliBindingTrace()
|
||||
|
||||
init {
|
||||
// Module source scope is empty because all binary classes are in the dependency module, and all source classes are guaranteed
|
||||
|
||||
Reference in New Issue
Block a user