J2K backend-common classes: convert
Also merge CodegenUtilKt into CodegenUtil
This commit is contained in:
@@ -14,183 +14,200 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common;
|
||||
package org.jetbrains.kotlin.backend.common
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.backend.common.bridges.findTraitImplementation
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.isDynamic
|
||||
import org.jetbrains.kotlin.utils.keysToMapExceptNulls
|
||||
|
||||
import java.util.*;
|
||||
object CodegenUtil {
|
||||
// class Foo : Bar by baz
|
||||
// descriptor = Foo
|
||||
// toInterface = Bar
|
||||
// delegateExpressionType = typeof(baz)
|
||||
// return Map<member of Foo, corresponding member of typeOf(baz)>
|
||||
@JvmStatic
|
||||
fun getDelegates(
|
||||
descriptor: ClassDescriptor,
|
||||
toInterface: ClassDescriptor,
|
||||
delegateExpressionType: KotlinType? = null
|
||||
): Map<CallableMemberDescriptor, CallableDescriptor> {
|
||||
if (delegateExpressionType?.isDynamic() ?: false) return emptyMap()
|
||||
|
||||
public class CodegenUtil {
|
||||
return descriptor.defaultType.memberScope.getContributedDescriptors().asSequence()
|
||||
.filterIsInstance<CallableMemberDescriptor>()
|
||||
.filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }
|
||||
.asIterable()
|
||||
.sortedWith(MemberComparator.INSTANCE)
|
||||
.keysToMapExceptNulls { delegatingMember ->
|
||||
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
|
||||
.mapNotNull { overriddenDescriptor ->
|
||||
if (overriddenDescriptor.containingDeclaration == toInterface) {
|
||||
val scope = (delegateExpressionType ?: toInterface.defaultType).memberScope
|
||||
val name = overriddenDescriptor.name
|
||||
|
||||
private CodegenUtil() {
|
||||
}
|
||||
// this is the actual member of delegateExpressionType that we are delegating to
|
||||
(scope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND) +
|
||||
scope.getContributedVariables(name, NoLookupLocation.FROM_BACKEND))
|
||||
.firstOrNull {
|
||||
(listOf(it) + DescriptorUtils.getAllOverriddenDescriptors(it))
|
||||
.map(CallableMemberDescriptor::getOriginal)
|
||||
.contains(overriddenDescriptor.original)
|
||||
}
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FunctionDescriptor getDeclaredFunctionByRawSignature(
|
||||
@NotNull ClassDescriptor owner,
|
||||
@NotNull Name name,
|
||||
@NotNull ClassifierDescriptor returnedClassifier,
|
||||
@NotNull ClassifierDescriptor... valueParameterClassifiers
|
||||
) {
|
||||
Collection<SimpleFunctionDescriptor> functions = owner.getDefaultType().getMemberScope().getContributedFunctions(name, NoLookupLocation.FROM_BACKEND);
|
||||
for (FunctionDescriptor function : functions) {
|
||||
if (!CallResolverUtilKt.isOrOverridesSynthesized(function)
|
||||
&& function.getTypeParameters().isEmpty()
|
||||
&& valueParameterClassesMatch(function.getValueParameters(), Arrays.asList(valueParameterClassifiers))
|
||||
&& rawTypeMatches(function.getReturnType(), returnedClassifier)) {
|
||||
return function;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
assert(actualDelegates.size <= 1) { "Many delegates found for $delegatingMember: $actualDelegates" }
|
||||
|
||||
@Nullable
|
||||
public static PropertyDescriptor getDelegatePropertyIfAny(KtExpression expression, ClassDescriptor classDescriptor, BindingContext bindingContext) {
|
||||
PropertyDescriptor propertyDescriptor = null;
|
||||
if (expression instanceof KtSimpleNameExpression) {
|
||||
ResolvedCall<?> call = CallUtilKt.getResolvedCall(expression, bindingContext);
|
||||
if (call != null) {
|
||||
CallableDescriptor callResultingDescriptor = call.getResultingDescriptor();
|
||||
if (callResultingDescriptor instanceof ValueParameterDescriptor) {
|
||||
ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) callResultingDescriptor;
|
||||
// constructor parameter
|
||||
if (valueParameterDescriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
|
||||
// constructor of my class
|
||||
if (valueParameterDescriptor.getContainingDeclaration().getContainingDeclaration() == classDescriptor) {
|
||||
propertyDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameterDescriptor);
|
||||
}
|
||||
}
|
||||
actualDelegates.firstOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
// todo: when and if frontend will allow properties defined not as constructor parameters to be used in delegation specifier
|
||||
@JvmStatic
|
||||
fun getDeclaredFunctionByRawSignature(
|
||||
owner: ClassDescriptor,
|
||||
name: Name,
|
||||
returnedClassifier: ClassifierDescriptor,
|
||||
vararg valueParameterClassifiers: ClassifierDescriptor
|
||||
): FunctionDescriptor? {
|
||||
return owner.defaultType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).firstOrNull { function ->
|
||||
!isOrOverridesSynthesized(function) &&
|
||||
function.typeParameters.isEmpty() &&
|
||||
valueParameterClassesMatch(function.valueParameters, valueParameterClassifiers.toList()) &&
|
||||
rawTypeMatches(function.returnType!!, returnedClassifier)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDelegatePropertyIfAny(
|
||||
expression: KtExpression, classDescriptor: ClassDescriptor, bindingContext: BindingContext
|
||||
): PropertyDescriptor? {
|
||||
val call = (expression as? KtSimpleNameExpression)?.getResolvedCall(bindingContext) ?: return null
|
||||
val callResultingDescriptor = call.resultingDescriptor as? ValueParameterDescriptor ?: return null
|
||||
// constructor parameter
|
||||
if (callResultingDescriptor.containingDeclaration is ConstructorDescriptor) {
|
||||
// constructor of my class
|
||||
if (callResultingDescriptor.containingDeclaration.containingDeclaration === classDescriptor) {
|
||||
return bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, callResultingDescriptor)
|
||||
}
|
||||
}
|
||||
return propertyDescriptor;
|
||||
return null
|
||||
}
|
||||
|
||||
public static boolean isFinalPropertyWithBackingField(PropertyDescriptor propertyDescriptor, BindingContext bindingContext) {
|
||||
@JvmStatic
|
||||
fun isFinalPropertyWithBackingField(propertyDescriptor: PropertyDescriptor?, bindingContext: BindingContext): Boolean {
|
||||
return propertyDescriptor != null &&
|
||||
!propertyDescriptor.isVar() &&
|
||||
Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
|
||||
!propertyDescriptor.isVar &&
|
||||
(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false)
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Map<FunctionDescriptor, FunctionDescriptor> getNonPrivateTraitMethods(ClassDescriptor descriptor) {
|
||||
Map<FunctionDescriptor, FunctionDescriptor> result = new LinkedHashMap<FunctionDescriptor, FunctionDescriptor>();
|
||||
for (DeclarationDescriptor declaration : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
|
||||
if (!(declaration instanceof CallableMemberDescriptor)) continue;
|
||||
@JvmStatic
|
||||
fun getNonPrivateTraitMethods(descriptor: ClassDescriptor): Map<FunctionDescriptor, FunctionDescriptor> {
|
||||
val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>()
|
||||
for (declaration in DescriptorUtils.getAllDescriptors(descriptor.defaultType.memberScope)) {
|
||||
if (declaration !is CallableMemberDescriptor) continue
|
||||
|
||||
CallableMemberDescriptor inheritedMember = (CallableMemberDescriptor) declaration;
|
||||
CallableMemberDescriptor traitMember = ImplKt.findTraitImplementation(inheritedMember);
|
||||
if (traitMember == null || Visibilities.isPrivate(traitMember.getVisibility())) continue;
|
||||
val traitMember = findTraitImplementation(declaration)
|
||||
if (traitMember == null || Visibilities.isPrivate(traitMember.visibility)) continue
|
||||
|
||||
assert traitMember.getModality() != Modality.ABSTRACT : "Cannot delegate to abstract trait method: " + inheritedMember;
|
||||
assert(traitMember.modality !== Modality.ABSTRACT) { "Cannot delegate to abstract trait method: $declaration" }
|
||||
|
||||
// inheritedMember can be abstract here. In order for FunctionCodegen to generate the method body, we're creating a copy here
|
||||
// with traitMember's modality
|
||||
result.putAll(copyFunctions(inheritedMember, traitMember, inheritedMember.getContainingDeclaration(), traitMember.getModality(), Visibilities.PUBLIC,
|
||||
CallableMemberDescriptor.Kind.DECLARATION, true));
|
||||
result.putAll(copyFunctions(declaration, traitMember, declaration.containingDeclaration, traitMember.modality,
|
||||
Visibilities.PUBLIC, CallableMemberDescriptor.Kind.DECLARATION, true))
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Map<FunctionDescriptor, FunctionDescriptor> copyFunctions(
|
||||
@NotNull CallableMemberDescriptor inheritedMember,
|
||||
@NotNull CallableMemberDescriptor traitMember,
|
||||
DeclarationDescriptor newOwner,
|
||||
Modality modality,
|
||||
Visibility visibility,
|
||||
CallableMemberDescriptor.Kind kind,
|
||||
boolean copyOverrides
|
||||
) {
|
||||
CallableMemberDescriptor copy = inheritedMember.copy(newOwner, modality, visibility, kind, copyOverrides);
|
||||
Map<FunctionDescriptor, FunctionDescriptor> result = new LinkedHashMap<FunctionDescriptor, FunctionDescriptor>(0);
|
||||
if (traitMember instanceof SimpleFunctionDescriptor) {
|
||||
result.put((FunctionDescriptor) traitMember, (FunctionDescriptor) copy);
|
||||
fun copyFunctions(
|
||||
inheritedMember: CallableMemberDescriptor,
|
||||
traitMember: CallableMemberDescriptor,
|
||||
newOwner: DeclarationDescriptor,
|
||||
modality: Modality,
|
||||
visibility: Visibility,
|
||||
kind: CallableMemberDescriptor.Kind,
|
||||
copyOverrides: Boolean
|
||||
): Map<FunctionDescriptor, FunctionDescriptor> {
|
||||
val copy = inheritedMember.copy(newOwner, modality, visibility, kind, copyOverrides)
|
||||
val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>()
|
||||
if (traitMember is SimpleFunctionDescriptor) {
|
||||
result[traitMember] = copy as FunctionDescriptor
|
||||
}
|
||||
else if (traitMember instanceof PropertyDescriptor) {
|
||||
for (PropertyAccessorDescriptor traitAccessor : ((PropertyDescriptor) traitMember).getAccessors()) {
|
||||
for (PropertyAccessorDescriptor inheritedAccessor : ((PropertyDescriptor) copy).getAccessors()) {
|
||||
if (inheritedAccessor.getClass() == traitAccessor.getClass()) { // same accessor kind
|
||||
result.put(traitAccessor, inheritedAccessor);
|
||||
else if (traitMember is PropertyDescriptor) {
|
||||
for (traitAccessor in traitMember.accessors) {
|
||||
for (inheritedAccessor in (copy as PropertyDescriptor).accessors) {
|
||||
if (inheritedAccessor.javaClass == traitAccessor.javaClass) { // same accessor kind
|
||||
result.put(traitAccessor, inheritedAccessor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ClassDescriptor getSuperClassBySuperTypeListEntry(@NotNull KtSuperTypeListEntry specifier, @NotNull BindingContext bindingContext) {
|
||||
KotlinType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
|
||||
assert superType != null : "superType should not be null: " + specifier.getText();
|
||||
@JvmStatic
|
||||
fun getSuperClassBySuperTypeListEntry(specifier: KtSuperTypeListEntry, bindingContext: BindingContext): ClassDescriptor {
|
||||
val superType = bindingContext.get(BindingContext.TYPE, specifier.typeReference!!)
|
||||
?: error("superType should not be null: ${specifier.text}")
|
||||
|
||||
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
|
||||
assert superClassDescriptor != null : "superClassDescriptor should not be null: " + specifier.getText();
|
||||
return superClassDescriptor;
|
||||
return superType.constructor.declarationDescriptor as? ClassDescriptor
|
||||
?: error("ClassDescriptor of superType should not be null: ${specifier.text}")
|
||||
}
|
||||
|
||||
private static boolean valueParameterClassesMatch(
|
||||
@NotNull List<ValueParameterDescriptor> parameters,
|
||||
@NotNull List<ClassifierDescriptor> classifiers
|
||||
) {
|
||||
if (parameters.size() != classifiers.size()) return false;
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
ValueParameterDescriptor parameterDescriptor = parameters.get(i);
|
||||
ClassifierDescriptor classDescriptor = classifiers.get(i);
|
||||
if (!rawTypeMatches(parameterDescriptor.getType(), classDescriptor)) {
|
||||
return false;
|
||||
private fun valueParameterClassesMatch(
|
||||
parameters: List<ValueParameterDescriptor>,
|
||||
classifiers: List<ClassifierDescriptor>
|
||||
): Boolean {
|
||||
if (parameters.size != classifiers.size) return false
|
||||
for ((parameterDescriptor, classDescriptor) in parameters.zip(classifiers)) {
|
||||
if (!rawTypeMatches(parameterDescriptor.type, classDescriptor)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
private static boolean rawTypeMatches(KotlinType type, ClassifierDescriptor classifier) {
|
||||
return type.getConstructor().equals(classifier.getTypeConstructor());
|
||||
private fun rawTypeMatches(type: KotlinType, classifier: ClassifierDescriptor): Boolean =
|
||||
type.constructor == classifier.typeConstructor
|
||||
|
||||
@JvmStatic
|
||||
fun isEnumValueOfMethod(functionDescriptor: FunctionDescriptor): Boolean {
|
||||
val methodTypeParameters = functionDescriptor.valueParameters
|
||||
val nullableString = TypeUtils.makeNullable(functionDescriptor.builtIns.stringType)
|
||||
return DescriptorUtils.ENUM_VALUE_OF == functionDescriptor.name
|
||||
&& methodTypeParameters.size == 1
|
||||
&& KotlinTypeChecker.DEFAULT.isSubtypeOf(methodTypeParameters[0].type, nullableString)
|
||||
}
|
||||
|
||||
public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
|
||||
KotlinType nullableString = TypeUtils.makeNullable(DescriptorUtilsKt.getBuiltIns(functionDescriptor).getStringType());
|
||||
return DescriptorUtils.ENUM_VALUE_OF.equals(functionDescriptor.getName())
|
||||
&& methodTypeParameters.size() == 1
|
||||
&& KotlinTypeChecker.DEFAULT.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Integer getLineNumberForElement(@NotNull PsiElement statement, boolean markEndOffset) {
|
||||
PsiFile file = statement.getContainingFile();
|
||||
if (file instanceof KtFile) {
|
||||
if (KtPsiFactoryKt.getDoNotAnalyze((KtFile) file) != null) {
|
||||
return null;
|
||||
}
|
||||
@JvmStatic
|
||||
fun getLineNumberForElement(statement: PsiElement, markEndOffset: Boolean): Int? {
|
||||
val file = statement.containingFile
|
||||
if (file is KtFile && file.doNotAnalyze != null) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (statement instanceof KtConstructorDelegationReferenceExpression && statement.getTextLength() == 0) {
|
||||
if (statement is KtConstructorDelegationReferenceExpression && statement.textLength == 0) {
|
||||
// PsiElement for constructor delegation reference is always generated, so we shouldn't mark it's line number if it's empty
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
Document document = file.getViewProvider().getDocument();
|
||||
return document != null ? document.getLineNumber(markEndOffset ? statement.getTextRange().getEndOffset() : statement.getTextOffset()) + 1 : null;
|
||||
val document = file.viewProvider.document
|
||||
return document?.getLineNumber(if (markEndOffset) statement.textRange.endOffset else statement.textOffset)?.plus(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isDynamic
|
||||
import org.jetbrains.kotlin.utils.keysToMapExceptNulls
|
||||
import java.util.Comparator
|
||||
|
||||
object CodegenUtilKt {
|
||||
|
||||
// class Foo : Bar by baz
|
||||
// descriptor = Foo
|
||||
// toInterface = Bar
|
||||
// delegateExpressionType = typeof(baz)
|
||||
// return Map<member of Foo, corresponding member of typeOf(baz)>
|
||||
@JvmStatic fun getDelegates(
|
||||
descriptor: ClassDescriptor,
|
||||
toInterface: ClassDescriptor,
|
||||
delegateExpressionType: KotlinType? = null
|
||||
): Map<CallableMemberDescriptor, CallableDescriptor> {
|
||||
if (delegateExpressionType?.isDynamic() ?: false) return mapOf()
|
||||
|
||||
return descriptor.defaultType.memberScope.getContributedDescriptors().asSequence()
|
||||
.filterIsInstance<CallableMemberDescriptor>()
|
||||
.filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }
|
||||
.asIterable()
|
||||
.sortedWith(MemberComparator.INSTANCE)
|
||||
.keysToMapExceptNulls {
|
||||
delegatingMember ->
|
||||
|
||||
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
|
||||
.mapNotNull {
|
||||
overriddenDescriptor ->
|
||||
if (overriddenDescriptor.containingDeclaration == toInterface) {
|
||||
val scope = (delegateExpressionType ?: toInterface.defaultType).memberScope
|
||||
val name = overriddenDescriptor.name
|
||||
|
||||
// this is the actual member of delegateExpressionType that we are delegating to
|
||||
(scope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND) + scope.getContributedVariables(name, NoLookupLocation.FROM_BACKEND))
|
||||
.firstOrNull {
|
||||
(listOf(it) + DescriptorUtils.getAllOverriddenDescriptors(it))
|
||||
.map { it.original }
|
||||
.contains(overriddenDescriptor.original)
|
||||
}
|
||||
}
|
||||
else null
|
||||
}
|
||||
assert(actualDelegates.size <= 1) { "Many delegates found for $delegatingMember: $actualDelegates" }
|
||||
|
||||
actualDelegates.firstOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
-107
@@ -14,158 +14,115 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common;
|
||||
package org.jetbrains.kotlin.backend.common
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.KtClass;
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject;
|
||||
import org.jetbrains.kotlin.psi.KtParameter;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||
import org.jetbrains.kotlin.resolve.OverrideResolver;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.resolve.OverrideResolver
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
|
||||
/**
|
||||
* A platform-independent logic for generating data class synthetic methods.
|
||||
* TODO: data class with zero components gets no toString/equals/hashCode methods. This is inconsistent and should be
|
||||
* changed here with the platform backends adopted.
|
||||
* changed here with the platform backends adopted.
|
||||
*/
|
||||
public abstract class DataClassMethodGenerator {
|
||||
private final KtClassOrObject declaration;
|
||||
private final BindingContext bindingContext;
|
||||
private final ClassDescriptor classDescriptor;
|
||||
private final KotlinBuiltIns builtIns;
|
||||
abstract class DataClassMethodGenerator(private val declaration: KtClassOrObject, private val bindingContext: BindingContext) {
|
||||
protected val classDescriptor: ClassDescriptor = BindingContextUtils.getNotNull(bindingContext, BindingContext.CLASS, declaration)
|
||||
|
||||
public DataClassMethodGenerator(KtClassOrObject declaration, BindingContext bindingContext) {
|
||||
this.declaration = declaration;
|
||||
this.bindingContext = bindingContext;
|
||||
this.classDescriptor = BindingContextUtils.getNotNull(bindingContext, BindingContext.CLASS, declaration);
|
||||
this.builtIns = DescriptorUtilsKt.getBuiltIns(classDescriptor);
|
||||
}
|
||||
private val builtIns = classDescriptor.builtIns
|
||||
|
||||
public void generate() {
|
||||
generateComponentFunctionsForDataClasses();
|
||||
fun generate() {
|
||||
generateComponentFunctionsForDataClasses()
|
||||
|
||||
generateCopyFunctionForDataClasses(getPrimaryConstructorParameters());
|
||||
generateCopyFunctionForDataClasses(primaryConstructorParameters)
|
||||
|
||||
List<PropertyDescriptor> properties = getDataProperties();
|
||||
if (!properties.isEmpty()) {
|
||||
generateDataClassToStringIfNeeded(properties);
|
||||
generateDataClassHashCodeIfNeeded(properties);
|
||||
generateDataClassEqualsIfNeeded(properties);
|
||||
val properties = dataProperties
|
||||
if (properties.isNotEmpty()) {
|
||||
generateDataClassToStringIfNeeded(properties)
|
||||
generateDataClassHashCodeIfNeeded(properties)
|
||||
generateDataClassEqualsIfNeeded(properties)
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull ValueParameterDescriptor parameter);
|
||||
protected abstract fun generateComponentFunction(function: FunctionDescriptor, parameter: ValueParameterDescriptor)
|
||||
|
||||
protected abstract void generateCopyFunction(@NotNull FunctionDescriptor function, @NotNull List<KtParameter> constructorParameters);
|
||||
protected abstract fun generateCopyFunction(function: FunctionDescriptor, constructorParameters: List<KtParameter>)
|
||||
|
||||
protected abstract void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List<PropertyDescriptor> properties);
|
||||
protected abstract fun generateToStringMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>)
|
||||
|
||||
protected abstract void generateHashCodeMethod(@NotNull FunctionDescriptor function, @NotNull List<PropertyDescriptor> properties);
|
||||
protected abstract fun generateHashCodeMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>)
|
||||
|
||||
protected abstract void generateEqualsMethod(@NotNull FunctionDescriptor function, @NotNull List<PropertyDescriptor> properties);
|
||||
protected abstract fun generateEqualsMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>)
|
||||
|
||||
@NotNull
|
||||
protected ClassDescriptor getClassDescriptor() {
|
||||
return classDescriptor;
|
||||
}
|
||||
|
||||
private void generateComponentFunctionsForDataClasses() {
|
||||
ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
|
||||
private fun generateComponentFunctionsForDataClasses() {
|
||||
// primary constructor should exist for data classes
|
||||
// but when generating light-classes still need to check we have one
|
||||
if (constructor == null) return;
|
||||
val constructor = classDescriptor.unsubstitutedPrimaryConstructor ?: return
|
||||
|
||||
for (ValueParameterDescriptor parameter : constructor.getValueParameters()) {
|
||||
FunctionDescriptor function = bindingContext.get(BindingContext.DATA_CLASS_COMPONENT_FUNCTION, parameter);
|
||||
for (parameter in constructor.valueParameters) {
|
||||
val function = bindingContext.get(BindingContext.DATA_CLASS_COMPONENT_FUNCTION, parameter)
|
||||
if (function != null) {
|
||||
generateComponentFunction(function, parameter);
|
||||
generateComponentFunction(function, parameter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateCopyFunctionForDataClasses(List<KtParameter> constructorParameters) {
|
||||
FunctionDescriptor copyFunction = bindingContext.get(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor);
|
||||
if (copyFunction != null) {
|
||||
generateCopyFunction(copyFunction, constructorParameters);
|
||||
}
|
||||
private fun generateCopyFunctionForDataClasses(constructorParameters: List<KtParameter>) {
|
||||
val copyFunction = bindingContext.get(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor) ?: return
|
||||
generateCopyFunction(copyFunction, constructorParameters)
|
||||
}
|
||||
|
||||
private void generateDataClassToStringIfNeeded(@NotNull List<PropertyDescriptor> properties) {
|
||||
FunctionDescriptor function = getDeclaredMember("toString", builtIns.getString());
|
||||
private fun generateDataClassToStringIfNeeded(properties: List<PropertyDescriptor>) {
|
||||
val function = getDeclaredMember("toString", builtIns.string)
|
||||
if (function != null && isTrivial(function)) {
|
||||
generateToStringMethod(function, properties);
|
||||
generateToStringMethod(function, properties)
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDataClassHashCodeIfNeeded(@NotNull List<PropertyDescriptor> properties) {
|
||||
FunctionDescriptor function = getDeclaredMember("hashCode", builtIns.getInt());
|
||||
private fun generateDataClassHashCodeIfNeeded(properties: List<PropertyDescriptor>) {
|
||||
val function = getDeclaredMember("hashCode", builtIns.int)
|
||||
if (function != null && isTrivial(function)) {
|
||||
generateHashCodeMethod(function, properties);
|
||||
generateHashCodeMethod(function, properties)
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDataClassEqualsIfNeeded(@NotNull List<PropertyDescriptor> properties) {
|
||||
FunctionDescriptor function = getDeclaredMember("equals", builtIns.getBoolean(), builtIns.getAny());
|
||||
private fun generateDataClassEqualsIfNeeded(properties: List<PropertyDescriptor>) {
|
||||
val function = getDeclaredMember("equals", builtIns.boolean, builtIns.any)
|
||||
if (function != null && isTrivial(function)) {
|
||||
generateEqualsMethod(function, properties);
|
||||
generateEqualsMethod(function, properties)
|
||||
}
|
||||
}
|
||||
|
||||
private List<PropertyDescriptor> getDataProperties() {
|
||||
List<PropertyDescriptor> result = Lists.newArrayList();
|
||||
for (KtParameter parameter : getPrimaryConstructorParameters()) {
|
||||
if (parameter.hasValOrVar()) {
|
||||
result.add(bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private val dataProperties: List<PropertyDescriptor>
|
||||
get() = primaryConstructorParameters
|
||||
.filter { it.hasValOrVar() }
|
||||
.map { bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it)!! }
|
||||
|
||||
@NotNull
|
||||
private List<KtParameter> getPrimaryConstructorParameters() {
|
||||
if (declaration instanceof KtClass) {
|
||||
return declaration.getPrimaryConstructorParameters();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
private val primaryConstructorParameters: List<KtParameter>
|
||||
get() = (declaration as? KtClass)?.getPrimaryConstructorParameters().orEmpty()
|
||||
|
||||
@Nullable
|
||||
private FunctionDescriptor getDeclaredMember(
|
||||
@NotNull String name,
|
||||
@NotNull ClassDescriptor returnedClassifier,
|
||||
@NotNull ClassDescriptor... valueParameterClassifiers
|
||||
) {
|
||||
return CodegenUtil.getDeclaredFunctionByRawSignature(
|
||||
classDescriptor, Name.identifier(name), returnedClassifier, valueParameterClassifiers
|
||||
);
|
||||
}
|
||||
private fun getDeclaredMember(
|
||||
name: String,
|
||||
returnedClassifier: ClassDescriptor,
|
||||
vararg valueParameterClassifiers: ClassDescriptor
|
||||
): FunctionDescriptor? = CodegenUtil.getDeclaredFunctionByRawSignature(
|
||||
classDescriptor, Name.identifier(name), returnedClassifier, *valueParameterClassifiers
|
||||
)
|
||||
|
||||
/**
|
||||
* @return true if the member is an inherited implementation of a method from Any
|
||||
*/
|
||||
private boolean isTrivial(@NotNull FunctionDescriptor function) {
|
||||
if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (CallableDescriptor overridden : OverrideResolver.getOverriddenDeclarations(function)) {
|
||||
if (overridden instanceof CallableMemberDescriptor
|
||||
&& ((CallableMemberDescriptor) overridden).getKind() == CallableMemberDescriptor.Kind.DECLARATION
|
||||
&& !overridden.getContainingDeclaration().equals(builtIns.getAny())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
private fun isTrivial(function: FunctionDescriptor): Boolean {
|
||||
return function.kind != CallableMemberDescriptor.Kind.DECLARATION &&
|
||||
OverrideResolver.getOverriddenDeclarations(function).none { overridden ->
|
||||
overridden is CallableMemberDescriptor &&
|
||||
overridden.kind == CallableMemberDescriptor.Kind.DECLARATION &&
|
||||
overridden.containingDeclaration != builtIns.any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import kotlin.jvm.functions.Function2;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtilKt;
|
||||
import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
|
||||
@@ -496,7 +495,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateEqualsMethod(@NotNull FunctionDescriptor function, @NotNull List<PropertyDescriptor> properties) {
|
||||
public void generateEqualsMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> properties) {
|
||||
MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function);
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null);
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
@@ -553,7 +552,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateHashCodeMethod(@NotNull FunctionDescriptor function, @NotNull List<PropertyDescriptor> properties) {
|
||||
public void generateHashCodeMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> properties) {
|
||||
MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function);
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "hashCode", "()I", null, null);
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
@@ -602,7 +601,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List<PropertyDescriptor> properties) {
|
||||
public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> properties) {
|
||||
MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function);
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
@@ -692,7 +691,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateCopyFunction(@NotNull final FunctionDescriptor function, @NotNull List<KtParameter> constructorParameters) {
|
||||
public void generateCopyFunction(
|
||||
@NotNull final FunctionDescriptor function,
|
||||
@NotNull List<? extends KtParameter> constructorParameters
|
||||
) {
|
||||
final Type thisDescriptorType = typeMapper.mapType(descriptor);
|
||||
|
||||
functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(myClass, function), function, new FunctionGenerationStrategy() {
|
||||
@@ -1640,8 +1642,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
fieldInfo.name, fieldInfo.type.getDescriptor(), /*TODO*/null, null);
|
||||
}
|
||||
|
||||
protected void generateDelegates(ClassDescriptor toTrait, KotlinType delegateExpressionType, DelegationFieldsInfo.Field field) {
|
||||
for (Map.Entry<CallableMemberDescriptor, CallableDescriptor> entry : CodegenUtilKt.getDelegates(descriptor, toTrait, delegateExpressionType).entrySet()) {
|
||||
private void generateDelegates(ClassDescriptor toTrait, KotlinType delegateExpressionType, DelegationFieldsInfo.Field field) {
|
||||
for (Map.Entry<CallableMemberDescriptor, CallableDescriptor> entry :
|
||||
CodegenUtil.getDelegates(descriptor, toTrait, delegateExpressionType).entrySet()) {
|
||||
CallableMemberDescriptor callableMemberDescriptor = entry.getKey();
|
||||
CallableDescriptor delegateTo = entry.getValue();
|
||||
if (callableMemberDescriptor instanceof PropertyDescriptor) {
|
||||
|
||||
@@ -82,12 +82,13 @@ class JvmStaticGenerator(
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic fun createStaticFunctionDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
|
||||
@JvmStatic
|
||||
fun createStaticFunctionDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
|
||||
val memberDescriptor = if (descriptor is PropertyAccessorDescriptor) descriptor.correspondingProperty else descriptor
|
||||
val copies = CodegenUtil.copyFunctions(
|
||||
memberDescriptor,
|
||||
memberDescriptor,
|
||||
descriptor.containingDeclaration.containingDeclaration,
|
||||
descriptor.containingDeclaration.containingDeclaration!!,
|
||||
descriptor.modality,
|
||||
descriptor.visibility,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
|
||||
+2
-3
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.translate.declaration
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtilKt
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
@@ -32,8 +31,8 @@ import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunc
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateFunctionAsEcma5PropertyDescriptor
|
||||
import org.jetbrains.kotlin.js.translate.utils.generateDelegateCall
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtSuperTypeListEntry
|
||||
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
|
||||
import org.jetbrains.kotlin.psi.KtSuperTypeListEntry
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
class DelegationTranslator(
|
||||
@@ -90,7 +89,7 @@ class DelegationTranslator(
|
||||
CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext())
|
||||
|
||||
private fun generateDelegates(toClass: ClassDescriptor, field: Field, properties: MutableList<JsPropertyInitializer>) {
|
||||
for ((descriptor, overriddenDescriptor) in CodegenUtilKt.getDelegates(classDescriptor, toClass)) {
|
||||
for ((descriptor, overriddenDescriptor) in CodegenUtil.getDelegates(classDescriptor, toClass)) {
|
||||
when (descriptor) {
|
||||
is PropertyDescriptor ->
|
||||
generateDelegateCallForPropertyMember(descriptor, field.name, properties)
|
||||
|
||||
+4
-4
@@ -61,7 +61,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateCopyFunction(@NotNull FunctionDescriptor function, @NotNull List<KtParameter> constructorParameters) {
|
||||
public void generateCopyFunction(@NotNull FunctionDescriptor function, @NotNull List<? extends KtParameter> constructorParameters) {
|
||||
JsFunction functionObj = generateJsMethod(function);
|
||||
|
||||
assert function.getValueParameters().size() == constructorParameters.size();
|
||||
@@ -110,7 +110,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List<PropertyDescriptor> classProperties) {
|
||||
public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> classProperties) {
|
||||
// TODO: relax this limitation, with the data generation logic fixed.
|
||||
assert !classProperties.isEmpty();
|
||||
JsFunction functionObj = generateJsMethod(function);
|
||||
@@ -136,7 +136,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateHashCodeMethod(@NotNull FunctionDescriptor function, @NotNull List<PropertyDescriptor> classProperties) {
|
||||
public void generateHashCodeMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> classProperties) {
|
||||
JsFunction functionObj = generateJsMethod(function);
|
||||
|
||||
JsProgram jsProgram = context.program();
|
||||
@@ -161,7 +161,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateEqualsMethod(@NotNull FunctionDescriptor function, @NotNull List<PropertyDescriptor> classProperties) {
|
||||
public void generateEqualsMethod(@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> classProperties) {
|
||||
assert !classProperties.isEmpty();
|
||||
JsFunction functionObj = generateJsMethod(function);
|
||||
JsFunctionScope funScope = functionObj.getScope();
|
||||
|
||||
Reference in New Issue
Block a user