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