001    /*
002     * Copyright 2010-2014 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.backend.common;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
022    import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
023    import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
024    import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
025    import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
026    import org.jetbrains.jet.lang.resolve.name.Name;
027    import org.jetbrains.jet.lang.types.JetType;
028    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
029    
030    import java.util.Arrays;
031    import java.util.Collection;
032    import java.util.List;
033    
034    /**
035     * Backend-independent utility class.
036     */
037    public class CodegenUtil {
038    
039        private CodegenUtil() {
040        }
041    
042        // TODO: consider putting predefined method signatures here too.
043        public static final String EQUALS_METHOD_NAME = "equals";
044        public static final String TO_STRING_METHOD_NAME = "toString";
045        public static final String HASH_CODE_METHOD_NAME = "hashCode";
046    
047        @Nullable
048        public static FunctionDescriptor getDeclaredFunctionByRawSignature(
049                @NotNull ClassDescriptor owner,
050                @NotNull Name name,
051                @NotNull ClassifierDescriptor returnedClassifier,
052                @NotNull ClassifierDescriptor... valueParameterClassifiers
053        ) {
054            Collection<FunctionDescriptor> functions = owner.getDefaultType().getMemberScope().getFunctions(name);
055            for (FunctionDescriptor function : functions) {
056                if (!CallResolverUtil.isOrOverridesSynthesized(function)
057                    && function.getTypeParameters().isEmpty()
058                    && valueParameterClassesMatch(function.getValueParameters(), Arrays.asList(valueParameterClassifiers))
059                    && rawTypeMatches(function.getReturnType(), returnedClassifier)) {
060                    return function;
061                }
062            }
063            return null;
064        }
065    
066        public static FunctionDescriptor getAnyEqualsMethod() {
067            ClassDescriptor anyClass = KotlinBuiltIns.getInstance().getAny();
068            FunctionDescriptor function =
069                    getDeclaredFunctionByRawSignature(anyClass, Name.identifier(EQUALS_METHOD_NAME),
070                                                      KotlinBuiltIns.getInstance().getBoolean(),
071                                                      anyClass);
072            assert function != null;
073            return function;
074        }
075    
076        public static FunctionDescriptor getAnyToStringMethod() {
077            ClassDescriptor anyClass = KotlinBuiltIns.getInstance().getAny();
078            FunctionDescriptor function =
079                    getDeclaredFunctionByRawSignature(anyClass, Name.identifier(TO_STRING_METHOD_NAME),
080                                                      KotlinBuiltIns.getInstance().getString());
081            assert function != null;
082            return function;
083        }
084    
085        public static FunctionDescriptor getAnyHashCodeMethod() {
086            ClassDescriptor anyClass = KotlinBuiltIns.getInstance().getAny();
087            FunctionDescriptor function =
088                    getDeclaredFunctionByRawSignature(anyClass, Name.identifier(HASH_CODE_METHOD_NAME),
089                                                      KotlinBuiltIns.getInstance().getInt());
090            assert function != null;
091            return function;
092        }
093    
094        private static boolean valueParameterClassesMatch(
095                @NotNull List<ValueParameterDescriptor> parameters,
096                @NotNull List<ClassifierDescriptor> classifiers
097        ) {
098            if (parameters.size() != classifiers.size()) return false;
099            for (int i = 0; i < parameters.size(); i++) {
100                ValueParameterDescriptor parameterDescriptor = parameters.get(i);
101                ClassifierDescriptor classDescriptor = classifiers.get(i);
102                if (!rawTypeMatches(parameterDescriptor.getType(), classDescriptor)) {
103                    return false;
104                }
105            }
106            return true;
107        }
108    
109        private static boolean rawTypeMatches(JetType type, ClassifierDescriptor classifier) {
110            return type.getConstructor().getDeclarationDescriptor().getOriginal() == classifier.getOriginal();
111        }
112    }