[light classes] move descriptors from KtLightClassForSourceDeclaration to KtLightClassImpl
^KT-53097
This commit is contained in:
@@ -108,7 +108,7 @@ class CliKotlinAsJavaSupport(
|
||||
).mapNotNull { member -> (member as? PackageViewDescriptor)?.fqName }
|
||||
}
|
||||
|
||||
override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? = KtLightClassForSourceDeclaration.create(classOrObject)
|
||||
override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? = KtLightClassImpl.create(classOrObject)
|
||||
|
||||
override fun getLightClassForScript(script: KtScript): KtLightClassForScript? = KtLightClassForScript.create(script)
|
||||
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ abstract class KtLightClassForScript(val script: KtScript) : KtLightClassBase(sc
|
||||
// inner classes with null names can't be searched for and can't be used from java anyway
|
||||
// we can't prohibit creating light classes with null names either since they can contain members
|
||||
.filter { it.name != null }
|
||||
.mapNotNull { KtLightClassForSourceDeclaration.create(it) }
|
||||
.mapNotNull { KtLightClassImpl.create(it) }
|
||||
}
|
||||
|
||||
override fun getInitializers(): Array<PsiClassInitializer> = PsiClassInitializer.EMPTY_ARRAY
|
||||
|
||||
+4
-110
@@ -11,23 +11,15 @@ import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.PsiImmediateClassType
|
||||
import com.intellij.psi.impl.source.tree.TreeUtil
|
||||
import com.intellij.psi.scope.PsiScopeProcessor
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.stubs.IStubElementType
|
||||
import com.intellij.psi.stubs.StubElement
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
|
||||
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult
|
||||
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.UNSURE
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightModifierList
|
||||
import org.jetbrains.kotlin.asJava.hasInterfaceDefaultImpls
|
||||
import org.jetbrains.kotlin.config.JvmDefaultMode
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
|
||||
@@ -38,16 +30,6 @@ import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub
|
||||
import javax.swing.Icon
|
||||
|
||||
private class KtLightClassModifierList(containingClass: KtLightClassForSourceDeclaration, computeModifiers: () -> Set<String>) :
|
||||
KtLightModifierList<KtLightClassForSourceDeclaration>(containingClass) {
|
||||
|
||||
private val modifiers by lazyPub { computeModifiers() }
|
||||
|
||||
override fun hasModifierProperty(name: String): Boolean =
|
||||
if (name != PsiModifier.FINAL) name in modifiers else owner.isFinal(PsiModifier.FINAL in modifiers)
|
||||
|
||||
}
|
||||
|
||||
abstract class KtLightClassForSourceDeclaration(
|
||||
protected val classOrObject: KtClassOrObject,
|
||||
protected val jvmDefaultMode: JvmDefaultMode,
|
||||
@@ -75,7 +57,6 @@ abstract class KtLightClassForSourceDeclaration(
|
||||
|
||||
private val _extendsList by lazyPub { createExtendsList() }
|
||||
private val _implementsList by lazyPub { createImplementsList() }
|
||||
private val _deprecated by lazyPub { classOrObject.isDeprecated() }
|
||||
|
||||
protected abstract fun createExtendsList(): PsiReferenceList?
|
||||
protected abstract fun createImplementsList(): PsiReferenceList?
|
||||
@@ -86,35 +67,7 @@ abstract class KtLightClassForSourceDeclaration(
|
||||
abstract override fun getParent(): PsiElement?
|
||||
abstract override fun getQualifiedName(): String?
|
||||
|
||||
private val _containingFile: PsiFile by lazyPub {
|
||||
object : FakeFileForLightClass(
|
||||
classOrObject.containingKtFile,
|
||||
{ if (classOrObject.isTopLevel()) this else create(getOutermostClassOrObject(classOrObject))!! },
|
||||
) {
|
||||
override fun findReferenceAt(offset: Int) = ktFile.findReferenceAt(offset)
|
||||
|
||||
override fun processDeclarations(
|
||||
processor: PsiScopeProcessor,
|
||||
state: ResolveState,
|
||||
lastParent: PsiElement?,
|
||||
place: PsiElement
|
||||
): Boolean {
|
||||
if (!super.processDeclarations(processor, state, lastParent, place)) return false
|
||||
|
||||
// We have to explicitly process package declarations if current file belongs to default package
|
||||
// so that Java resolve can find classes located in that package
|
||||
val packageName = packageName
|
||||
if (!packageName.isEmpty()) return true
|
||||
|
||||
val aPackage = JavaPsiFacade.getInstance(myManager.project).findPackage(packageName)
|
||||
if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContainingFile(): PsiFile? = _containingFile
|
||||
abstract override fun getContainingFile(): PsiFile?
|
||||
|
||||
override fun getNavigationElement(): PsiElement = classOrObject
|
||||
|
||||
@@ -140,17 +93,6 @@ abstract class KtLightClassForSourceDeclaration(
|
||||
|
||||
override fun hashCode(): Int = classOrObject.hashCode() * 31 + jvmDefaultMode.hashCode()
|
||||
|
||||
override fun getContainingClass(): PsiClass? {
|
||||
if (classOrObject.parent === classOrObject.containingFile) return null
|
||||
|
||||
val containingClassOrObject = (classOrObject.parent as? KtClassBody)?.parent as? KtClassOrObject
|
||||
if (containingClassOrObject != null) {
|
||||
return create(containingClassOrObject)
|
||||
}
|
||||
|
||||
// TODO: should return null
|
||||
return super.getContainingClass()
|
||||
}
|
||||
|
||||
private val _typeParameterList: PsiTypeParameterList by lazyPub { buildTypeParameterList() }
|
||||
|
||||
@@ -162,15 +104,11 @@ abstract class KtLightClassForSourceDeclaration(
|
||||
|
||||
override fun getName(): String? = classOrObject.nameAsName?.asString()
|
||||
|
||||
private val _modifierList: PsiModifierList by lazyPub { KtLightClassModifierList(this) { computeModifiers() } }
|
||||
|
||||
override fun getModifierList(): PsiModifierList? = _modifierList
|
||||
|
||||
abstract override fun getModifierList(): PsiModifierList?
|
||||
protected abstract fun computeModifiers(): Set<String>
|
||||
|
||||
override fun hasModifierProperty(@NonNls name: String): Boolean = modifierList?.hasModifierProperty(name) ?: false
|
||||
|
||||
override fun isDeprecated(): Boolean = _deprecated
|
||||
abstract override fun isDeprecated(): Boolean
|
||||
|
||||
override fun isInterface(): Boolean {
|
||||
if (classOrObject !is KtClass) return false
|
||||
@@ -195,25 +133,7 @@ abstract class KtLightClassForSourceDeclaration(
|
||||
|
||||
override fun toString() = "${this::class.java.simpleName}:${classOrObject.getDebugText()}"
|
||||
|
||||
override fun getOwnInnerClasses(): List<PsiClass> {
|
||||
val result = ArrayList<PsiClass>()
|
||||
classOrObject.declarations.filterIsInstance<KtClassOrObject>()
|
||||
// workaround for ClassInnerStuffCache not supporting classes with null names, see KT-13927
|
||||
// inner classes with null names can't be searched for and can't be used from java anyway
|
||||
// we can't prohibit creating light classes with null names either since they can contain members
|
||||
.filter { it.name != null }
|
||||
.mapNotNullTo(result) {
|
||||
create(it)
|
||||
}
|
||||
|
||||
if (classOrObject.hasInterfaceDefaultImpls && jvmDefaultMode != JvmDefaultMode.ALL_INCOMPATIBLE) {
|
||||
result.add(createClassForInterfaceDefaultImpls())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
protected abstract fun createClassForInterfaceDefaultImpls(): PsiClass
|
||||
abstract override fun getOwnInnerClasses(): List<PsiClass>
|
||||
|
||||
override fun getUseScope(): SearchScope = kotlinOrigin.useScope
|
||||
|
||||
@@ -225,32 +145,6 @@ abstract class KtLightClassForSourceDeclaration(
|
||||
override fun getExtendsList(): PsiReferenceList? = _extendsList
|
||||
override fun getImplementsList(): PsiReferenceList? = _implementsList
|
||||
|
||||
companion object {
|
||||
fun create(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? =
|
||||
CachedValuesManager.getCachedValue(classOrObject) {
|
||||
CachedValueProvider.Result.create(
|
||||
createNoCache(classOrObject),
|
||||
KotlinModificationTrackerService.getInstance(classOrObject.project).outOfBlockModificationTracker,
|
||||
)
|
||||
}
|
||||
|
||||
fun createNoCache(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? {
|
||||
val containingFile = classOrObject.containingFile
|
||||
if (containingFile is KtCodeFragment) {
|
||||
// Avoid building light classes for code fragments
|
||||
return null
|
||||
}
|
||||
|
||||
if (classOrObject.shouldNotBeVisibleAsLightClass()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return LightClassGenerationSupport.getInstance(classOrObject.project).run {
|
||||
createUltraLightClass(classOrObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract override fun getSupers(): Array<PsiClass>
|
||||
|
||||
abstract override fun getSuperTypes(): Array<PsiClassType>
|
||||
|
||||
+144
-32
@@ -5,20 +5,35 @@
|
||||
|
||||
package org.jetbrains.kotlin.asJava.classes
|
||||
|
||||
import com.intellij.psi.CommonClassNames
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiModifier
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.InheritanceImplUtil
|
||||
import com.intellij.psi.scope.PsiScopeProcessor
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightModifierList
|
||||
import org.jetbrains.kotlin.asJava.hasInterfaceDefaultImpls
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.config.JvmDefaultMode
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.psi.KtClassBody
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
private class KtLightClassModifierList(containingClass: KtLightClassForSourceDeclaration, computeModifiers: () -> Set<String>) :
|
||||
KtLightModifierList<KtLightClassForSourceDeclaration>(containingClass) {
|
||||
|
||||
private val modifiers by lazyPub { computeModifiers() }
|
||||
|
||||
override fun hasModifierProperty(name: String): Boolean =
|
||||
if (name != PsiModifier.FINAL) name in modifiers else owner.isFinal(PsiModifier.FINAL in modifiers)
|
||||
}
|
||||
|
||||
// light class for top level or (inner/nested of top level) source declarations
|
||||
abstract class KtLightClassImpl @JvmOverloads constructor(
|
||||
classOrObject: KtClassOrObject,
|
||||
@@ -28,6 +43,15 @@ abstract class KtLightClassImpl @JvmOverloads constructor(
|
||||
fun getDescriptor() =
|
||||
LightClassGenerationSupport.getInstance(project).resolveToDescriptor(classOrObject) as? ClassDescriptor
|
||||
|
||||
private val _deprecated by lazyPub { classOrObject.isDeprecated() }
|
||||
|
||||
override fun isDeprecated(): Boolean = _deprecated
|
||||
|
||||
|
||||
private val _modifierList: PsiModifierList by lazyPub { KtLightClassModifierList(this) { computeModifiers() } }
|
||||
|
||||
override fun getModifierList(): PsiModifierList? = _modifierList
|
||||
|
||||
override fun computeModifiers(): Set<String> {
|
||||
val psiModifiers = hashSetOf<String>()
|
||||
|
||||
@@ -110,41 +134,129 @@ abstract class KtLightClassImpl @JvmOverloads constructor(
|
||||
containingClass
|
||||
|
||||
abstract override fun copy(): PsiElement
|
||||
}
|
||||
|
||||
private fun checkSuperTypeByFQName(classDescriptor: ClassDescriptor, qualifiedName: String, deep: Boolean): Boolean {
|
||||
if (CommonClassNames.JAVA_LANG_OBJECT == qualifiedName) return true
|
||||
private val _containingFile: PsiFile by lazyPub {
|
||||
object : FakeFileForLightClass(
|
||||
classOrObject.containingKtFile,
|
||||
{ if (classOrObject.isTopLevel()) this else create(getOutermostClassOrObject(classOrObject))!! },
|
||||
) {
|
||||
override fun findReferenceAt(offset: Int) = ktFile.findReferenceAt(offset)
|
||||
|
||||
if (qualifiedName == DescriptorUtils.getFqName(classDescriptor).asString()) return true
|
||||
override fun processDeclarations(
|
||||
processor: PsiScopeProcessor,
|
||||
state: ResolveState,
|
||||
lastParent: PsiElement?,
|
||||
place: PsiElement
|
||||
): Boolean {
|
||||
if (!super.processDeclarations(processor, state, lastParent, place)) return false
|
||||
|
||||
val fqName = FqNameUnsafe(qualifiedName)
|
||||
val mappedQName =
|
||||
if (fqName.isSafe)
|
||||
JavaToKotlinClassMap.mapJavaToKotlin(fqName.toSafe())?.asSingleFqName()?.asString()
|
||||
else null
|
||||
if (qualifiedName == mappedQName) return true
|
||||
// We have to explicitly process package declarations if current file belongs to default package
|
||||
// so that Java resolve can find classes located in that package
|
||||
val packageName = packageName
|
||||
if (packageName.isNotEmpty()) return true
|
||||
|
||||
for (superType in classDescriptor.typeConstructor.supertypes) {
|
||||
val superDescriptor = superType.constructor.declarationDescriptor
|
||||
val aPackage = JavaPsiFacade.getInstance(myManager.project).findPackage(packageName)
|
||||
if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false
|
||||
|
||||
if (superDescriptor is ClassDescriptor) {
|
||||
val superQName = DescriptorUtils.getFqName(superDescriptor).asString()
|
||||
if (superQName == qualifiedName || superQName == mappedQName) return true
|
||||
|
||||
if (deep) {
|
||||
if (checkSuperTypeByFQName(superDescriptor, qualifiedName, true)) {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
override fun getContainingFile(): PsiFile? = _containingFile
|
||||
|
||||
private val jetTokenToPsiModifier = listOf(
|
||||
KtTokens.PUBLIC_KEYWORD to PsiModifier.PUBLIC,
|
||||
KtTokens.INTERNAL_KEYWORD to PsiModifier.PUBLIC,
|
||||
KtTokens.PROTECTED_KEYWORD to PsiModifier.PROTECTED,
|
||||
KtTokens.FINAL_KEYWORD to PsiModifier.FINAL,
|
||||
)
|
||||
override fun getOwnInnerClasses(): List<PsiClass> {
|
||||
val result = ArrayList<PsiClass>()
|
||||
classOrObject.declarations.filterIsInstance<KtClassOrObject>()
|
||||
// workaround for ClassInnerStuffCache not supporting classes with null names, see KT-13927
|
||||
// inner classes with null names can't be searched for and can't be used from java anyway
|
||||
// we can't prohibit creating light classes with null names either since they can contain members
|
||||
.filter { it.name != null }
|
||||
.mapNotNullTo(result) {
|
||||
create(it)
|
||||
}
|
||||
|
||||
if (classOrObject.hasInterfaceDefaultImpls && jvmDefaultMode != JvmDefaultMode.ALL_INCOMPATIBLE) {
|
||||
result.add(createClassForInterfaceDefaultImpls())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
protected abstract fun createClassForInterfaceDefaultImpls(): PsiClass
|
||||
|
||||
override fun getContainingClass(): PsiClass? {
|
||||
if (classOrObject.parent === classOrObject.containingFile) return null
|
||||
|
||||
val containingClassOrObject = (classOrObject.parent as? KtClassBody)?.parent as? KtClassOrObject
|
||||
if (containingClassOrObject != null) {
|
||||
return create(containingClassOrObject)
|
||||
}
|
||||
|
||||
// TODO: should return null
|
||||
return super.getContainingClass()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun checkSuperTypeByFQName(classDescriptor: ClassDescriptor, qualifiedName: String, deep: Boolean): Boolean {
|
||||
if (CommonClassNames.JAVA_LANG_OBJECT == qualifiedName) return true
|
||||
|
||||
if (qualifiedName == DescriptorUtils.getFqName(classDescriptor).asString()) return true
|
||||
|
||||
val fqName = FqNameUnsafe(qualifiedName)
|
||||
val mappedQName =
|
||||
if (fqName.isSafe)
|
||||
JavaToKotlinClassMap.mapJavaToKotlin(fqName.toSafe())?.asSingleFqName()?.asString()
|
||||
else null
|
||||
if (qualifiedName == mappedQName) return true
|
||||
|
||||
for (superType in classDescriptor.typeConstructor.supertypes) {
|
||||
val superDescriptor = superType.constructor.declarationDescriptor
|
||||
|
||||
if (superDescriptor is ClassDescriptor) {
|
||||
val superQName = DescriptorUtils.getFqName(superDescriptor).asString()
|
||||
if (superQName == qualifiedName || superQName == mappedQName) return true
|
||||
|
||||
if (deep) {
|
||||
if (checkSuperTypeByFQName(superDescriptor, qualifiedName, true)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private val jetTokenToPsiModifier = listOf(
|
||||
KtTokens.PUBLIC_KEYWORD to PsiModifier.PUBLIC,
|
||||
KtTokens.INTERNAL_KEYWORD to PsiModifier.PUBLIC,
|
||||
KtTokens.PROTECTED_KEYWORD to PsiModifier.PROTECTED,
|
||||
KtTokens.FINAL_KEYWORD to PsiModifier.FINAL,
|
||||
)
|
||||
|
||||
fun create(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? =
|
||||
CachedValuesManager.getCachedValue(classOrObject) {
|
||||
CachedValueProvider.Result.create(
|
||||
createNoCache(classOrObject),
|
||||
KotlinModificationTrackerService.getInstance(classOrObject.project).outOfBlockModificationTracker,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createNoCache(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? {
|
||||
val containingFile = classOrObject.containingFile
|
||||
if (containingFile is KtCodeFragment) {
|
||||
// Avoid building light classes for code fragments
|
||||
return null
|
||||
}
|
||||
|
||||
if (classOrObject.shouldNotBeVisibleAsLightClass()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return LightClassGenerationSupport.getInstance(classOrObject.project).run {
|
||||
createUltraLightClass(classOrObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user