FIR: Do not load hashCode/toString/equals methods from Java interface

As it's done in FE 1.0, and there are subtle semantics in the language that depends on it
This commit is contained in:
Denis Zharkov
2020-09-22 18:26:31 +03:00
parent 7c7c5336f9
commit 9914b487b7
6 changed files with 37 additions and 42 deletions
@@ -205,6 +205,7 @@ class JavaSymbolProvider(
val classIsAnnotation = classKind == ClassKind.ANNOTATION_CLASS
for (javaMethod in javaClass.methods) {
if (javaMethod.isObjectMethodInInterface()) continue
declarations += convertJavaMethodToFir(
javaMethod,
classId,
@@ -1,6 +1,4 @@
public abstract interface Comparator<T : R|ft<kotlin/Any, kotlin/Any?>!|> : R|kotlin/Any| {
public abstract fun compare(o1: R|ft<T, T?>!|, o2: R|ft<T, T?>!|): R|kotlin/Int|
public abstract operator fun equals(obj: R|kotlin/Any?|): R|kotlin/Boolean|
}
@@ -1,4 +1,2 @@
public abstract interface InterfaceWithObjectMethod : R|kotlin/Any| {
public abstract fun toString(): R|kotlin/String|
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.load.java.structure
fun JavaMember.isObjectMethodInInterface(): Boolean {
return containingClass.isInterface && this is JavaMethod && isObjectMethod(this)
}
private fun isObjectMethod(method: JavaMethod): Boolean {
return when (method.name.asString()) {
"toString", "hashCode" -> {
method.valueParameters.isEmpty()
}
"equals" -> {
isMethodWithOneObjectParameter(method)
}
else -> false
}
}
private fun isMethodWithOneObjectParameter(method: JavaMethod): Boolean {
val parameters = method.valueParameters
val type = parameters.singleOrNull()?.type as? JavaClassifierType ?: return false
val classifier = type.classifier
if (classifier is JavaClass) {
val classFqName = classifier.fqName
return classFqName != null && classFqName.asString() == "java.lang.Object"
}
return false
}
@@ -24,8 +24,6 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.load.java.structure.*;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy;
import org.jetbrains.kotlin.resolve.OverridingUtil;
@@ -33,7 +31,6 @@ import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public final class DescriptorResolverUtils {
@@ -121,33 +118,4 @@ public final class DescriptorResolverUtils {
return null;
}
public static boolean isObjectMethodInInterface(@NotNull JavaMember member) {
return member.getContainingClass().isInterface() && member instanceof JavaMethod && isObjectMethod((JavaMethod) member);
}
private static boolean isObjectMethod(@NotNull JavaMethod method) {
String name = method.getName().asString();
if (name.equals("toString") || name.equals("hashCode")) {
return method.getValueParameters().isEmpty();
}
else if (name.equals("equals")) {
return isMethodWithOneObjectParameter(method);
}
return false;
}
private static boolean isMethodWithOneObjectParameter(@NotNull JavaMethod method) {
List<JavaValueParameter> parameters = method.getValueParameters();
if (parameters.size() == 1) {
JavaType type = parameters.get(0).getType();
if (type instanceof JavaClassifierType) {
JavaClassifier classifier = ((JavaClassifierType) type).getClassifier();
if (classifier instanceof JavaClass) {
FqName classFqName = ((JavaClass) classifier).getFqName();
return classFqName != null && classFqName.asString().equals("java.lang.Object");
}
}
}
return false;
}
}
@@ -16,11 +16,7 @@
package org.jetbrains.kotlin.load.java.lazy.descriptors
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaField
import org.jetbrains.kotlin.load.java.structure.JavaMember
import org.jetbrains.kotlin.load.java.structure.JavaMethod
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.Name
interface DeclaredMemberIndex {
@@ -44,7 +40,7 @@ open class ClassDeclaredMemberIndex(
private val memberFilter: (JavaMember) -> Boolean
) : DeclaredMemberIndex {
private val methodFilter = { m: JavaMethod ->
memberFilter(m) && !DescriptorResolverUtils.isObjectMethodInInterface(m)
memberFilter(m) && !m.isObjectMethodInInterface()
}
private val methods = jClass.methods.asSequence().filter(methodFilter).groupBy { m -> m.name }