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