001    /*
002     * Copyright 2010-2013 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.jet.lang.resolve;
018    
019    import org.jetbrains.jet.lang.descriptors.*;
020    import org.jetbrains.jet.renderer.DescriptorRenderer;
021    import org.jetbrains.jet.renderer.DescriptorRendererBuilder;
022    
023    import java.util.Comparator;
024    import java.util.List;
025    
026    public class MemberComparator implements Comparator<DeclarationDescriptor> {
027        public static final MemberComparator INSTANCE = new MemberComparator();
028    
029        private static final DescriptorRenderer RENDERER = new DescriptorRendererBuilder().setWithDefinedIn(false).setVerbose(true).build();
030    
031        private MemberComparator() {
032        }
033    
034        private static int getDeclarationPriority(DeclarationDescriptor descriptor) {
035            if (descriptor instanceof ConstructorDescriptor) {
036                return 6;
037            }
038            else if (descriptor instanceof PropertyDescriptor) {
039                if (((PropertyDescriptor)descriptor).getReceiverParameter() == null) {
040                    return 5;
041                }
042                else {
043                    return 4;
044                }
045            }
046            else if (descriptor instanceof FunctionDescriptor) {
047                if (((FunctionDescriptor)descriptor).getReceiverParameter() == null) {
048                    return 3;
049                }
050                else {
051                    return 2;
052                }
053            }
054            else if (descriptor instanceof ClassDescriptor) {
055                return 1;
056            }
057            return 0;
058        }
059    
060        @Override
061        public int compare(DeclarationDescriptor o1, DeclarationDescriptor o2) {
062            int prioritiesCompareTo = getDeclarationPriority(o2) - getDeclarationPriority(o1);
063            if (prioritiesCompareTo != 0) {
064                return prioritiesCompareTo;
065            }
066    
067            int namesCompareTo = o1.getName().compareTo(o2.getName());
068            if (namesCompareTo != 0) {
069                return namesCompareTo;
070            }
071    
072            if (!(o1 instanceof CallableDescriptor) || !(o2 instanceof CallableDescriptor)) {
073                assert false;
074            }
075    
076            CallableDescriptor c1 = (CallableDescriptor)o1;
077            CallableDescriptor c2 = (CallableDescriptor)o2;
078    
079            ReceiverParameterDescriptor c1ReceiverParameter = c1.getReceiverParameter();
080            ReceiverParameterDescriptor c2ReceiverParameter = c2.getReceiverParameter();
081            assert (c1ReceiverParameter != null) == (c2ReceiverParameter != null);
082            if (c1ReceiverParameter != null) {
083                String r1 = RENDERER.renderType(c1ReceiverParameter.getType());
084                String r2 = RENDERER.renderType(c2ReceiverParameter.getType());
085                int receiversCompareTo = r1.compareTo(r2);
086                if (receiversCompareTo != 0) {
087                    return receiversCompareTo;
088                }
089            }
090    
091            List<ValueParameterDescriptor> c1ValueParameters = c1.getValueParameters();
092            List<ValueParameterDescriptor> c2ValueParameters = c2.getValueParameters();
093            for (int i = 0; i < Math.min(c1ValueParameters.size(), c2ValueParameters.size()); i++) {
094                String p1 = RENDERER.renderType(c1ValueParameters.get(i).getType());
095                String p2 = RENDERER.renderType(c2ValueParameters.get(i).getType());
096                int parametersCompareTo = p1.compareTo(p2);
097                if (parametersCompareTo != 0) {
098                    return parametersCompareTo;
099                }
100            }
101    
102            int valueParametersNumberCompareTo = c1ValueParameters.size() - c2ValueParameters.size();
103            if (valueParametersNumberCompareTo != 0) {
104                return valueParametersNumberCompareTo;
105            }
106    
107            List<TypeParameterDescriptor> c1TypeParameters = c1.getTypeParameters();
108            List<TypeParameterDescriptor> c2TypeParameters = c2.getTypeParameters();
109            for (int i = 0; i < Math.min(c1TypeParameters.size(), c2TypeParameters.size()); i++) {
110                String p1 = RENDERER.renderType(c1TypeParameters.get(i).getUpperBoundsAsType());
111                String p2 = RENDERER.renderType(c2TypeParameters.get(i).getUpperBoundsAsType());
112                int parametersCompareTo = p1.compareTo(p2);
113                if (parametersCompareTo != 0) {
114                    return parametersCompareTo;
115                }
116            }
117    
118            int typeParametersCompareTo = c1TypeParameters.size() - c2TypeParameters.size();
119            if (typeParametersCompareTo != 0) {
120                return typeParametersCompareTo;
121            }
122    
123            if (c1 instanceof CallableMemberDescriptor && c2 instanceof CallableMemberDescriptor) {
124                CallableMemberDescriptor.Kind c1Kind = ((CallableMemberDescriptor) c1).getKind();
125                CallableMemberDescriptor.Kind c2Kind = ((CallableMemberDescriptor) c2).getKind();
126                int kindsCompareTo = c1Kind.ordinal() - c2Kind.ordinal();
127                if (kindsCompareTo != 0) {
128                    return kindsCompareTo;
129                }
130            }
131    
132            return RENDERER.render(o1).compareTo(RENDERER.render(o2));
133        }
134    }