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.jet.lang.PlatformToKotlinClassMap;
022 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
023 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
024 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
025 import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
026 import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage;
027 import org.jetbrains.jet.lang.resolve.name.FqName;
028 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
029 import org.jetbrains.jet.lang.types.JetType;
030 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
031 import org.jetbrains.jet.lang.types.lang.PrimitiveType;
032
033 import java.util.*;
034
035 public class JavaToKotlinClassMap extends JavaToKotlinClassMapBuilder implements PlatformToKotlinClassMap {
036 private static JavaToKotlinClassMap instance = null;
037
038 @NotNull
039 public static JavaToKotlinClassMap getInstance() {
040 if (instance == null) {
041 instance = new JavaToKotlinClassMap();
042 }
043 return instance;
044 }
045
046 private final Map<FqName, ClassDescriptor> classDescriptorMap = new HashMap<FqName, ClassDescriptor>();
047 private final Map<FqName, ClassDescriptor> classDescriptorMapForCovariantPositions = new HashMap<FqName, ClassDescriptor>();
048 private final Map<String, JetType> primitiveTypesMap = new HashMap<String, JetType>();
049 private final Map<FqName, Collection<ClassDescriptor>> packagesWithMappedClasses = new HashMap<FqName, Collection<ClassDescriptor>>();
050
051 private JavaToKotlinClassMap() {
052 init();
053 initPrimitives();
054 }
055
056 private void initPrimitives() {
057 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
058 for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
059 PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
060 String name = jvmPrimitiveType.getName();
061 FqName wrapperFqName = jvmPrimitiveType.getWrapperFqName();
062
063 register(wrapperFqName, builtIns.getPrimitiveClassDescriptor(primitiveType));
064 primitiveTypesMap.put(name, builtIns.getPrimitiveJetType(primitiveType));
065 primitiveTypesMap.put("[" + name, builtIns.getPrimitiveArrayJetType(primitiveType));
066 primitiveTypesMap.put(wrapperFqName.asString(), builtIns.getNullablePrimitiveJetType(primitiveType));
067 }
068 primitiveTypesMap.put("void", KotlinBuiltIns.getInstance().getUnitType());
069 }
070
071 @Nullable
072 public JetType mapPrimitiveKotlinClass(@NotNull String name) {
073 return primitiveTypesMap.get(name);
074 }
075
076 @Nullable
077 public ClassDescriptor mapKotlinClass(@NotNull FqName fqName, @NotNull TypeUsage typeUsage) {
078 if (typeUsage == TypeUsage.MEMBER_SIGNATURE_COVARIANT
079 || typeUsage == TypeUsage.SUPERTYPE) {
080 ClassDescriptor descriptor = classDescriptorMapForCovariantPositions.get(fqName);
081 if (descriptor != null) {
082 return descriptor;
083 }
084 }
085 return classDescriptorMap.get(fqName);
086 }
087
088 @NotNull
089 private static FqName fqNameByClass(@NotNull Class<?> clazz) {
090 return new FqName(clazz.getCanonicalName());
091 }
092
093 @Override
094 protected void register(@NotNull Class<?> javaClass, @NotNull ClassDescriptor kotlinDescriptor, @NotNull Direction direction) {
095 if (direction == Direction.BOTH || direction == Direction.JAVA_TO_KOTLIN) {
096 register(fqNameByClass(javaClass), kotlinDescriptor);
097 }
098 }
099
100 @Override
101 protected void register(
102 @NotNull Class<?> javaClass,
103 @NotNull ClassDescriptor kotlinDescriptor,
104 @NotNull ClassDescriptor kotlinMutableDescriptor,
105 @NotNull Direction direction
106 ) {
107 if (direction == Direction.BOTH || direction == Direction.JAVA_TO_KOTLIN) {
108 FqName javaClassName = fqNameByClass(javaClass);
109 register(javaClassName, kotlinDescriptor);
110 registerCovariant(javaClassName, kotlinMutableDescriptor);
111 }
112 }
113
114 private void register(@NotNull FqName javaClassName, @NotNull ClassDescriptor kotlinDescriptor) {
115 classDescriptorMap.put(javaClassName, kotlinDescriptor);
116 registerClassInPackage(javaClassName.parent(), kotlinDescriptor);
117 }
118
119 private void registerCovariant(@NotNull FqName javaClassName, @NotNull ClassDescriptor kotlinDescriptor) {
120 classDescriptorMapForCovariantPositions.put(javaClassName, kotlinDescriptor);
121 registerClassInPackage(javaClassName.parent(), kotlinDescriptor);
122 }
123
124 private void registerClassInPackage(@NotNull FqName packageFqName, @NotNull ClassDescriptor kotlinDescriptor) {
125 Collection<ClassDescriptor> classesInPackage = packagesWithMappedClasses.get(packageFqName);
126 if (classesInPackage == null) {
127 classesInPackage = new HashSet<ClassDescriptor>();
128 packagesWithMappedClasses.put(packageFqName, classesInPackage);
129 }
130 classesInPackage.add(kotlinDescriptor);
131 }
132
133 @NotNull
134 public Collection<ClassDescriptor> mapPlatformClass(@NotNull FqName fqName) {
135 ClassDescriptor kotlinAnalog = classDescriptorMap.get(fqName);
136 ClassDescriptor kotlinCovariantAnalog = classDescriptorMapForCovariantPositions.get(fqName);
137 List<ClassDescriptor> descriptors = new ArrayList<ClassDescriptor>(2);
138 if (kotlinAnalog != null) {
139 descriptors.add(kotlinAnalog);
140 }
141 if (kotlinCovariantAnalog != null) {
142 descriptors.add(kotlinCovariantAnalog);
143 }
144 return descriptors;
145 }
146
147 @Override
148 @NotNull
149 public Collection<ClassDescriptor> mapPlatformClass(@NotNull ClassDescriptor classDescriptor) {
150 FqNameUnsafe className = DescriptorUtils.getFqName(classDescriptor);
151 if (!className.isSafe()) {
152 return Collections.emptyList();
153 }
154 return mapPlatformClass(className.toSafe());
155 }
156
157 @Override
158 @NotNull
159 public Collection<ClassDescriptor> mapPlatformClassesInside(@NotNull DeclarationDescriptor containingDeclaration) {
160 FqNameUnsafe fqName = DescriptorUtils.getFqName(containingDeclaration);
161 if (!fqName.isSafe()) {
162 return Collections.emptyList();
163 }
164 Collection<ClassDescriptor> result = packagesWithMappedClasses.get(fqName.toSafe());
165 return result == null ? Collections.<ClassDescriptor>emptySet() : Collections.unmodifiableCollection(result);
166 }
167 }