001 /*
002 * Copyright 2010-2015 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.kotlin.platform;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
022 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
023 import org.jetbrains.kotlin.builtins.PrimitiveType;
024 import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor;
025 import org.jetbrains.kotlin.descriptors.ClassDescriptor;
026 import org.jetbrains.kotlin.name.ClassId;
027 import org.jetbrains.kotlin.name.FqName;
028 import org.jetbrains.kotlin.name.FqNameUnsafe;
029 import org.jetbrains.kotlin.name.Name;
030 import org.jetbrains.kotlin.resolve.DescriptorUtils;
031 import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
032
033 import java.lang.annotation.Annotation;
034 import java.util.*;
035
036 public class JavaToKotlinClassMap implements PlatformToKotlinClassMap {
037 public static final JavaToKotlinClassMap INSTANCE = new JavaToKotlinClassMap();
038
039 private final Map<FqName, ClassDescriptor> javaToKotlin = new HashMap<FqName, ClassDescriptor>();
040 private final Map<FqNameUnsafe, ClassId> kotlinToJava = new HashMap<FqNameUnsafe, ClassId>();
041
042 private final Map<ClassDescriptor, ClassDescriptor> mutableToReadOnly = new HashMap<ClassDescriptor, ClassDescriptor>();
043 private final Map<ClassDescriptor, ClassDescriptor> readOnlyToMutable = new HashMap<ClassDescriptor, ClassDescriptor>();
044
045 private JavaToKotlinClassMap() {
046 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
047
048 add(Object.class, builtIns.getAny());
049 add(String.class, builtIns.getString());
050 add(CharSequence.class, builtIns.getCharSequence());
051 add(Throwable.class, builtIns.getThrowable());
052 add(Cloneable.class, builtIns.getCloneable());
053 add(Number.class, builtIns.getNumber());
054 add(Comparable.class, builtIns.getComparable());
055 add(Enum.class, builtIns.getEnum());
056 add(Annotation.class, builtIns.getAnnotation());
057
058 add(Iterable.class, builtIns.getIterable(), builtIns.getMutableIterable());
059 add(Iterator.class, builtIns.getIterator(), builtIns.getMutableIterator());
060 add(Collection.class, builtIns.getCollection(), builtIns.getMutableCollection());
061 add(List.class, builtIns.getList(), builtIns.getMutableList());
062 add(Set.class, builtIns.getSet(), builtIns.getMutableSet());
063 add(Map.class, builtIns.getMap(), builtIns.getMutableMap());
064 add(Map.Entry.class, builtIns.getMapEntry(), builtIns.getMutableMapEntry());
065 add(ListIterator.class, builtIns.getListIterator(), builtIns.getMutableListIterator());
066
067 for (JvmPrimitiveType jvmType : JvmPrimitiveType.values()) {
068 add(ClassId.topLevel(jvmType.getWrapperFqName()), builtIns.getPrimitiveClassDescriptor(jvmType.getPrimitiveType()));
069 }
070
071 for (ClassDescriptor descriptor : CompanionObjectMapping.allClassesWithIntrinsicCompanions()) {
072 ClassDescriptor companion = descriptor.getCompanionObjectDescriptor();
073 assert companion != null : "No companion object found for " + descriptor;
074 add(ClassId.topLevel(new FqName("kotlin.jvm.internal." + descriptor.getName().asString() + "CompanionObject")), companion);
075 }
076
077 // TODO: support also functions with >= 23 parameters
078 for (int i = 0; i < 23; i++) {
079 add(ClassId.topLevel(new FqName("kotlin.jvm.functions.Function" + i)), builtIns.getFunction(i));
080
081 for (FunctionClassDescriptor.Kind kind : FunctionClassDescriptor.Kinds.KFunctions) {
082 String kFun = kind.getPackageFqName() + "." + kind.getClassNamePrefix();
083 addKotlinToJava(new FqNameUnsafe(kFun + i), ClassId.topLevel(new FqName(kFun)));
084 }
085 }
086
087 addJavaToKotlin(classId(Deprecated.class), builtIns.getDeprecatedAnnotation());
088
089 addKotlinToJava(builtIns.getNothing(), classId(Void.class));
090 }
091
092 /**
093 * E.g.
094 * java.lang.String -> kotlin.String
095 * java.lang.Deprecated -> kotlin.deprecated
096 * java.lang.Integer -> kotlin.Int
097 * kotlin.jvm.internal.IntCompanionObject -> kotlin.Int.Companion
098 * java.util.List -> kotlin.List
099 * java.util.Map.Entry -> kotlin.Map.Entry
100 * java.lang.Void -> null
101 * kotlin.jvm.functions.Function3 -> kotlin.Function3
102 */
103 @Nullable
104 public ClassDescriptor mapJavaToKotlin(@NotNull FqName fqName) {
105 return javaToKotlin.get(fqName);
106 }
107
108 /**
109 * E.g.
110 * kotlin.Throwable -> java.lang.Throwable
111 * kotlin.Int -> java.lang.Integer
112 * kotlin.Int.Companion -> kotlin.jvm.internal.IntCompanionObject
113 * kotlin.Nothing -> java.lang.Void
114 * kotlin.IntArray -> null
115 * kotlin.Function3 -> kotlin.jvm.functions.Function3
116 * kotlin.reflect.KFunction3 -> kotlin.reflect.KFunction
117 */
118 @Nullable
119 public ClassId mapKotlinToJava(@NotNull FqNameUnsafe kotlinFqName) {
120 return kotlinToJava.get(kotlinFqName);
121 }
122
123 private void add(
124 @NotNull Class<?> javaClass,
125 @NotNull ClassDescriptor kotlinDescriptor,
126 @NotNull ClassDescriptor kotlinMutableDescriptor
127 ) {
128 ClassId javaClassId = classId(javaClass);
129
130 add(javaClassId, kotlinDescriptor);
131 addKotlinToJava(kotlinMutableDescriptor, javaClassId);
132
133 mutableToReadOnly.put(kotlinMutableDescriptor, kotlinDescriptor);
134 readOnlyToMutable.put(kotlinDescriptor, kotlinMutableDescriptor);
135 }
136
137 private void add(@NotNull ClassId javaClassId, @NotNull ClassDescriptor kotlinDescriptor) {
138 addJavaToKotlin(javaClassId, kotlinDescriptor);
139 addKotlinToJava(kotlinDescriptor, javaClassId);
140 }
141
142 private void add(@NotNull Class<?> javaClass, @NotNull ClassDescriptor kotlinDescriptor) {
143 add(classId(javaClass), kotlinDescriptor);
144 }
145
146 private void addJavaToKotlin(@NotNull ClassId javaClassId, @NotNull ClassDescriptor kotlinDescriptor) {
147 javaToKotlin.put(javaClassId.asSingleFqName(), kotlinDescriptor);
148 }
149
150 private void addKotlinToJava(@NotNull ClassDescriptor kotlinDescriptor, @NotNull ClassId javaClassId) {
151 addKotlinToJava(DescriptorUtils.getFqName(kotlinDescriptor), javaClassId);
152 }
153
154 private void addKotlinToJava(@NotNull FqNameUnsafe kotlinFqName, @NotNull ClassId javaClassId) {
155 kotlinToJava.put(kotlinFqName, javaClassId);
156 }
157
158 @NotNull
159 private static ClassId classId(@NotNull Class<?> clazz) {
160 assert !clazz.isPrimitive() && !clazz.isArray() : "Invalid class: " + clazz;
161 Class<?> outer = clazz.getDeclaringClass();
162 return outer == null
163 ? ClassId.topLevel(new FqName(clazz.getCanonicalName()))
164 : classId(outer).createNestedClassId(Name.identifier(clazz.getSimpleName()));
165 }
166
167 @NotNull
168 public Collection<ClassDescriptor> mapPlatformClass(@NotNull FqName fqName) {
169 ClassDescriptor kotlinAnalog = mapJavaToKotlin(fqName);
170 if (kotlinAnalog == null) return Collections.emptySet();
171
172 ClassDescriptor kotlinMutableAnalog = readOnlyToMutable.get(kotlinAnalog);
173 if (kotlinMutableAnalog == null) return Collections.singleton(kotlinAnalog);
174
175 return Arrays.asList(kotlinAnalog, kotlinMutableAnalog);
176 }
177
178 @Override
179 @NotNull
180 public Collection<ClassDescriptor> mapPlatformClass(@NotNull ClassDescriptor classDescriptor) {
181 FqNameUnsafe className = DescriptorUtils.getFqName(classDescriptor);
182 return className.isSafe() ? mapPlatformClass(className.toSafe()) : Collections.<ClassDescriptor>emptySet();
183 }
184
185 public boolean isMutableCollection(@NotNull ClassDescriptor mutable) {
186 return mutableToReadOnly.containsKey(mutable);
187 }
188
189 public boolean isReadOnlyCollection(@NotNull ClassDescriptor readOnly) {
190 return readOnlyToMutable.containsKey(readOnly);
191 }
192
193 @NotNull
194 public ClassDescriptor convertMutableToReadOnly(@NotNull ClassDescriptor mutable) {
195 ClassDescriptor readOnly = mutableToReadOnly.get(mutable);
196 if (readOnly == null) {
197 throw new IllegalArgumentException("Given class " + mutable + " is not a mutable collection");
198 }
199 return readOnly;
200 }
201
202 @NotNull
203 public ClassDescriptor convertReadOnlyToMutable(@NotNull ClassDescriptor readOnly) {
204 ClassDescriptor mutable = readOnlyToMutable.get(readOnly);
205 if (mutable == null) {
206 throw new IllegalArgumentException("Given class " + readOnly + " is not a read-only collection");
207 }
208 return mutable;
209 }
210
211 // TODO: get rid of this method, it's unclear what it does
212 @NotNull
213 public List<ClassDescriptor> allKotlinClasses() {
214 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
215
216 List<ClassDescriptor> result = new ArrayList<ClassDescriptor>();
217 result.addAll(javaToKotlin.values());
218 result.addAll(readOnlyToMutable.values());
219
220 for (PrimitiveType type : PrimitiveType.values()) {
221 result.add(builtIns.getPrimitiveArrayClassDescriptor(type));
222 }
223
224 result.add(builtIns.getUnit());
225 result.add(builtIns.getNothing());
226
227 return result;
228 }
229 }