Light classes: allow light classes for inner/nested classes to be build separately
Avoid analyzing/generating bytecode for outers
This commit is contained in:
@@ -77,9 +77,13 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
}
|
||||
}
|
||||
|
||||
generatePrimaryConstructorProperties();
|
||||
generateConstructors();
|
||||
generateDefaultImplsIfNeeded();
|
||||
boolean generateNonClassMembers = shouldGenerateNonClassMembers();
|
||||
|
||||
if (generateNonClassMembers) {
|
||||
generatePrimaryConstructorProperties();
|
||||
generateConstructors();
|
||||
generateDefaultImplsIfNeeded();
|
||||
}
|
||||
|
||||
// Generate _declared_ companions
|
||||
for (KtObjectDeclaration companion : companions) {
|
||||
@@ -92,23 +96,30 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
genSyntheticClassOrObject((SyntheticClassOrObjectDescriptor) companionObjectDescriptor);
|
||||
}
|
||||
|
||||
if (!DescriptorUtils.isInterface(descriptor)) {
|
||||
for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
|
||||
if (memberDescriptor instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor member = (CallableMemberDescriptor) memberDescriptor;
|
||||
if (!member.getKind().isReal() && ImplKt.findInterfaceImplementation(member) == null) {
|
||||
if (member instanceof FunctionDescriptor) {
|
||||
functionCodegen.generateBridges((FunctionDescriptor) member);
|
||||
if (generateNonClassMembers) {
|
||||
generateBridges();
|
||||
}
|
||||
}
|
||||
|
||||
private void generateBridges() {
|
||||
if (DescriptorUtils.isInterface(descriptor)) {
|
||||
return;
|
||||
}
|
||||
for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
|
||||
if (memberDescriptor instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor member = (CallableMemberDescriptor) memberDescriptor;
|
||||
if (!member.getKind().isReal() && ImplKt.findInterfaceImplementation(member) == null) {
|
||||
if (member instanceof FunctionDescriptor) {
|
||||
functionCodegen.generateBridges((FunctionDescriptor) member);
|
||||
}
|
||||
else if (member instanceof PropertyDescriptor) {
|
||||
PropertyGetterDescriptor getter = ((PropertyDescriptor) member).getGetter();
|
||||
if (getter != null) {
|
||||
functionCodegen.generateBridges(getter);
|
||||
}
|
||||
else if (member instanceof PropertyDescriptor) {
|
||||
PropertyGetterDescriptor getter = ((PropertyDescriptor) member).getGetter();
|
||||
if (getter != null) {
|
||||
functionCodegen.generateBridges(getter);
|
||||
}
|
||||
PropertySetterDescriptor setter = ((PropertyDescriptor) member).getSetter();
|
||||
if (setter != null) {
|
||||
functionCodegen.generateBridges(setter);
|
||||
}
|
||||
PropertySetterDescriptor setter = ((PropertyDescriptor) member).getSetter();
|
||||
if (setter != null) {
|
||||
functionCodegen.generateBridges(setter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,6 +127,11 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldGenerateNonClassMembers() {
|
||||
return !(myClass instanceof KtClassOrObject) ||
|
||||
state.getGenerateDeclaredClassFilter().shouldGenerateClassMembers((KtClassOrObject) myClass);
|
||||
}
|
||||
|
||||
protected void generateConstructors() {
|
||||
|
||||
}
|
||||
@@ -130,7 +146,9 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
|
||||
protected void generateDeclaration(KtDeclaration declaration) {
|
||||
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) {
|
||||
genSimpleMember(declaration);
|
||||
if (shouldGenerateNonClassMembers()) {
|
||||
genSimpleMember(declaration);
|
||||
}
|
||||
}
|
||||
else if (declaration instanceof KtClassOrObject) {
|
||||
if (declaration instanceof KtEnumEntry && !enumEntryNeedSubclass(bindingContext, (KtEnumEntry) declaration)) {
|
||||
|
||||
@@ -127,7 +127,10 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
|
||||
generateBody();
|
||||
|
||||
generateSyntheticParts();
|
||||
if (!(element instanceof KtClassOrObject) ||
|
||||
state.getGenerateDeclaredClassFilter().shouldGenerateClassMembers((KtClassOrObject) element)) {
|
||||
generateSyntheticParts();
|
||||
}
|
||||
|
||||
if (state.getClassBuilderMode().generateMetadata) {
|
||||
generateKotlinMetadataAnnotation();
|
||||
|
||||
@@ -71,6 +71,7 @@ class GenerationState @JvmOverloads constructor(
|
||||
abstract fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean
|
||||
abstract fun shouldGeneratePackagePart(jetFile: KtFile): Boolean
|
||||
abstract fun shouldGenerateScript(script: KtScript): Boolean
|
||||
open fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject)
|
||||
|
||||
companion object {
|
||||
@JvmField val GENERATE_ALL: GenerateClassFilter = object : GenerateClassFilter() {
|
||||
|
||||
+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