Support data classes in ultra-light classes

This commit is contained in:
Denis Zharkov
2018-12-03 17:56:18 +03:00
parent 8b65311769
commit dbf9ff29a9
7 changed files with 248 additions and 18 deletions
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver;
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker;
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.jvm.*;
import org.jetbrains.kotlin.resolve.jvm.checkers.DalvikIdentifierUtils;
@@ -311,7 +312,11 @@ public class AsmUtil {
}
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) {
int flags = getCommonCallableFlags(functionDescriptor, kind, state);
return getMethodAsmFlags(functionDescriptor, kind, state.getDeprecationProvider());
}
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind, DeprecationResolver deprecationResolver) {
int flags = getCommonCallableFlags(functionDescriptor, kind, deprecationResolver);
for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) {
flags |= flagAnnotation.getJvmFlag(functionDescriptor.getOriginal());
@@ -361,18 +366,18 @@ public class AsmUtil {
}
public static int getCommonCallableFlags(FunctionDescriptor functionDescriptor, @NotNull GenerationState state) {
return getCommonCallableFlags(functionDescriptor, null, state);
return getCommonCallableFlags(functionDescriptor, null, state.getDeprecationProvider());
}
private static int getCommonCallableFlags(
FunctionDescriptor functionDescriptor,
@Nullable OwnerKind kind,
@NotNull GenerationState state
@NotNull DeprecationResolver deprecationResolver
) {
int flags = getVisibilityAccessFlag(functionDescriptor, kind);
flags |= getVarargsFlag(functionDescriptor);
flags |= getDeprecatedAccessFlag(functionDescriptor);
if (state.getDeprecationProvider().isDeprecatedHidden(functionDescriptor) ||
if (deprecationResolver.isDeprecatedHidden(functionDescriptor) ||
(functionDescriptor.isSuspend()) && functionDescriptor.getVisibility().equals(Visibilities.PRIVATE)) {
flags |= ACC_SYNTHETIC;
}
@@ -74,7 +74,7 @@ public class JvmCodegenUtil {
return !hasJvmDefaultAnnotation(descriptor);
}
public static boolean isJvmInterface(DeclarationDescriptor descriptor) {
public static boolean isJvmInterface(@Nullable DeclarationDescriptor descriptor) {
if (descriptor instanceof ClassDescriptor) {
ClassKind kind = ((ClassDescriptor) descriptor).getKind();
return kind == INTERFACE || kind == ANNOTATION_CLASS;
@@ -91,6 +91,24 @@ internal class KtUltraLightMethodForSourceDeclaration(
override fun computeDescriptor() = kotlinOrigin?.resolve() as? FunctionDescriptor
}
internal class KtUltraLightMethodForDescriptor(
private val descriptor: FunctionDescriptor,
delegate: LightMethodBuilder,
closestDeclarationForOrigin: KtDeclaration?,
support: UltraLightSupport,
containingClass: KtUltraLightClass
) : KtUltraLightMethod(
delegate,
closestDeclarationForOrigin,
support,
containingClass
) {
override fun buildTypeParameterList() = buildTypeParameterList(descriptor, this, support)
override fun computeDescriptor() = descriptor
override val kotlinTypeForNullabilityAnnotation: KotlinType?
get() = descriptor.returnType
}
internal abstract class KtUltraLightParameter(
@@ -212,3 +230,20 @@ internal class KtUltraLightReceiverParameter(
computeContainingDescriptor()?.extensionReceiverParameter?.type
}
}
internal class KtUltraLightParameterForDescriptor(
private val descriptor: ParameterDescriptor,
kotlinOrigin: KtDeclaration?,
support: UltraLightSupport,
method: KtLightMethod
) : KtUltraLightParameter(
if (descriptor.name.isSpecial) "\$self" else descriptor.name.identifier,
kotlinOrigin, support, method
) {
override val kotlinType: KotlinType?
get() = descriptor.type
override fun computeContainingDescriptor() = descriptor.containingDeclaration as? CallableMemberDescriptor
override fun isVarArgs() = (descriptor as? ValueParameterDescriptor)?.varargElementType != null
}
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.asJava.builder.LightClassData
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
@@ -32,10 +33,12 @@ import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_OVERLOADS_FQ_NAME
@@ -288,9 +291,47 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
}
}
}
addMethodsFromDataClass(result)
result
}
private fun addMethodsFromDataClass(result: MutableList<KtLightMethod>) {
if (!classOrObject.hasModifier(DATA_KEYWORD)) return
val descriptor = classOrObject.resolve() as? ClassDescriptor ?: return
val bindingContext = classOrObject.analyze()
// Force resolving data class members set
descriptor.unsubstitutedMemberScope.getContributedDescriptors()
object : DataClassMethodGenerator(classOrObject, bindingContext) {
private fun addFunction(descriptor: FunctionDescriptor, declarationForOrigin: KtDeclaration? = null) {
result.add(createGeneratedMethodFromDescriptor(descriptor, declarationForOrigin))
}
override fun generateComponentFunction(function: FunctionDescriptor, parameter: ValueParameterDescriptor) {
addFunction(function, DescriptorToSourceUtils.descriptorToDeclaration(parameter) as? KtDeclaration)
}
override fun generateCopyFunction(function: FunctionDescriptor, constructorParameters: List<KtParameter>) {
addFunction(function)
}
override fun generateToStringMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
addFunction(function)
}
override fun generateHashCodeMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
addFunction(function)
}
override fun generateEqualsMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
addFunction(function)
}
}.generate()
}
private fun createConstructors(): List<KtLightMethod> {
val result = arrayListOf<KtLightMethod>()
val constructors = classOrObject.allConstructors
@@ -601,6 +642,7 @@ interface UltraLightSupport {
val moduleName: String
fun findAnnotation(owner: KtAnnotated, fqName: FqName): Pair<KtAnnotationEntry, AnnotationDescriptor>?
fun isTooComplexForUltraLightGeneration(element: KtClassOrObject): Boolean
val deprecationResolver: DeprecationResolver
}
interface KtUltraLightElementWithNullabilityAnnotation<out T : KtDeclaration, out D : PsiModifierListOwner> : KtLightDeclaration<T, D>,
@@ -6,48 +6,102 @@
package org.jetbrains.kotlin.asJava.classes
import com.intellij.psi.*
import com.intellij.psi.impl.cache.ModifierFlags
import com.intellij.psi.impl.cache.TypeInfo
import com.intellij.psi.impl.compiled.ClsTypeElementImpl
import com.intellij.psi.impl.compiled.SignatureParsing
import com.intellij.psi.impl.compiled.StubBuildingVisitor
import com.intellij.psi.impl.light.LightReferenceListBuilder
import com.intellij.psi.impl.light.LightTypeParameterBuilder
import com.intellij.psi.impl.light.*
import com.intellij.util.BitUtil.isSet
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
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.descriptors.*
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
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 org.jetbrains.org.objectweb.asm.Opcodes
import java.text.StringCharacterIterator
internal fun buildTypeParameterList(
declaration: CallableMemberDescriptor,
owner: PsiTypeParameterListOwner,
support: UltraLightSupport
): PsiTypeParameterList = buildTypeParameterList(
declaration, owner, support,
object : TypeParametersSupport<CallableMemberDescriptor, TypeParameterDescriptor> {
override fun parameters(declaration: CallableMemberDescriptor) = declaration.typeParameters
override fun name(typeParameter: TypeParameterDescriptor) = typeParameter.name.asString()
override fun hasNonTrivialBounds(
declaration: CallableMemberDescriptor,
typeParameter: TypeParameterDescriptor
) = typeParameter.upperBounds.any { !KotlinBuiltIns.isDefaultBound(it) }
override fun asDescriptor(typeParameter: TypeParameterDescriptor) = typeParameter
}
)
internal fun buildTypeParameterList(
declaration: KtTypeParameterListOwner,
owner: PsiTypeParameterListOwner,
support: UltraLightSupport
): PsiTypeParameterList = buildTypeParameterList(
declaration, owner, support,
object : TypeParametersSupport<KtTypeParameterListOwner, KtTypeParameter> {
override fun parameters(declaration: KtTypeParameterListOwner) = declaration.typeParameters
override fun name(typeParameter: KtTypeParameter) = typeParameter.name
override fun hasNonTrivialBounds(
declaration: KtTypeParameterListOwner,
typeParameter: KtTypeParameter
) = typeParameter.extendsBound != null || declaration.typeConstraints.isNotEmpty()
override fun asDescriptor(typeParameter: KtTypeParameter) = typeParameter.resolve() as? TypeParameterDescriptor
}
)
interface TypeParametersSupport<D, T> {
fun parameters(declaration: D): List<T>
fun name(typeParameter: T): String?
fun hasNonTrivialBounds(declaration: D, typeParameter: T): Boolean
fun asDescriptor(typeParameter: T): TypeParameterDescriptor?
}
internal fun <D, T> buildTypeParameterList(
declaration: D,
owner: PsiTypeParameterListOwner,
support: UltraLightSupport,
typeParametersSupport: TypeParametersSupport<D, T>
): PsiTypeParameterList {
val tpList = KotlinLightTypeParameterListBuilder(owner)
for ((i, ktParam) in declaration.typeParameters.withIndex()) {
tpList.addParameter(object : LightTypeParameterBuilder(ktParam.name.orEmpty(), owner, i) {
for ((i, param) in typeParametersSupport.parameters(declaration).withIndex()) {
tpList.addParameter(object : LightTypeParameterBuilder(typeParametersSupport.name(param).orEmpty(), owner, i) {
private val superList: LightReferenceListBuilder by lazyPub {
val boundList =
KotlinLightReferenceListBuilder(manager, PsiReferenceList.Role.EXTENDS_BOUNDS_LIST)
if (ktParam.extendsBound != null || declaration.typeConstraints.isNotEmpty()) {
val boundTypes = (ktParam.resolve() as? TypeParameterDescriptor)?.upperBounds.orEmpty()
if (typeParametersSupport.hasNonTrivialBounds(declaration, param)) {
val boundTypes = typeParametersSupport.asDescriptor(param)?.upperBounds.orEmpty()
.mapNotNull { it.asPsiType(support, TypeMappingMode.DEFAULT, this) as? PsiClassType }
val hasDefaultBound = boundTypes.size == 1 && boundTypes[0].equalsToText(CommonClassNames.JAVA_LANG_OBJECT)
if (!hasDefaultBound) {
@@ -76,6 +130,7 @@ internal fun KtDeclaration.getKotlinType(): KotlinType? {
}
internal fun KtDeclaration.resolve() = LightClassGenerationSupport.getInstance(project).resolveToDescriptor(this)
internal fun KtDeclaration.analyze() = LightClassGenerationSupport.getInstance(project).analyze(this)
// copy-pasted from kotlinInternalUastUtils.kt and post-processed
internal fun KotlinType.asPsiType(
@@ -145,3 +200,94 @@ fun KotlinType.cleanFromAnonymousTypes(): KotlinType? {
return replace(newArguments = newArguments)
}
fun KtUltraLightClass.createGeneratedMethodFromDescriptor(
descriptor: FunctionDescriptor,
declarationForOrigin: KtDeclaration? = null
): KtLightMethod {
val lightMethod = lightMethod(descriptor)
val kotlinOrigin =
declarationForOrigin
?: DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtDeclaration
?: kotlinOrigin
val wrapper = KtUltraLightMethodForDescriptor(descriptor, lightMethod, kotlinOrigin, support, this)
descriptor.extensionReceiverParameter?.let { receiver ->
lightMethod.addParameter(KtUltraLightParameterForDescriptor(receiver, kotlinOrigin, support, wrapper))
}
for (valueParameter in descriptor.valueParameters) {
lightMethod.addParameter(KtUltraLightParameterForDescriptor(valueParameter, kotlinOrigin, support, wrapper))
}
lightMethod.setMethodReturnType {
support.mapType(wrapper) { typeMapper, signatureWriter ->
typeMapper.mapReturnType(descriptor, signatureWriter)
}
}
return wrapper
}
private fun KtUltraLightClass.lightMethod(
descriptor: FunctionDescriptor
): LightMethodBuilder {
val name = descriptor.name.asString()
val accessFlags: Int by lazyPub {
val asmFlags = AsmUtil.getMethodAsmFlags(descriptor, OwnerKind.IMPLEMENTATION, support.deprecationResolver)
packMethodFlags(asmFlags, JvmCodegenUtil.isJvmInterface(kotlinOrigin.resolve() as? ClassDescriptor))
}
return LightMethodBuilder(
manager, language, name,
LightParameterListBuilder(manager, language),
object : LightModifierList(manager, language) {
override fun hasModifierProperty(name: String) = ModifierFlags.hasModifierProperty(name, accessFlags)
}
)
}
private fun packCommonFlags(access: Int): Int {
var flags = when {
isSet(access, Opcodes.ACC_PRIVATE) -> ModifierFlags.PRIVATE_MASK
isSet(access, Opcodes.ACC_PROTECTED) -> ModifierFlags.PROTECTED_MASK
isSet(access, Opcodes.ACC_PUBLIC) -> ModifierFlags.PUBLIC_MASK
else -> ModifierFlags.PACKAGE_LOCAL_MASK
}
if (isSet(access, Opcodes.ACC_STATIC)) {
flags = flags or ModifierFlags.STATIC_MASK
}
if (isSet(access, Opcodes.ACC_FINAL)) {
flags = flags or ModifierFlags.FINAL_MASK
}
return flags
}
private fun packMethodFlags(access: Int, isInterface: Boolean): Int {
var flags = packCommonFlags(access)
if (isSet(access, Opcodes.ACC_SYNCHRONIZED)) {
flags = flags or ModifierFlags.SYNCHRONIZED_MASK
}
if (isSet(access, Opcodes.ACC_NATIVE)) {
flags = flags or ModifierFlags.NATIVE_MASK
}
if (isSet(access, Opcodes.ACC_STRICT)) {
flags = flags or ModifierFlags.STRICTFP_MASK
}
if (isSet(access, Opcodes.ACC_ABSTRACT)) {
flags = flags or ModifierFlags.ABSTRACT_MASK
} else if (isInterface && !isSet(access, Opcodes.ACC_STATIC)) {
flags = flags or ModifierFlags.DEFAULT_MASK
}
return flags
}
@@ -1,7 +1,5 @@
/** should load cls */
data class User(val name: String = "", val age: Int = 0)
/** should load cls */
data class Person(val name: String) {
var age: Int = 0
}
@@ -50,6 +50,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -103,6 +104,10 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
}
return null
}
override val deprecationResolver: DeprecationResolver by lazyPub {
element.getResolutionFacade().getFrontendService(DeprecationResolver::class.java)
}
})
}
@@ -110,7 +115,6 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
if (declaration.hasExpectModifier() ||
declaration.hasModifier(KtTokens.ANNOTATION_KEYWORD) ||
declaration.hasModifier(KtTokens.INLINE_KEYWORD) && declaration is KtClassOrObject ||
declaration.hasModifier(KtTokens.DATA_KEYWORD) ||
declaration.hasModifier(KtTokens.SUSPEND_KEYWORD)
) {
return declaration