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