Optimize and improve AbstractClassTypeConstructor.equals

Instead of computing and comparing FQ names, compare simple names of
classes and theirs containers. This code was responsible for creation of
about 10% of FqNameUnsafe instances during compilation of "core"
modules.

Also make the check more strict: previously, a class "c" declared in
package "a.b" would be considered equal to a class "c" declared in class
"b" in package "a". Because JVM type descriptors of such classes are
different, this behavior was suspicious and might have lead to error at
runtime. Now, we require the number of containing classes of the given
two classes also to be the same
This commit is contained in:
Alexander Udalov
2017-06-21 15:17:26 +03:00
parent d5e02f069a
commit 0352bdbca5
@@ -18,9 +18,7 @@ package org.jetbrains.kotlin.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
@@ -63,7 +61,7 @@ public abstract class AbstractClassTypeConstructor extends AbstractTypeConstruct
}
@Override
public boolean equals(Object other) {
public final boolean equals(Object other) {
if (!(other instanceof TypeConstructor)) return false;
// performance optimization: getFqName is slow method
@@ -86,14 +84,35 @@ public abstract class AbstractClassTypeConstructor extends AbstractTypeConstruct
}
if (myDescriptor instanceof ClassDescriptor && otherDescriptor instanceof ClassDescriptor) {
FqNameUnsafe otherFqName = DescriptorUtils.getFqName(otherDescriptor);
FqNameUnsafe myFqName = DescriptorUtils.getFqName(myDescriptor);
return myFqName.equals(otherFqName);
return areFqNamesEqual(((ClassDescriptor) myDescriptor), ((ClassDescriptor) otherDescriptor));
}
return false;
}
private static boolean areFqNamesEqual(ClassDescriptor first, ClassDescriptor second) {
if (!first.getName().equals(second.getName())) return false;
DeclarationDescriptor a = first.getContainingDeclaration();
DeclarationDescriptor b = second.getContainingDeclaration();
while (a != null && b != null) {
if (a instanceof ModuleDescriptor) return b instanceof ModuleDescriptor;
if (b instanceof ModuleDescriptor) return false;
if (a instanceof PackageFragmentDescriptor) {
return b instanceof PackageFragmentDescriptor &&
((PackageFragmentDescriptor) a).getFqName().equals(((PackageFragmentDescriptor) b).getFqName());
}
if (b instanceof PackageFragmentDescriptor) return false;
if (!a.getName().equals(b.getName())) return false;
a = a.getContainingDeclaration();
b = b.getContainingDeclaration();
}
return true;
}
private static boolean hasMeaningfulFqName(@NotNull ClassifierDescriptor descriptor) {
return !ErrorUtils.isError(descriptor) &&
!DescriptorUtils.isLocal(descriptor);