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.java.kotlinSignature;
018    
019    import com.google.common.collect.ImmutableCollection;
020    import com.google.common.collect.ImmutableMap;
021    import com.google.common.collect.ImmutableMultimap;
022    import com.google.common.collect.Lists;
023    import com.intellij.openapi.util.Pair;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
026    import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
027    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028    import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
029    import org.jetbrains.jet.lang.resolve.java.structure.JavaSignatureFormatter;
030    import org.jetbrains.jet.lang.resolve.name.FqName;
031    import org.jetbrains.jet.lang.resolve.name.Name;
032    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033    import org.jetbrains.jet.renderer.DescriptorRenderer;
034    
035    import java.util.*;
036    
037    public class JavaToKotlinMethodMap {
038        public static final JavaToKotlinMethodMap INSTANCE = new JavaToKotlinMethodMap();
039    
040        private final JavaToKotlinMethodMapGenerated mapContainer = new JavaToKotlinMethodMapGenerated();
041    
042        private JavaToKotlinMethodMap() {
043        }
044    
045        @NotNull
046        public List<FunctionDescriptor> getFunctions(
047                @NotNull JavaMethod javaMethod,
048                @NotNull FqName classFqName,
049                @NotNull ClassDescriptor containingClass
050        ) {
051            ImmutableCollection<ClassData> classDatas = mapContainer.map.get(classFqName.asString());
052    
053            List<FunctionDescriptor> result = Lists.newArrayList();
054    
055            Set<ClassDescriptor> allSuperClasses = new HashSet<ClassDescriptor>(DescriptorUtils.getSuperclassDescriptors(containingClass));
056    
057            String serializedMethod = JavaSignatureFormatter.getInstance().formatMethod(javaMethod);
058            for (ClassData classData : classDatas) {
059                String expectedSerializedFunction = classData.method2Function.get(serializedMethod);
060                if (expectedSerializedFunction == null) continue;
061    
062                ClassDescriptor kotlinClass = classData.kotlinClass;
063                if (!allSuperClasses.contains(kotlinClass)) continue;
064    
065                Collection<FunctionDescriptor> functions = kotlinClass.getDefaultType().getMemberScope().getFunctions(javaMethod.getName());
066    
067                for (FunctionDescriptor function : functions) {
068                    if (expectedSerializedFunction.equals(serializeFunction(function))) {
069                        result.add(function);
070                    }
071                }
072            }
073    
074            return result;
075        }
076    
077        @NotNull
078        public static String serializeFunction(@NotNull FunctionDescriptor fun) {
079            return DescriptorRenderer.COMPACT.render(fun);
080        }
081    
082        // used in generated code
083        static Pair<String, String> pair(String a, String b) {
084            return Pair.create(a, b);
085        }
086    
087        // used in generated code
088        static void put(
089                ImmutableMultimap.Builder<String, ClassData> builder,
090                String javaFqName,
091                String kotlinQualifiedName,
092                Pair<String, String>... methods2Functions
093        ) {
094            ImmutableMap<String, String> methods2FunctionsMap = pairs2Map(methods2Functions);
095    
096            ClassDescriptor kotlinClass;
097            if (kotlinQualifiedName.contains(".")) { // Map.Entry and MutableMap.MutableEntry
098                String[] kotlinNames = kotlinQualifiedName.split("\\.");
099                assert kotlinNames.length == 2 : "unexpected qualified name " + kotlinQualifiedName;
100    
101                ClassDescriptor outerClass = KotlinBuiltIns.getInstance().getBuiltInClassByName(Name.identifier(kotlinNames[0]));
102                kotlinClass = DescriptorUtils.getInnerClassByName(outerClass, kotlinNames[1]);
103                assert kotlinClass != null : "Class not found: " + kotlinQualifiedName;
104            }
105            else {
106                kotlinClass = KotlinBuiltIns.getInstance().getBuiltInClassByName(Name.identifier(kotlinQualifiedName));
107            }
108    
109            builder.put(javaFqName, new ClassData(kotlinClass, methods2FunctionsMap));
110        }
111    
112        private static ImmutableMap<String, String> pairs2Map(Pair<String, String>[] pairs) {
113            ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
114            for (Pair<String, String> pair : pairs) {
115                builder.put(pair.first, pair.second);
116            }
117            return builder.build();
118        }
119    
120        static class ClassData {
121            @NotNull
122            public final ClassDescriptor kotlinClass;
123            @NotNull
124            public Map<String, String> method2Function;
125    
126            public ClassData(@NotNull ClassDescriptor kotlinClass, @NotNull Map<String, String> method2Function) {
127                this.kotlinClass = kotlinClass;
128                this.method2Function = method2Function;
129            }
130        }
131    }