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