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.mapping;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.asm4.Type;
022    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
023    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
024    import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
025    import org.jetbrains.jet.lang.resolve.java.JvmClassName;
026    import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
027    import org.jetbrains.jet.lang.resolve.name.FqName;
028    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
029    import org.jetbrains.jet.lang.types.lang.PrimitiveType;
030    
031    import java.util.HashMap;
032    import java.util.Map;
033    
034    import static org.jetbrains.jet.lang.resolve.java.mapping.PrimitiveTypesUtil.asmTypeForPrimitive;
035    
036    public class KotlinToJavaTypesMap extends JavaToKotlinClassMapBuilder {
037        private static KotlinToJavaTypesMap instance = null;
038    
039        @NotNull
040        public static KotlinToJavaTypesMap getInstance() {
041            if (instance == null) {
042                instance = new KotlinToJavaTypesMap();
043            }
044            return instance;
045        }
046    
047        private final Map<FqName, Type> asmTypes = new HashMap<FqName, Type>();
048        private final Map<FqName, Type> asmNullableTypes = new HashMap<FqName, Type>();
049        private final Map<FqName, FqName> kotlinToJavaFqName = new HashMap<FqName, FqName>();
050    
051        private KotlinToJavaTypesMap() {
052            init();
053            initPrimitives();
054        }
055    
056        private void initPrimitives() {
057            FqName builtInsFqName = KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME;
058            for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
059                PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
060                Type asmType = asmTypeForPrimitive(jvmPrimitiveType);
061                FqName fqName = builtInsFqName.child(primitiveType.getTypeName());
062    
063                register(fqName, asmType);
064    
065                FqName wrapperFqName = jvmPrimitiveType.getWrapperFqName();
066                registerNullable(fqName, Type.getObjectType(JvmClassName.byFqNameWithoutInnerClasses(wrapperFqName).getInternalName()));
067                registerFqName(fqName, wrapperFqName);
068    
069                register(builtInsFqName.child(primitiveType.getArrayTypeName()), Type.getType("[" + asmType.getDescriptor()));
070            }
071        }
072    
073        @Nullable
074        public Type getJavaAnalog(@NotNull FqName fqName, boolean isNullable) {
075            if (isNullable) {
076                Type nullableType = asmNullableTypes.get(fqName);
077                if (nullableType != null) {
078                    return nullableType;
079                }
080            }
081            return asmTypes.get(fqName);
082        }
083    
084        /**
085         * E.g.
086         * kotlin.Throwable -> java.lang.Throwable
087         * kotlin.deprecated -> java.lang.annotation.Deprecated
088         * kotlin.Int -> java.lang.Integer
089         * kotlin.IntArray -> null
090         */
091        @Nullable
092        public FqName getKotlinToJavaFqName(@NotNull FqName fqName) {
093            return kotlinToJavaFqName.get(fqName);
094        }
095    
096        @Override
097        protected void register(@NotNull Class<?> javaClass, @NotNull ClassDescriptor kotlinDescriptor, @NotNull Direction direction) {
098            if (direction == Direction.BOTH || direction == Direction.KOTLIN_TO_JAVA) {
099                FqName fqName = DescriptorUtils.getFqNameSafe(kotlinDescriptor);
100                register(fqName, AsmTypeConstants.getType(javaClass));
101                registerFqName(fqName, new FqName(javaClass.getCanonicalName()));
102            }
103        }
104    
105        @Override
106        protected void register(
107                @NotNull Class<?> javaClass,
108                @NotNull ClassDescriptor kotlinDescriptor,
109                @NotNull ClassDescriptor kotlinMutableDescriptor,
110                @NotNull Direction direction
111        ) {
112            if (direction == Direction.BOTH || direction == Direction.KOTLIN_TO_JAVA) {
113                register(javaClass, kotlinDescriptor);
114                register(javaClass, kotlinMutableDescriptor);
115            }
116        }
117    
118        private void register(@NotNull FqName fqName, @NotNull Type type) {
119            asmTypes.put(fqName, type);
120        }
121    
122        private void registerNullable(@NotNull FqName fqName, @NotNull Type nullableType) {
123            asmNullableTypes.put(fqName, nullableType);
124        }
125    
126        private void registerFqName(@NotNull FqName kotlinFqName, @NotNull FqName javaFqName) {
127            kotlinToJavaFqName.put(kotlinFqName, javaFqName);
128        }
129    }