J2K backend-common classes: convert

Also merge CodegenUtilKt into CodegenUtil
This commit is contained in:
Alexander Udalov
2016-04-13 14:53:47 +03:00
parent 27ed0dd25f
commit c1c2651988
7 changed files with 234 additions and 331 deletions
@@ -14,183 +14,200 @@
* limitations under the License. * 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.PsiElement; import org.jetbrains.kotlin.backend.common.bridges.findTraitImplementation
import com.intellij.psi.PsiFile; import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.backend.common.bridges.ImplKt; import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.MemberComparator
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt; import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.utils.keysToMapExceptNulls
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
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 assert(actualDelegates.size <= 1) { "Many delegates found for $delegatingMember: $actualDelegates" }
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;
}
@Nullable actualDelegates.firstOrNull()
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);
}
}
} }
}
// 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 && return propertyDescriptor != null &&
!propertyDescriptor.isVar() && !propertyDescriptor.isVar &&
Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)); (bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false)
} }
@NotNull @JvmStatic
public static Map<FunctionDescriptor, FunctionDescriptor> getNonPrivateTraitMethods(ClassDescriptor descriptor) { fun getNonPrivateTraitMethods(descriptor: ClassDescriptor): Map<FunctionDescriptor, FunctionDescriptor> {
Map<FunctionDescriptor, FunctionDescriptor> result = new LinkedHashMap<FunctionDescriptor, FunctionDescriptor>(); val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>()
for (DeclarationDescriptor declaration : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) { for (declaration in DescriptorUtils.getAllDescriptors(descriptor.defaultType.memberScope)) {
if (!(declaration instanceof CallableMemberDescriptor)) continue; if (declaration !is CallableMemberDescriptor) continue
CallableMemberDescriptor inheritedMember = (CallableMemberDescriptor) declaration; val traitMember = findTraitImplementation(declaration)
CallableMemberDescriptor traitMember = ImplKt.findTraitImplementation(inheritedMember); if (traitMember == null || Visibilities.isPrivate(traitMember.visibility)) continue
if (traitMember == null || Visibilities.isPrivate(traitMember.getVisibility())) 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 // inheritedMember can be abstract here. In order for FunctionCodegen to generate the method body, we're creating a copy here
// with traitMember's modality // with traitMember's modality
result.putAll(copyFunctions(inheritedMember, traitMember, inheritedMember.getContainingDeclaration(), traitMember.getModality(), Visibilities.PUBLIC, result.putAll(copyFunctions(declaration, traitMember, declaration.containingDeclaration, traitMember.modality,
CallableMemberDescriptor.Kind.DECLARATION, true)); Visibilities.PUBLIC, CallableMemberDescriptor.Kind.DECLARATION, true))
} }
return result; return result
} }
@NotNull fun copyFunctions(
public static Map<FunctionDescriptor, FunctionDescriptor> copyFunctions( inheritedMember: CallableMemberDescriptor,
@NotNull CallableMemberDescriptor inheritedMember, traitMember: CallableMemberDescriptor,
@NotNull CallableMemberDescriptor traitMember, newOwner: DeclarationDescriptor,
DeclarationDescriptor newOwner, modality: Modality,
Modality modality, visibility: Visibility,
Visibility visibility, kind: CallableMemberDescriptor.Kind,
CallableMemberDescriptor.Kind kind, copyOverrides: Boolean
boolean copyOverrides ): Map<FunctionDescriptor, FunctionDescriptor> {
) { val copy = inheritedMember.copy(newOwner, modality, visibility, kind, copyOverrides)
CallableMemberDescriptor copy = inheritedMember.copy(newOwner, modality, visibility, kind, copyOverrides); val result = linkedMapOf<FunctionDescriptor, FunctionDescriptor>()
Map<FunctionDescriptor, FunctionDescriptor> result = new LinkedHashMap<FunctionDescriptor, FunctionDescriptor>(0); if (traitMember is SimpleFunctionDescriptor) {
if (traitMember instanceof SimpleFunctionDescriptor) { result[traitMember] = copy as FunctionDescriptor
result.put((FunctionDescriptor) traitMember, (FunctionDescriptor) copy);
} }
else if (traitMember instanceof PropertyDescriptor) { else if (traitMember is PropertyDescriptor) {
for (PropertyAccessorDescriptor traitAccessor : ((PropertyDescriptor) traitMember).getAccessors()) { for (traitAccessor in traitMember.accessors) {
for (PropertyAccessorDescriptor inheritedAccessor : ((PropertyDescriptor) copy).getAccessors()) { for (inheritedAccessor in (copy as PropertyDescriptor).accessors) {
if (inheritedAccessor.getClass() == traitAccessor.getClass()) { // same accessor kind if (inheritedAccessor.javaClass == traitAccessor.javaClass) { // same accessor kind
result.put(traitAccessor, inheritedAccessor); result.put(traitAccessor, inheritedAccessor)
} }
} }
} }
} }
return result; return result
} }
@NotNull @JvmStatic
public static ClassDescriptor getSuperClassBySuperTypeListEntry(@NotNull KtSuperTypeListEntry specifier, @NotNull BindingContext bindingContext) { fun getSuperClassBySuperTypeListEntry(specifier: KtSuperTypeListEntry, bindingContext: BindingContext): ClassDescriptor {
KotlinType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); val superType = bindingContext.get(BindingContext.TYPE, specifier.typeReference!!)
assert superType != null : "superType should not be null: " + specifier.getText(); ?: error("superType should not be null: ${specifier.text}")
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); return superType.constructor.declarationDescriptor as? ClassDescriptor
assert superClassDescriptor != null : "superClassDescriptor should not be null: " + specifier.getText(); ?: error("ClassDescriptor of superType should not be null: ${specifier.text}")
return superClassDescriptor;
} }
private static boolean valueParameterClassesMatch( private fun valueParameterClassesMatch(
@NotNull List<ValueParameterDescriptor> parameters, parameters: List<ValueParameterDescriptor>,
@NotNull List<ClassifierDescriptor> classifiers classifiers: List<ClassifierDescriptor>
) { ): Boolean {
if (parameters.size() != classifiers.size()) return false; if (parameters.size != classifiers.size) return false
for (int i = 0; i < parameters.size(); i++) { for ((parameterDescriptor, classDescriptor) in parameters.zip(classifiers)) {
ValueParameterDescriptor parameterDescriptor = parameters.get(i); if (!rawTypeMatches(parameterDescriptor.type, classDescriptor)) {
ClassifierDescriptor classDescriptor = classifiers.get(i); return false
if (!rawTypeMatches(parameterDescriptor.getType(), classDescriptor)) {
return false;
} }
} }
return true; return true
} }
private static boolean rawTypeMatches(KotlinType type, ClassifierDescriptor classifier) { private fun rawTypeMatches(type: KotlinType, classifier: ClassifierDescriptor): Boolean =
return type.getConstructor().equals(classifier.getTypeConstructor()); 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) { @JvmStatic
List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters(); fun getLineNumberForElement(statement: PsiElement, markEndOffset: Boolean): Int? {
KotlinType nullableString = TypeUtils.makeNullable(DescriptorUtilsKt.getBuiltIns(functionDescriptor).getStringType()); val file = statement.containingFile
return DescriptorUtils.ENUM_VALUE_OF.equals(functionDescriptor.getName()) if (file is KtFile && file.doNotAnalyze != null) {
&& methodTypeParameters.size() == 1 return null
&& 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;
}
} }
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 // 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(); val document = file.viewProvider.document
return document != null ? document.getLineNumber(markEndOffset ? statement.getTextRange().getEndOffset() : statement.getTextOffset()) + 1 : null; 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()
}
}
}
@@ -14,158 +14,115 @@
* limitations under the License. * 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.kotlin.descriptors.*
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.name.Name
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.psi.KtClass; import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.resolve.OverrideResolver
import org.jetbrains.kotlin.psi.KtParameter; import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
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;
/** /**
* A platform-independent logic for generating data class synthetic methods. * 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 * 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 { abstract class DataClassMethodGenerator(private val declaration: KtClassOrObject, private val bindingContext: BindingContext) {
private final KtClassOrObject declaration; protected val classDescriptor: ClassDescriptor = BindingContextUtils.getNotNull(bindingContext, BindingContext.CLASS, declaration)
private final BindingContext bindingContext;
private final ClassDescriptor classDescriptor;
private final KotlinBuiltIns builtIns;
public DataClassMethodGenerator(KtClassOrObject declaration, BindingContext bindingContext) { private val builtIns = classDescriptor.builtIns
this.declaration = declaration;
this.bindingContext = bindingContext;
this.classDescriptor = BindingContextUtils.getNotNull(bindingContext, BindingContext.CLASS, declaration);
this.builtIns = DescriptorUtilsKt.getBuiltIns(classDescriptor);
}
public void generate() { fun generate() {
generateComponentFunctionsForDataClasses(); generateComponentFunctionsForDataClasses()
generateCopyFunctionForDataClasses(getPrimaryConstructorParameters()); generateCopyFunctionForDataClasses(primaryConstructorParameters)
List<PropertyDescriptor> properties = getDataProperties(); val properties = dataProperties
if (!properties.isEmpty()) { if (properties.isNotEmpty()) {
generateDataClassToStringIfNeeded(properties); generateDataClassToStringIfNeeded(properties)
generateDataClassHashCodeIfNeeded(properties); generateDataClassHashCodeIfNeeded(properties)
generateDataClassEqualsIfNeeded(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 private fun generateComponentFunctionsForDataClasses() {
protected ClassDescriptor getClassDescriptor() {
return classDescriptor;
}
private void generateComponentFunctionsForDataClasses() {
ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
// primary constructor should exist for data classes // primary constructor should exist for data classes
// but when generating light-classes still need to check we have one // 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()) { for (parameter in constructor.valueParameters) {
FunctionDescriptor function = bindingContext.get(BindingContext.DATA_CLASS_COMPONENT_FUNCTION, parameter); val function = bindingContext.get(BindingContext.DATA_CLASS_COMPONENT_FUNCTION, parameter)
if (function != null) { if (function != null) {
generateComponentFunction(function, parameter); generateComponentFunction(function, parameter)
} }
} }
} }
private void generateCopyFunctionForDataClasses(List<KtParameter> constructorParameters) { private fun generateCopyFunctionForDataClasses(constructorParameters: List<KtParameter>) {
FunctionDescriptor copyFunction = bindingContext.get(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor); val copyFunction = bindingContext.get(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor) ?: return
if (copyFunction != null) { generateCopyFunction(copyFunction, constructorParameters)
generateCopyFunction(copyFunction, constructorParameters);
}
} }
private void generateDataClassToStringIfNeeded(@NotNull List<PropertyDescriptor> properties) { private fun generateDataClassToStringIfNeeded(properties: List<PropertyDescriptor>) {
FunctionDescriptor function = getDeclaredMember("toString", builtIns.getString()); val function = getDeclaredMember("toString", builtIns.string)
if (function != null && isTrivial(function)) { if (function != null && isTrivial(function)) {
generateToStringMethod(function, properties); generateToStringMethod(function, properties)
} }
} }
private void generateDataClassHashCodeIfNeeded(@NotNull List<PropertyDescriptor> properties) { private fun generateDataClassHashCodeIfNeeded(properties: List<PropertyDescriptor>) {
FunctionDescriptor function = getDeclaredMember("hashCode", builtIns.getInt()); val function = getDeclaredMember("hashCode", builtIns.int)
if (function != null && isTrivial(function)) { if (function != null && isTrivial(function)) {
generateHashCodeMethod(function, properties); generateHashCodeMethod(function, properties)
} }
} }
private void generateDataClassEqualsIfNeeded(@NotNull List<PropertyDescriptor> properties) { private fun generateDataClassEqualsIfNeeded(properties: List<PropertyDescriptor>) {
FunctionDescriptor function = getDeclaredMember("equals", builtIns.getBoolean(), builtIns.getAny()); val function = getDeclaredMember("equals", builtIns.boolean, builtIns.any)
if (function != null && isTrivial(function)) { if (function != null && isTrivial(function)) {
generateEqualsMethod(function, properties); generateEqualsMethod(function, properties)
} }
} }
private List<PropertyDescriptor> getDataProperties() { private val dataProperties: List<PropertyDescriptor>
List<PropertyDescriptor> result = Lists.newArrayList(); get() = primaryConstructorParameters
for (KtParameter parameter : getPrimaryConstructorParameters()) { .filter { it.hasValOrVar() }
if (parameter.hasValOrVar()) { .map { bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it)!! }
result.add(bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter));
}
}
return result;
}
@NotNull private val primaryConstructorParameters: List<KtParameter>
private List<KtParameter> getPrimaryConstructorParameters() { get() = (declaration as? KtClass)?.getPrimaryConstructorParameters().orEmpty()
if (declaration instanceof KtClass) {
return declaration.getPrimaryConstructorParameters();
}
return Collections.emptyList();
}
@Nullable private fun getDeclaredMember(
private FunctionDescriptor getDeclaredMember( name: String,
@NotNull String name, returnedClassifier: ClassDescriptor,
@NotNull ClassDescriptor returnedClassifier, vararg valueParameterClassifiers: ClassDescriptor
@NotNull ClassDescriptor... valueParameterClassifiers ): FunctionDescriptor? = CodegenUtil.getDeclaredFunctionByRawSignature(
) { classDescriptor, Name.identifier(name), returnedClassifier, *valueParameterClassifiers
return CodegenUtil.getDeclaredFunctionByRawSignature( )
classDescriptor, Name.identifier(name), returnedClassifier, valueParameterClassifiers
);
}
/** /**
* @return true if the member is an inherited implementation of a method from Any * @return true if the member is an inherited implementation of a method from Any
*/ */
private boolean isTrivial(@NotNull FunctionDescriptor function) { private fun isTrivial(function: FunctionDescriptor): Boolean {
if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) { return function.kind != CallableMemberDescriptor.Kind.DECLARATION &&
return false; OverrideResolver.getOverriddenDeclarations(function).none { overridden ->
} overridden is CallableMemberDescriptor &&
overridden.kind == CallableMemberDescriptor.Kind.DECLARATION &&
for (CallableDescriptor overridden : OverrideResolver.getOverriddenDeclarations(function)) { overridden.containingDeclaration != builtIns.any
if (overridden instanceof CallableMemberDescriptor }
&& ((CallableMemberDescriptor) overridden).getKind() == CallableMemberDescriptor.Kind.DECLARATION
&& !overridden.getContainingDeclaration().equals(builtIns.getAny())) {
return false;
}
}
return true;
} }
} }
@@ -27,7 +27,6 @@ import kotlin.jvm.functions.Function2;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.CodegenUtil; 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.backend.common.DataClassMethodGenerator;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.codegen.binding.MutableClosure; import org.jetbrains.kotlin.codegen.binding.MutableClosure;
@@ -496,7 +495,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
@Override @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); MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function);
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null); MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null);
InstructionAdapter iv = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
@@ -553,7 +552,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
@Override @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); MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function);
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "hashCode", "()I", null, null); MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "hashCode", "()I", null, null);
InstructionAdapter iv = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
@@ -602,7 +601,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
@Override @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); MethodContext context = ImplementationBodyCodegen.this.context.intoFunction(function);
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
InstructionAdapter iv = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
@@ -692,7 +691,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
@Override @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); final Type thisDescriptorType = typeMapper.mapType(descriptor);
functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(myClass, function), function, new FunctionGenerationStrategy() { 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); fieldInfo.name, fieldInfo.type.getDescriptor(), /*TODO*/null, null);
} }
protected void generateDelegates(ClassDescriptor toTrait, KotlinType delegateExpressionType, DelegationFieldsInfo.Field field) { private void generateDelegates(ClassDescriptor toTrait, KotlinType delegateExpressionType, DelegationFieldsInfo.Field field) {
for (Map.Entry<CallableMemberDescriptor, CallableDescriptor> entry : CodegenUtilKt.getDelegates(descriptor, toTrait, delegateExpressionType).entrySet()) { for (Map.Entry<CallableMemberDescriptor, CallableDescriptor> entry :
CodegenUtil.getDelegates(descriptor, toTrait, delegateExpressionType).entrySet()) {
CallableMemberDescriptor callableMemberDescriptor = entry.getKey(); CallableMemberDescriptor callableMemberDescriptor = entry.getKey();
CallableDescriptor delegateTo = entry.getValue(); CallableDescriptor delegateTo = entry.getValue();
if (callableMemberDescriptor instanceof PropertyDescriptor) { if (callableMemberDescriptor instanceof PropertyDescriptor) {
@@ -82,12 +82,13 @@ class JvmStaticGenerator(
} }
companion object { 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 memberDescriptor = if (descriptor is PropertyAccessorDescriptor) descriptor.correspondingProperty else descriptor
val copies = CodegenUtil.copyFunctions( val copies = CodegenUtil.copyFunctions(
memberDescriptor, memberDescriptor,
memberDescriptor, memberDescriptor,
descriptor.containingDeclaration.containingDeclaration, descriptor.containingDeclaration.containingDeclaration!!,
descriptor.modality, descriptor.modality,
descriptor.visibility, descriptor.visibility,
CallableMemberDescriptor.Kind.SYNTHESIZED, CallableMemberDescriptor.Kind.SYNTHESIZED,
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.* import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.backend.common.CodegenUtilKt
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext 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.TranslationUtils.translateFunctionAsEcma5PropertyDescriptor
import org.jetbrains.kotlin.js.translate.utils.generateDelegateCall import org.jetbrains.kotlin.js.translate.utils.generateDelegateCall
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtSuperTypeListEntry
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
import org.jetbrains.kotlin.psi.KtSuperTypeListEntry
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
class DelegationTranslator( class DelegationTranslator(
@@ -90,7 +89,7 @@ class DelegationTranslator(
CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext()) CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext())
private fun generateDelegates(toClass: ClassDescriptor, field: Field, properties: MutableList<JsPropertyInitializer>) { 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) { when (descriptor) {
is PropertyDescriptor -> is PropertyDescriptor ->
generateDelegateCallForPropertyMember(descriptor, field.name, properties) generateDelegateCallForPropertyMember(descriptor, field.name, properties)
@@ -61,7 +61,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
} }
@Override @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); JsFunction functionObj = generateJsMethod(function);
assert function.getValueParameters().size() == constructorParameters.size(); assert function.getValueParameters().size() == constructorParameters.size();
@@ -110,7 +110,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
} }
@Override @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. // TODO: relax this limitation, with the data generation logic fixed.
assert !classProperties.isEmpty(); assert !classProperties.isEmpty();
JsFunction functionObj = generateJsMethod(function); JsFunction functionObj = generateJsMethod(function);
@@ -136,7 +136,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
} }
@Override @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); JsFunction functionObj = generateJsMethod(function);
JsProgram jsProgram = context.program(); JsProgram jsProgram = context.program();
@@ -161,7 +161,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
} }
@Override @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(); assert !classProperties.isEmpty();
JsFunction functionObj = generateJsMethod(function); JsFunction functionObj = generateJsMethod(function);
JsFunctionScope funScope = functionObj.getScope(); JsFunctionScope funScope = functionObj.getScope();