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();
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() {
@@ -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()
}
@@ -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
@@ -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
}