Light classes: allow light classes for inner/nested classes to be build separately
Avoid analyzing/generating bytecode for outers
This commit is contained in:
+13
-21
@@ -34,11 +34,10 @@ import com.intellij.psi.stubs.StubElement
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject
|
||||
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
||||
@@ -48,8 +47,8 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
|
||||
abstract class LightClassDataProvider<T : WithFileStubAndExtraDiagnostics>(
|
||||
@@ -177,21 +176,13 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
|
||||
javaFileStub: PsiJavaFileStub,
|
||||
bindingContext: BindingContext,
|
||||
extraDiagnostics: Diagnostics): WithFileStubAndExtraDiagnostics {
|
||||
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject) ?: return InvalidLightClassData
|
||||
bindingContext.get(BindingContext.CLASS, classOrObject) ?: return InvalidLightClassData
|
||||
|
||||
val allInnerClasses = CodegenBinding.getAllInnerClasses(bindingContext, classDescriptor)
|
||||
|
||||
val innerClassesMap = ContainerUtil.newHashMap<KtClassOrObject, InnerKotlinClassLightClassData>()
|
||||
for (innerClassDescriptor in allInnerClasses) {
|
||||
val declaration = descriptorToDeclaration(innerClassDescriptor) as? KtClassOrObject ?: continue
|
||||
innerClassesMap.put(declaration, InnerKotlinClassLightClassData(declaration))
|
||||
}
|
||||
|
||||
return OutermostKotlinClassLightClassData(
|
||||
javaFileStub,
|
||||
extraDiagnostics,
|
||||
classOrObject,
|
||||
innerClassesMap)
|
||||
classOrObject)
|
||||
}
|
||||
|
||||
override val files: Collection<KtFile>
|
||||
@@ -211,15 +202,11 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
|
||||
return shouldGenerateClass(processingClassOrObject)
|
||||
}
|
||||
|
||||
override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean {
|
||||
// Trivial: generate and analyze class we are interested in.
|
||||
override fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject): Boolean {
|
||||
if (classOrObject === processingClassOrObject) return true
|
||||
|
||||
// Process all parent classes as they are context for current class
|
||||
// Process child classes because they probably affect members (heuristic)
|
||||
|
||||
if (PsiTreeUtil.isAncestor(classOrObject, processingClassOrObject, true) ||
|
||||
PsiTreeUtil.isAncestor(processingClassOrObject, classOrObject, true)) {
|
||||
// process all children
|
||||
if (classOrObject.isAncestor(processingClassOrObject, true)) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -245,6 +232,11 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean {
|
||||
// generate outer classes but not their members
|
||||
return shouldGenerateClassMembers(processingClassOrObject) || processingClassOrObject.isAncestor(classOrObject, true)
|
||||
}
|
||||
|
||||
override fun shouldGenerateScript(script: KtScript): Boolean {
|
||||
return PsiTreeUtil.isAncestor(script, classOrObject, false)
|
||||
}
|
||||
@@ -255,7 +247,7 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
|
||||
val file = classOrObject.containingKtFile
|
||||
val packagePartType = state.fileClassesProvider.getFileClassType(file)
|
||||
val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file)
|
||||
packageCodegen.generateClassOrObject(classOrObject, context)
|
||||
packageCodegen.generateClassOrObject(getOutermostClassOrObject(classOrObject), context)
|
||||
state.factory.asList()
|
||||
}
|
||||
|
||||
|
||||
+2
-8
@@ -55,11 +55,5 @@ data class InnerKotlinClassLightClassData(
|
||||
data class OutermostKotlinClassLightClassData(
|
||||
override val javaFileStub: PsiJavaFileStub,
|
||||
override val extraDiagnostics: Diagnostics,
|
||||
override val classOrObject: KtClassOrObject,
|
||||
val allInnerClasses: Map<KtClassOrObject, InnerKotlinClassLightClassData>
|
||||
): LightClassDataForKotlinClass, WithFileStubAndExtraDiagnostics {
|
||||
|
||||
fun dataForClass(cls: KtClassOrObject): LightClassDataForKotlinClass? =
|
||||
if (cls == classOrObject) this else allInnerClasses[cls]
|
||||
|
||||
}
|
||||
override val classOrObject: KtClassOrObject
|
||||
): LightClassDataForKotlinClass, WithFileStubAndExtraDiagnostics
|
||||
|
||||
+13
-11
@@ -388,23 +388,17 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
|
||||
}
|
||||
|
||||
fun getLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue<WithFileStubAndExtraDiagnostics> {
|
||||
val outermostClassOrObject = getOutermostClassOrObject(classOrObject)
|
||||
var value = outermostClassOrObject.getUserData(JAVA_API_STUB)
|
||||
var value =
|
||||
getOutermostClassOrObject(classOrObject).getUserData(JAVA_API_STUB) // stub computed for outer class can be used for inner/nested
|
||||
?: classOrObject.getUserData (JAVA_API_STUB)
|
||||
if (value == null) {
|
||||
value = CachedValuesManager.getManager(classOrObject.project).createCachedValue(
|
||||
LightClassDataProviderForClassOrObject(outermostClassOrObject), false)
|
||||
value = outermostClassOrObject.putUserDataIfAbsent(JAVA_API_STUB, value)
|
||||
LightClassDataProviderForClassOrObject(classOrObject), false)
|
||||
value = classOrObject.putUserDataIfAbsent(JAVA_API_STUB, value)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
private fun getOutermostClassOrObject(classOrObject: KtClassOrObject): KtClassOrObject {
|
||||
val outermostClass = KtPsiUtil.getOutermostClassOrObject(classOrObject) ?:
|
||||
throw IllegalStateException("Attempt to build a light class for a local class: " + classOrObject.text)
|
||||
|
||||
return outermostClass
|
||||
}
|
||||
|
||||
private fun checkSuperTypeByFQName(classDescriptor: ClassDescriptor, qualifiedName: String, deep: Boolean): Boolean {
|
||||
if (CommonClassNames.JAVA_LANG_OBJECT == qualifiedName) return true
|
||||
|
||||
@@ -441,3 +435,11 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
|
||||
override val originKind: LightClassOriginKind
|
||||
get() = LightClassOriginKind.SOURCE
|
||||
}
|
||||
|
||||
fun getOutermostClassOrObject(classOrObject: KtClassOrObject): KtClassOrObject {
|
||||
val outermostClass = KtPsiUtil.getOutermostClassOrObject(classOrObject) ?:
|
||||
throw IllegalStateException("Attempt to build a light class for a local class: " + classOrObject.text)
|
||||
|
||||
return outermostClass
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user