Light classes: allow light classes for inner/nested classes to be build separately

Avoid analyzing/generating bytecode for outers
This commit is contained in:
Pavel V. Talanov
2017-02-06 18:37:51 +03:00
parent 6924ddeace
commit 1441aea2ea
6 changed files with 71 additions and 61 deletions
@@ -77,9 +77,13 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
} }
} }
generatePrimaryConstructorProperties(); boolean generateNonClassMembers = shouldGenerateNonClassMembers();
generateConstructors();
generateDefaultImplsIfNeeded(); if (generateNonClassMembers) {
generatePrimaryConstructorProperties();
generateConstructors();
generateDefaultImplsIfNeeded();
}
// Generate _declared_ companions // Generate _declared_ companions
for (KtObjectDeclaration companion : companions) { for (KtObjectDeclaration companion : companions) {
@@ -92,23 +96,30 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
genSyntheticClassOrObject((SyntheticClassOrObjectDescriptor) companionObjectDescriptor); genSyntheticClassOrObject((SyntheticClassOrObjectDescriptor) companionObjectDescriptor);
} }
if (!DescriptorUtils.isInterface(descriptor)) { if (generateNonClassMembers) {
for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) { generateBridges();
if (memberDescriptor instanceof CallableMemberDescriptor) { }
CallableMemberDescriptor member = (CallableMemberDescriptor) memberDescriptor; }
if (!member.getKind().isReal() && ImplKt.findInterfaceImplementation(member) == null) {
if (member instanceof FunctionDescriptor) { private void generateBridges() {
functionCodegen.generateBridges((FunctionDescriptor) member); 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) { PropertySetterDescriptor setter = ((PropertyDescriptor) member).getSetter();
PropertyGetterDescriptor getter = ((PropertyDescriptor) member).getGetter(); if (setter != null) {
if (getter != null) { functionCodegen.generateBridges(setter);
functionCodegen.generateBridges(getter);
}
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() { protected void generateConstructors() {
} }
@@ -130,7 +146,9 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
protected void generateDeclaration(KtDeclaration declaration) { protected void generateDeclaration(KtDeclaration declaration) {
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) { if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) {
genSimpleMember(declaration); if (shouldGenerateNonClassMembers()) {
genSimpleMember(declaration);
}
} }
else if (declaration instanceof KtClassOrObject) { else if (declaration instanceof KtClassOrObject) {
if (declaration instanceof KtEnumEntry && !enumEntryNeedSubclass(bindingContext, (KtEnumEntry) declaration)) { if (declaration instanceof KtEnumEntry && !enumEntryNeedSubclass(bindingContext, (KtEnumEntry) declaration)) {
@@ -127,7 +127,10 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
generateBody(); generateBody();
generateSyntheticParts(); if (!(element instanceof KtClassOrObject) ||
state.getGenerateDeclaredClassFilter().shouldGenerateClassMembers((KtClassOrObject) element)) {
generateSyntheticParts();
}
if (state.getClassBuilderMode().generateMetadata) { if (state.getClassBuilderMode().generateMetadata) {
generateKotlinMetadataAnnotation(); generateKotlinMetadataAnnotation();
@@ -71,6 +71,7 @@ class GenerationState @JvmOverloads constructor(
abstract fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean abstract fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean
abstract fun shouldGeneratePackagePart(jetFile: KtFile): Boolean abstract fun shouldGeneratePackagePart(jetFile: KtFile): Boolean
abstract fun shouldGenerateScript(script: KtScript): Boolean abstract fun shouldGenerateScript(script: KtScript): Boolean
open fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject)
companion object { companion object {
@JvmField val GENERATE_ALL: GenerateClassFilter = object : GenerateClassFilter() { @JvmField val GENERATE_ALL: GenerateClassFilter = object : GenerateClassFilter() {
@@ -34,11 +34,10 @@ import com.intellij.psi.stubs.StubElement
import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.PsiModificationTracker
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.Stack import com.intellij.util.containers.Stack
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject
import org.jetbrains.kotlin.codegen.CompilationErrorHandler import org.jetbrains.kotlin.codegen.CompilationErrorHandler
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider 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.KtFile
import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
abstract class LightClassDataProvider<T : WithFileStubAndExtraDiagnostics>( abstract class LightClassDataProvider<T : WithFileStubAndExtraDiagnostics>(
@@ -177,21 +176,13 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
javaFileStub: PsiJavaFileStub, javaFileStub: PsiJavaFileStub,
bindingContext: BindingContext, bindingContext: BindingContext,
extraDiagnostics: Diagnostics): WithFileStubAndExtraDiagnostics { 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( return OutermostKotlinClassLightClassData(
javaFileStub, javaFileStub,
extraDiagnostics, extraDiagnostics,
classOrObject, classOrObject)
innerClassesMap)
} }
override val files: Collection<KtFile> override val files: Collection<KtFile>
@@ -211,15 +202,11 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
return shouldGenerateClass(processingClassOrObject) return shouldGenerateClass(processingClassOrObject)
} }
override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean { override fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject): Boolean {
// Trivial: generate and analyze class we are interested in.
if (classOrObject === processingClassOrObject) return true if (classOrObject === processingClassOrObject) return true
// Process all parent classes as they are context for current class // process all children
// Process child classes because they probably affect members (heuristic) if (classOrObject.isAncestor(processingClassOrObject, true)) {
if (PsiTreeUtil.isAncestor(classOrObject, processingClassOrObject, true) ||
PsiTreeUtil.isAncestor(processingClassOrObject, classOrObject, true)) {
return true return true
} }
@@ -245,6 +232,11 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
return false 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 { override fun shouldGenerateScript(script: KtScript): Boolean {
return PsiTreeUtil.isAncestor(script, classOrObject, false) return PsiTreeUtil.isAncestor(script, classOrObject, false)
} }
@@ -255,7 +247,7 @@ class LightClassDataProviderForClassOrObject(private val classOrObject: KtClassO
val file = classOrObject.containingKtFile val file = classOrObject.containingKtFile
val packagePartType = state.fileClassesProvider.getFileClassType(file) val packagePartType = state.fileClassesProvider.getFileClassType(file)
val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file) val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file)
packageCodegen.generateClassOrObject(classOrObject, context) packageCodegen.generateClassOrObject(getOutermostClassOrObject(classOrObject), context)
state.factory.asList() state.factory.asList()
} }
@@ -55,11 +55,5 @@ data class InnerKotlinClassLightClassData(
data class OutermostKotlinClassLightClassData( data class OutermostKotlinClassLightClassData(
override val javaFileStub: PsiJavaFileStub, override val javaFileStub: PsiJavaFileStub,
override val extraDiagnostics: Diagnostics, override val extraDiagnostics: Diagnostics,
override val classOrObject: KtClassOrObject, override val classOrObject: KtClassOrObject
val allInnerClasses: Map<KtClassOrObject, InnerKotlinClassLightClassData> ): LightClassDataForKotlinClass, WithFileStubAndExtraDiagnostics
): LightClassDataForKotlinClass, WithFileStubAndExtraDiagnostics {
fun dataForClass(cls: KtClassOrObject): LightClassDataForKotlinClass? =
if (cls == classOrObject) this else allInnerClasses[cls]
}
@@ -388,23 +388,17 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
} }
fun getLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue<WithFileStubAndExtraDiagnostics> { fun getLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue<WithFileStubAndExtraDiagnostics> {
val outermostClassOrObject = getOutermostClassOrObject(classOrObject) var value =
var value = outermostClassOrObject.getUserData(JAVA_API_STUB) 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) { if (value == null) {
value = CachedValuesManager.getManager(classOrObject.project).createCachedValue( value = CachedValuesManager.getManager(classOrObject.project).createCachedValue(
LightClassDataProviderForClassOrObject(outermostClassOrObject), false) LightClassDataProviderForClassOrObject(classOrObject), false)
value = outermostClassOrObject.putUserDataIfAbsent(JAVA_API_STUB, value) value = classOrObject.putUserDataIfAbsent(JAVA_API_STUB, value)
} }
return 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 { private fun checkSuperTypeByFQName(classDescriptor: ClassDescriptor, qualifiedName: String, deep: Boolean): Boolean {
if (CommonClassNames.JAVA_LANG_OBJECT == qualifiedName) return true if (CommonClassNames.JAVA_LANG_OBJECT == qualifiedName) return true
@@ -441,3 +435,11 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
override val originKind: LightClassOriginKind override val originKind: LightClassOriginKind
get() = LightClassOriginKind.SOURCE 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
}