Support declarations returning object literals in ultra-light classes

This commit is contained in:
Denis Zharkov
2018-11-20 12:24:26 +03:00
parent 28f20a97f8
commit 7de8b4de4e
8 changed files with 250 additions and 46 deletions
@@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement;
import kotlin.Pair;
import kotlin.Unit;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
@@ -89,6 +90,8 @@ public class KotlinTypeMapper {
private final LanguageVersionSettings languageVersionSettings;
private final boolean isReleaseCoroutines;
private final boolean isIrBackend;
@Nullable
private final Function1<KotlinType, KotlinType> typePreprocessor;
private final TypeMappingConfiguration<Type> typeMappingConfiguration = new TypeMappingConfiguration<Type>() {
@NotNull
@@ -121,6 +124,13 @@ public class KotlinTypeMapper {
public boolean releaseCoroutines() {
return isReleaseCoroutines;
}
@Nullable
@Override
public KotlinType preprocessType(@NotNull KotlinType kotlinType) {
if (typePreprocessor == null) return null;
return typePreprocessor.invoke(kotlinType);
}
};
private static final TypeMappingConfiguration<Type> staticTypeMappingConfiguration = new TypeMappingConfiguration<Type>() {
@@ -151,8 +161,35 @@ public class KotlinTypeMapper {
public boolean releaseCoroutines() {
return false;
}
@Nullable
@Override
public KotlinType preprocessType(@NotNull KotlinType kotlinType) {
return null;
}
};
public KotlinTypeMapper(
@NotNull BindingContext bindingContext,
@NotNull ClassBuilderMode classBuilderMode,
@NotNull IncompatibleClassTracker incompatibleClassTracker,
@NotNull String moduleName,
@NotNull JvmTarget jvmTarget,
@NotNull LanguageVersionSettings languageVersionSettings,
boolean isIrBackend,
@Nullable Function1<KotlinType, KotlinType> typePreprocessor
) {
this.bindingContext = bindingContext;
this.classBuilderMode = classBuilderMode;
this.incompatibleClassTracker = incompatibleClassTracker;
this.moduleName = moduleName;
this.jvmTarget = jvmTarget;
this.languageVersionSettings = languageVersionSettings;
this.isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines);
this.isIrBackend = isIrBackend;
this.typePreprocessor = typePreprocessor;
}
public KotlinTypeMapper(
@NotNull BindingContext bindingContext,
@NotNull ClassBuilderMode classBuilderMode,
@@ -162,14 +199,7 @@ public class KotlinTypeMapper {
@NotNull LanguageVersionSettings languageVersionSettings,
boolean isIrBackend
) {
this.bindingContext = bindingContext;
this.classBuilderMode = classBuilderMode;
this.incompatibleClassTracker = incompatibleClassTracker;
this.moduleName = moduleName;
this.jvmTarget = jvmTarget;
this.languageVersionSettings = languageVersionSettings;
this.isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines);
this.isIrBackend = isIrBackend;
this(bindingContext, classBuilderMode, incompatibleClassTracker, moduleName, jvmTarget, languageVersionSettings, isIrBackend, null);
}
/**
@@ -21,13 +21,18 @@ import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.replace
import org.jetbrains.kotlin.types.typeUtil.supertypes
import java.text.StringCharacterIterator
internal fun buildTypeParameterList(
@@ -105,5 +110,38 @@ internal fun typeMapper(support: UltraLightSupport): KotlinTypeMapper = KotlinTy
IncompatibleClassTracker.DoNothing, support.moduleName,
JvmTarget.JVM_1_8,
KotlinTypeMapper.LANGUAGE_VERSION_SETTINGS_DEFAULT, // TODO use proper LanguageVersionSettings
false
false,
KotlinType::cleanFromAnonymousTypes
)
// Returns null when type is unchanged
fun KotlinType.cleanFromAnonymousTypes(): KotlinType? {
val returnTypeClass = constructor.declarationDescriptor as? ClassDescriptor ?: return null
if (DescriptorUtils.isAnonymousObject(returnTypeClass)) {
// We choose just the first supertype because:
// - In public declarations, object literals should always have a single supertype (otherwise it's an error)
// - For private declarations, they might have more than one supertype
// but it looks like it's not important how we choose a representative for them
val representative = returnTypeClass.defaultType.supertypes().firstOrNull() ?: return null
return representative.cleanFromAnonymousTypes() ?: representative
}
if (arguments.isEmpty()) return null
var wasUpdates = false
val newArguments = arguments.map { typeProjection ->
val updatedType =
typeProjection.takeUnless { it.isStarProjection }
?.type?.cleanFromAnonymousTypes()
?: return@map typeProjection
wasUpdates = true
TypeProjectionImpl(typeProjection.projectionKind, updatedType)
}
if (!wasUpdates) return null
return replace(newArguments = newArguments)
}
@@ -0,0 +1,101 @@
public final class Prop /* Prop*/ {
@org.jetbrains.annotations.NotNull()
private final java.lang.Object someProp;
@null()
public Prop();
}
public final class Fun /* Fun*/ {
@null()
public Fun();
@org.jetbrains.annotations.NotNull()
private final java.lang.Object someFun();
}
public final class ArrayOfAnonymous /* ArrayOfAnonymous*/ {
@org.jetbrains.annotations.NotNull()
private final java.lang.Object[] a1;
@null()
public ArrayOfAnonymous();
@org.jetbrains.annotations.NotNull()
public final java.lang.Object[] getA1();
}
final class C /* C*/ {
@null()
private final int y;
@org.jetbrains.annotations.NotNull()
private final kotlin.jvm.functions.Function0<java.lang.Object> initChild;
@null()
public C(@null() int);
@null()
public final int getY();
@org.jetbrains.annotations.NotNull()
public final kotlin.jvm.functions.Function0<java.lang.Object> getInitChild();
}
public abstract class Super /* Super*/ {
@null()
public Super();
@org.jetbrains.annotations.Nullable()
public abstract java.lang.Object getA();
}
public final class Sub /* Sub*/ extends Super {
@org.jetbrains.annotations.NotNull()
private final java.lang.Object[] a;
@null()
public Sub();
@org.jetbrains.annotations.NotNull()
public java.lang.Object[] getA();
}
public final class ValidPublicSupertype /* ValidPublicSupertype*/ {
@org.jetbrains.annotations.NotNull()
private final java.lang.Runnable x;
@null()
public ValidPublicSupertype();
@org.jetbrains.annotations.NotNull()
public final java.lang.Runnable bar();
@org.jetbrains.annotations.NotNull()
public final java.lang.Runnable getX();
}
public abstract interface I /* I*/ {
}
public final class InvalidPublicSupertype /* InvalidPublicSupertype*/ {
@org.jetbrains.annotations.NotNull()
private final java.lang.Runnable x;
@null()
public InvalidPublicSupertype();
@org.jetbrains.annotations.NotNull()
public final java.lang.Runnable bar();
@org.jetbrains.annotations.NotNull()
public final java.lang.Runnable getX();
}
@@ -1,22 +1,21 @@
/** should load cls */
class Prop {
private val someProp = object { }
}
/** should load cls */
class Fun {
private fun someFun() = object { }
}
/** should load cls */
class Array {
class ArrayOfAnonymous {
val a1 = arrayOf(
object { val fy = "text"}
)
}
/** should load cls */
private class C(val y: Int) {
val initChild = { ->
object {
@@ -28,14 +27,34 @@ private class C(val y: Int) {
}
class Super {
val a: Any?
abstract class Super {
abstract val a: Any?
}
/** should load cls */
class Sub {
class Sub : Super() {
override val a = arrayOf(
object { val fy = "text"}
)
}
}
class ValidPublicSupertype {
val x = object : Runnable {
override fun run() {}
}
fun bar() = object : Runnable {
override fun run() {}
}
}
interface I
class InvalidPublicSupertype {
val x = object : Runnable, I {
override fun run() {}
}
fun bar() = object : Runnable, I {
override fun run() {}
}
}