/*
* 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.resolve;
import kotlin.
Unit;
import kotlin.jvm.functions.
Function1;
import org.jetbrains.annotations.
Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.name.
Name;
import org.jetbrains.kotlin.renderer.
AnnotationArgumentsRenderingPolicy;
import org.jetbrains.kotlin.renderer.
DescriptorRenderer;
import org.jetbrains.kotlin.renderer.
DescriptorRendererModifier;
import org.jetbrains.kotlin.renderer.
DescriptorRendererOptions;
import org.jetbrains.kotlin.types.
KotlinType;
import java.util.
Comparator;
import java.util.
List;
import static org.jetbrains.kotlin.resolve.
DescriptorUtils.isEnumEntry;
public class
MemberComparator implements
Comparator<
DeclarationDescriptor> {
public static final
MemberComparator INSTANCE = new
MemberComparator();
private static final
DescriptorRenderer RENDERER =
DescriptorRenderer.
Companion.
withOptions(
new
Function1<
DescriptorRendererOptions,
Unit>() {
@
Override
public
Unit invoke(
DescriptorRendererOptions options) {
options.
setWithDefinedIn(false);
options.
setVerbose(true);
options.
setAnnotationArgumentsRenderingPolicy(
AnnotationArgumentsRenderingPolicy.
UNLESS_EMPTY);
options.
setModifiers(
DescriptorRendererModifier.
ALL);
return
Unit.
INSTANCE;
}
});
private
MemberComparator() {
}
public static class
NameAndTypeMemberComparator implements
Comparator<
DeclarationDescriptor> {
public static final
NameAndTypeMemberComparator INSTANCE = new
NameAndTypeMemberComparator();
private
NameAndTypeMemberComparator() {
}
private static int
getDeclarationPriority(
DeclarationDescriptor descriptor) {
if (
isEnumEntry(
descriptor)) {
return 8;
}
else if (
descriptor instanceof
ConstructorDescriptor) {
return 7;
}
else if (
descriptor instanceof
PropertyDescriptor) {
if (((
PropertyDescriptor)
descriptor).
getExtensionReceiverParameter() == null) {
return 6;
}
else {
return 5;
}
}
else if (
descriptor instanceof
FunctionDescriptor) {
if (((
FunctionDescriptor)
descriptor).
getExtensionReceiverParameter() == null) {
return 4;
}
else {
return 3;
}
}
else if (
descriptor instanceof
ClassDescriptor) {
return 2;
}
else if (
descriptor instanceof
TypeAliasDescriptor) {
return 1;
}
return 0;
}
@
Override
public int
compare(
DeclarationDescriptor o1,
DeclarationDescriptor o2) {
Integer compareInternal =
compareInternal(
o1,
o2);
return
compareInternal != null ?
compareInternal : 0;
}
@
Nullable
private static
Integer compareInternal(
DeclarationDescriptor o1,
DeclarationDescriptor o2) {
int
prioritiesCompareTo =
getDeclarationPriority(
o2) -
getDeclarationPriority(
o1);
if (
prioritiesCompareTo != 0) {
return
prioritiesCompareTo;
}
if (
isEnumEntry(
o1) &&
isEnumEntry(
o2)) {
//never reorder enum entries
return 0;
}
int
namesCompareTo =
o1.
getName().
compareTo(
o2.
getName());
if (
namesCompareTo != 0) {
return
namesCompareTo;
}
// Might be equal
return null;
}
}
@
Override
public int
compare(
DeclarationDescriptor o1,
DeclarationDescriptor o2) {
Integer typeAndNameCompareResult =
NameAndTypeMemberComparator.
compareInternal(
o1,
o2);
if (
typeAndNameCompareResult != null) {
return
typeAndNameCompareResult;
}
if (
o1 instanceof
TypeAliasDescriptor &&
o2 instanceof
TypeAliasDescriptor) {
TypeAliasDescriptor ta1 = (
TypeAliasDescriptor)
o1;
TypeAliasDescriptor ta2 = (
TypeAliasDescriptor)
o2;
String r1 =
RENDERER.
renderType(
ta1.
getUnderlyingType());
String r2 =
RENDERER.
renderType(
ta2.
getUnderlyingType());
int
underlyingTypesCompareTo =
r1.
compareTo(
r2);
if (
underlyingTypesCompareTo != 0) {
return
underlyingTypesCompareTo;
}
}
else if (
o1 instanceof
CallableDescriptor &&
o2 instanceof
CallableDescriptor) {
CallableDescriptor c1 = (
CallableDescriptor)
o1;
CallableDescriptor c2 = (
CallableDescriptor)
o2;
ReceiverParameterDescriptor c1ReceiverParameter =
c1.
getExtensionReceiverParameter();
ReceiverParameterDescriptor c2ReceiverParameter =
c2.
getExtensionReceiverParameter();
assert (
c1ReceiverParameter != null) == (
c2ReceiverParameter != null);
if (
c1ReceiverParameter != null) {
String r1 =
RENDERER.
renderType(
c1ReceiverParameter.
getType());
String r2 =
RENDERER.
renderType(
c2ReceiverParameter.
getType());
int
receiversCompareTo =
r1.
compareTo(
r2);
if (
receiversCompareTo != 0) {
return
receiversCompareTo;
}
}
List<
ValueParameterDescriptor>
c1ValueParameters =
c1.
getValueParameters();
List<
ValueParameterDescriptor>
c2ValueParameters =
c2.
getValueParameters();
for (int
i = 0;
i <
Math.
min(
c1ValueParameters.
size(),
c2ValueParameters.
size());
i++) {
String p1 =
RENDERER.
renderType(
c1ValueParameters.
get(
i).
getType());
String p2 =
RENDERER.
renderType(
c2ValueParameters.
get(
i).
getType());
int
parametersCompareTo =
p1.
compareTo(
p2);
if (
parametersCompareTo != 0) {
return
parametersCompareTo;
}
}
int
valueParametersNumberCompareTo =
c1ValueParameters.
size() -
c2ValueParameters.
size();
if (
valueParametersNumberCompareTo != 0) {
return
valueParametersNumberCompareTo;
}
List<
TypeParameterDescriptor>
c1TypeParameters =
c1.
getTypeParameters();
List<
TypeParameterDescriptor>
c2TypeParameters =
c2.
getTypeParameters();
for (int
i = 0;
i <
Math.
min(
c1TypeParameters.
size(),
c2TypeParameters.
size());
i++) {
List<
KotlinType>
c1Bounds =
c1TypeParameters.
get(
i).
getUpperBounds();
List<
KotlinType>
c2Bounds =
c2TypeParameters.
get(
i).
getUpperBounds();
int
boundsCountCompareTo =
c1Bounds.
size() -
c2Bounds.
size();
if (
boundsCountCompareTo != 0) {
return
boundsCountCompareTo;
}
for (int
j = 0;
j <
c1Bounds.
size();
j++) {
String b1 =
RENDERER.
renderType(
c1Bounds.
get(
j));
String b2 =
RENDERER.
renderType(
c2Bounds.
get(
j));
int
boundCompareTo =
b1.
compareTo(
b2);
if (
boundCompareTo != 0) {
return
boundCompareTo;
}
}
}
int
typeParametersCompareTo =
c1TypeParameters.
size() -
c2TypeParameters.
size();
if (
typeParametersCompareTo != 0) {
return
typeParametersCompareTo;
}
if (
c1 instanceof
CallableMemberDescriptor &&
c2 instanceof
CallableMemberDescriptor) {
CallableMemberDescriptor.
Kind c1Kind = ((
CallableMemberDescriptor)
c1).
getKind();
CallableMemberDescriptor.
Kind c2Kind = ((
CallableMemberDescriptor)
c2).
getKind();
int
kindsCompareTo =
c1Kind.
ordinal() -
c2Kind.
ordinal();
if (
kindsCompareTo != 0) {
return
kindsCompareTo;
}
}
}
else if (
o1 instanceof
ClassDescriptor &&
o2 instanceof
ClassDescriptor) {
ClassDescriptor class1 = (
ClassDescriptor)
o1;
ClassDescriptor class2 = (
ClassDescriptor)
o2;
if (
class1.
getKind().
ordinal() !=
class2.
getKind().
ordinal()) {
return
class1.
getKind().
ordinal() -
class2.
getKind().
ordinal();
}
if (
class1.
isCompanionObject() !=
class2.
isCompanionObject()) {
return
class1.
isCompanionObject() ? 1 : -1;
}
}
else {
throw new
AssertionError(
String.
format(
"Unsupported pair of descriptors:\n'" +
"%s' Class: %s\n" +
"%s' Class: %s",
o1,
o1.
getClass(),
o2,
o2.
getClass()));
}
int
renderDiff =
RENDERER.
render(
o1).
compareTo(
RENDERER.
render(
o2));
if (
renderDiff != 0) return
renderDiff;
Name firstModuleName =
DescriptorUtils.
getContainingModule(
o1).
getName();
Name secondModuleName =
DescriptorUtils.
getContainingModule(
o2).
getName();
return
firstModuleName.
compareTo(
secondModuleName);
}
}