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    }