001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.resolve; 018 019 import org.jetbrains.kotlin.descriptors.*; 020 import org.jetbrains.kotlin.name.Name; 021 import org.jetbrains.kotlin.renderer.DescriptorRenderer; 022 import org.jetbrains.kotlin.renderer.DescriptorRendererBuilder; 023 024 import java.util.Comparator; 025 import java.util.List; 026 027 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; 028 029 public class MemberComparator implements Comparator<DeclarationDescriptor> { 030 public static final MemberComparator INSTANCE = new MemberComparator(); 031 032 private static final DescriptorRenderer RENDERER = new DescriptorRendererBuilder().setWithDefinedIn(false).setVerbose(true).build(); 033 034 private MemberComparator() { 035 } 036 037 private static int getDeclarationPriority(DeclarationDescriptor descriptor) { 038 if (isEnumEntry(descriptor)) { 039 return 7; 040 } 041 else if (descriptor instanceof ConstructorDescriptor) { 042 return 6; 043 } 044 else if (descriptor instanceof PropertyDescriptor) { 045 if (((PropertyDescriptor)descriptor).getExtensionReceiverParameter() == null) { 046 return 5; 047 } 048 else { 049 return 4; 050 } 051 } 052 else if (descriptor instanceof FunctionDescriptor) { 053 if (((FunctionDescriptor)descriptor).getExtensionReceiverParameter() == null) { 054 return 3; 055 } 056 else { 057 return 2; 058 } 059 } 060 else if (descriptor instanceof ClassDescriptor) { 061 return 1; 062 } 063 return 0; 064 } 065 066 @Override 067 public int compare(DeclarationDescriptor o1, DeclarationDescriptor o2) { 068 int prioritiesCompareTo = getDeclarationPriority(o2) - getDeclarationPriority(o1); 069 if (prioritiesCompareTo != 0) { 070 return prioritiesCompareTo; 071 } 072 if (isEnumEntry(o1) && isEnumEntry(o2)) { 073 //never reorder enum entries 074 return 0; 075 } 076 077 int namesCompareTo = o1.getName().compareTo(o2.getName()); 078 if (namesCompareTo != 0) { 079 return namesCompareTo; 080 } 081 082 if (o1 instanceof CallableDescriptor && o2 instanceof CallableDescriptor) { 083 CallableDescriptor c1 = (CallableDescriptor) o1; 084 CallableDescriptor c2 = (CallableDescriptor) o2; 085 086 ReceiverParameterDescriptor c1ReceiverParameter = c1.getExtensionReceiverParameter(); 087 ReceiverParameterDescriptor c2ReceiverParameter = c2.getExtensionReceiverParameter(); 088 assert (c1ReceiverParameter != null) == (c2ReceiverParameter != null); 089 if (c1ReceiverParameter != null) { 090 String r1 = RENDERER.renderType(c1ReceiverParameter.getType()); 091 String r2 = RENDERER.renderType(c2ReceiverParameter.getType()); 092 int receiversCompareTo = r1.compareTo(r2); 093 if (receiversCompareTo != 0) { 094 return receiversCompareTo; 095 } 096 } 097 098 List<ValueParameterDescriptor> c1ValueParameters = c1.getValueParameters(); 099 List<ValueParameterDescriptor> c2ValueParameters = c2.getValueParameters(); 100 for (int i = 0; i < Math.min(c1ValueParameters.size(), c2ValueParameters.size()); i++) { 101 String p1 = RENDERER.renderType(c1ValueParameters.get(i).getType()); 102 String p2 = RENDERER.renderType(c2ValueParameters.get(i).getType()); 103 int parametersCompareTo = p1.compareTo(p2); 104 if (parametersCompareTo != 0) { 105 return parametersCompareTo; 106 } 107 } 108 109 int valueParametersNumberCompareTo = c1ValueParameters.size() - c2ValueParameters.size(); 110 if (valueParametersNumberCompareTo != 0) { 111 return valueParametersNumberCompareTo; 112 } 113 114 List<TypeParameterDescriptor> c1TypeParameters = c1.getTypeParameters(); 115 List<TypeParameterDescriptor> c2TypeParameters = c2.getTypeParameters(); 116 for (int i = 0; i < Math.min(c1TypeParameters.size(), c2TypeParameters.size()); i++) { 117 String p1 = RENDERER.renderType(c1TypeParameters.get(i).getUpperBoundsAsType()); 118 String p2 = RENDERER.renderType(c2TypeParameters.get(i).getUpperBoundsAsType()); 119 int parametersCompareTo = p1.compareTo(p2); 120 if (parametersCompareTo != 0) { 121 return parametersCompareTo; 122 } 123 } 124 125 int typeParametersCompareTo = c1TypeParameters.size() - c2TypeParameters.size(); 126 if (typeParametersCompareTo != 0) { 127 return typeParametersCompareTo; 128 } 129 130 if (c1 instanceof CallableMemberDescriptor && c2 instanceof CallableMemberDescriptor) { 131 CallableMemberDescriptor.Kind c1Kind = ((CallableMemberDescriptor) c1).getKind(); 132 CallableMemberDescriptor.Kind c2Kind = ((CallableMemberDescriptor) c2).getKind(); 133 int kindsCompareTo = c1Kind.ordinal() - c2Kind.ordinal(); 134 if (kindsCompareTo != 0) { 135 return kindsCompareTo; 136 } 137 } 138 } 139 else if (o1 instanceof ClassDescriptor && o2 instanceof ClassDescriptor) { 140 ClassDescriptor class1 = (ClassDescriptor) o1; 141 ClassDescriptor class2 = (ClassDescriptor) o2; 142 143 if (class1.getKind().ordinal() != class2.getKind().ordinal()) { 144 return class1.getKind().ordinal() - class2.getKind().ordinal(); 145 } 146 147 if (class1.isDefaultObject() != class2.isDefaultObject()) { 148 return class1.isDefaultObject() ? 1 : -1; 149 } 150 } 151 else { 152 throw new AssertionError(String.format( 153 "Unsupported pair of descriptors:\n'" + 154 "%s' Class: %s\n" + 155 "%s' Class: %s", 156 o1, o1.getClass(), o2, o2.getClass())); 157 } 158 159 int renderDiff = RENDERER.render(o1).compareTo(RENDERER.render(o2)); 160 if (renderDiff != 0) return renderDiff; 161 162 Name firstModuleName = DescriptorUtils.getContainingModule(o1).getName(); 163 Name secondModuleName = DescriptorUtils.getContainingModule(o2).getName(); 164 165 return firstModuleName.compareTo(secondModuleName); 166 } 167 }