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 kotlin.Unit; 020 import kotlin.jvm.functions.Function1; 021 import org.jetbrains.kotlin.descriptors.*; 022 import org.jetbrains.kotlin.name.Name; 023 import org.jetbrains.kotlin.renderer.DescriptorRenderer; 024 import org.jetbrains.kotlin.renderer.DescriptorRendererModifier; 025 import org.jetbrains.kotlin.renderer.DescriptorRendererOptions; 026 import org.jetbrains.kotlin.types.KotlinType; 027 028 import java.util.Comparator; 029 import java.util.List; 030 031 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; 032 033 public class MemberComparator implements Comparator<DeclarationDescriptor> { 034 public static final MemberComparator INSTANCE = new MemberComparator(); 035 036 private static final DescriptorRenderer RENDERER = DescriptorRenderer.Companion.withOptions( 037 new Function1<DescriptorRendererOptions, Unit>() { 038 @Override 039 public Unit invoke(DescriptorRendererOptions options) { 040 options.setWithDefinedIn(false); 041 options.setVerbose(true); 042 options.setModifiers(DescriptorRendererModifier.ALL); 043 return Unit.INSTANCE; 044 } 045 }); 046 047 private MemberComparator() { 048 } 049 050 private static int getDeclarationPriority(DeclarationDescriptor descriptor) { 051 if (isEnumEntry(descriptor)) { 052 return 7; 053 } 054 else if (descriptor instanceof ConstructorDescriptor) { 055 return 6; 056 } 057 else if (descriptor instanceof PropertyDescriptor) { 058 if (((PropertyDescriptor)descriptor).getExtensionReceiverParameter() == null) { 059 return 5; 060 } 061 else { 062 return 4; 063 } 064 } 065 else if (descriptor instanceof FunctionDescriptor) { 066 if (((FunctionDescriptor)descriptor).getExtensionReceiverParameter() == null) { 067 return 3; 068 } 069 else { 070 return 2; 071 } 072 } 073 else if (descriptor instanceof ClassDescriptor) { 074 return 1; 075 } 076 return 0; 077 } 078 079 @Override 080 public int compare(DeclarationDescriptor o1, DeclarationDescriptor o2) { 081 int prioritiesCompareTo = getDeclarationPriority(o2) - getDeclarationPriority(o1); 082 if (prioritiesCompareTo != 0) { 083 return prioritiesCompareTo; 084 } 085 if (isEnumEntry(o1) && isEnumEntry(o2)) { 086 //never reorder enum entries 087 return 0; 088 } 089 090 int namesCompareTo = o1.getName().compareTo(o2.getName()); 091 if (namesCompareTo != 0) { 092 return namesCompareTo; 093 } 094 095 if (o1 instanceof CallableDescriptor && o2 instanceof CallableDescriptor) { 096 CallableDescriptor c1 = (CallableDescriptor) o1; 097 CallableDescriptor c2 = (CallableDescriptor) o2; 098 099 ReceiverParameterDescriptor c1ReceiverParameter = c1.getExtensionReceiverParameter(); 100 ReceiverParameterDescriptor c2ReceiverParameter = c2.getExtensionReceiverParameter(); 101 assert (c1ReceiverParameter != null) == (c2ReceiverParameter != null); 102 if (c1ReceiverParameter != null) { 103 String r1 = RENDERER.renderType(c1ReceiverParameter.getType()); 104 String r2 = RENDERER.renderType(c2ReceiverParameter.getType()); 105 int receiversCompareTo = r1.compareTo(r2); 106 if (receiversCompareTo != 0) { 107 return receiversCompareTo; 108 } 109 } 110 111 List<ValueParameterDescriptor> c1ValueParameters = c1.getValueParameters(); 112 List<ValueParameterDescriptor> c2ValueParameters = c2.getValueParameters(); 113 for (int i = 0; i < Math.min(c1ValueParameters.size(), c2ValueParameters.size()); i++) { 114 String p1 = RENDERER.renderType(c1ValueParameters.get(i).getType()); 115 String p2 = RENDERER.renderType(c2ValueParameters.get(i).getType()); 116 int parametersCompareTo = p1.compareTo(p2); 117 if (parametersCompareTo != 0) { 118 return parametersCompareTo; 119 } 120 } 121 122 int valueParametersNumberCompareTo = c1ValueParameters.size() - c2ValueParameters.size(); 123 if (valueParametersNumberCompareTo != 0) { 124 return valueParametersNumberCompareTo; 125 } 126 127 List<TypeParameterDescriptor> c1TypeParameters = c1.getTypeParameters(); 128 List<TypeParameterDescriptor> c2TypeParameters = c2.getTypeParameters(); 129 for (int i = 0; i < Math.min(c1TypeParameters.size(), c2TypeParameters.size()); i++) { 130 List<KotlinType> c1Bounds = c1TypeParameters.get(i).getUpperBounds(); 131 List<KotlinType> c2Bounds = c2TypeParameters.get(i).getUpperBounds(); 132 int boundsCountCompareTo = c1Bounds.size() - c2Bounds.size(); 133 if (boundsCountCompareTo != 0) { 134 return boundsCountCompareTo; 135 } 136 for (int j = 0; j < c1Bounds.size(); j++) { 137 String b1 = RENDERER.renderType(c1Bounds.get(j)); 138 String b2 = RENDERER.renderType(c2Bounds.get(j)); 139 int boundCompareTo = b1.compareTo(b2); 140 if (boundCompareTo != 0) { 141 return boundCompareTo; 142 } 143 } 144 } 145 146 int typeParametersCompareTo = c1TypeParameters.size() - c2TypeParameters.size(); 147 if (typeParametersCompareTo != 0) { 148 return typeParametersCompareTo; 149 } 150 151 if (c1 instanceof CallableMemberDescriptor && c2 instanceof CallableMemberDescriptor) { 152 CallableMemberDescriptor.Kind c1Kind = ((CallableMemberDescriptor) c1).getKind(); 153 CallableMemberDescriptor.Kind c2Kind = ((CallableMemberDescriptor) c2).getKind(); 154 int kindsCompareTo = c1Kind.ordinal() - c2Kind.ordinal(); 155 if (kindsCompareTo != 0) { 156 return kindsCompareTo; 157 } 158 } 159 } 160 else if (o1 instanceof ClassDescriptor && o2 instanceof ClassDescriptor) { 161 ClassDescriptor class1 = (ClassDescriptor) o1; 162 ClassDescriptor class2 = (ClassDescriptor) o2; 163 164 if (class1.getKind().ordinal() != class2.getKind().ordinal()) { 165 return class1.getKind().ordinal() - class2.getKind().ordinal(); 166 } 167 168 if (class1.isCompanionObject() != class2.isCompanionObject()) { 169 return class1.isCompanionObject() ? 1 : -1; 170 } 171 } 172 else { 173 throw new AssertionError(String.format( 174 "Unsupported pair of descriptors:\n'" + 175 "%s' Class: %s\n" + 176 "%s' Class: %s", 177 o1, o1.getClass(), o2, o2.getClass())); 178 } 179 180 int renderDiff = RENDERER.render(o1).compareTo(RENDERER.render(o2)); 181 if (renderDiff != 0) return renderDiff; 182 183 Name firstModuleName = DescriptorUtils.getContainingModule(o1).getName(); 184 Name secondModuleName = DescriptorUtils.getContainingModule(o2).getName(); 185 186 return firstModuleName.compareTo(secondModuleName); 187 } 188 }