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.descriptors.ValueParameterDescriptor;
025 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl;
027 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028 import org.jetbrains.jet.lang.resolve.constants.StringValue;
029 import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
030 import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils;
031 import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationResolver;
032 import org.jetbrains.jet.lang.resolve.java.resolver.TypeUsage;
033 import org.jetbrains.jet.lang.resolve.name.FqName;
034 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
035 import org.jetbrains.jet.lang.types.JetType;
036 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
037 import org.jetbrains.jet.lang.types.lang.PrimitiveType;
038
039 import java.util.*;
040
041 import static org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils.fqNameByClass;
042
043 public class JavaToKotlinClassMap extends JavaToKotlinClassMapBuilder implements PlatformToKotlinClassMap {
044 private static final FqName JAVA_LANG_DEPRECATED = new FqName("java.lang.Deprecated");
045
046 private static JavaToKotlinClassMap instance = null;
047
048 @NotNull
049 public static JavaToKotlinClassMap getInstance() {
050 if (instance == null) {
051 instance = new JavaToKotlinClassMap();
052 }
053 return instance;
054 }
055
056 private final Map<FqName, ClassDescriptor> classDescriptorMap = new HashMap<FqName, ClassDescriptor>();
057 private final Map<FqName, ClassDescriptor> classDescriptorMapForCovariantPositions = new HashMap<FqName, ClassDescriptor>();
058 private final Map<String, JetType> primitiveTypesMap = new HashMap<String, JetType>();
059 private final Map<FqName, Collection<ClassDescriptor>> packagesWithMappedClasses = new HashMap<FqName, Collection<ClassDescriptor>>();
060
061 private JavaToKotlinClassMap() {
062 init();
063 initPrimitives();
064 }
065
066 private void initPrimitives() {
067 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
068 for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
069 PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
070 String name = jvmPrimitiveType.getName();
071 FqName wrapperFqName = jvmPrimitiveType.getWrapperFqName();
072
073 register(wrapperFqName, builtIns.getPrimitiveClassDescriptor(primitiveType));
074 primitiveTypesMap.put(name, builtIns.getPrimitiveJetType(primitiveType));
075 primitiveTypesMap.put("[" + name, builtIns.getPrimitiveArrayJetType(primitiveType));
076 primitiveTypesMap.put(wrapperFqName.asString(), builtIns.getNullablePrimitiveJetType(primitiveType));
077 }
078 primitiveTypesMap.put("void", KotlinBuiltIns.getInstance().getUnitType());
079 }
080
081 @Nullable
082 public JetType mapPrimitiveKotlinClass(@NotNull String name) {
083 return primitiveTypesMap.get(name);
084 }
085
086 @Nullable
087 public ClassDescriptor mapKotlinClass(@NotNull FqName fqName, @NotNull TypeUsage typeUsage) {
088 if (typeUsage == TypeUsage.MEMBER_SIGNATURE_COVARIANT
089 || typeUsage == TypeUsage.SUPERTYPE) {
090 ClassDescriptor descriptor = classDescriptorMapForCovariantPositions.get(fqName);
091 if (descriptor != null) {
092 return descriptor;
093 }
094 }
095 return classDescriptorMap.get(fqName);
096 }
097
098 @Nullable
099 public AnnotationDescriptor mapToAnnotationClass(@NotNull FqName fqName) {
100 ClassDescriptor classDescriptor = classDescriptorMap.get(fqName);
101 if (classDescriptor != null && fqName.equals(JAVA_LANG_DEPRECATED)) {
102 return getAnnotationDescriptorForJavaLangDeprecated(classDescriptor);
103 }
104 return null;
105 }
106
107 @NotNull
108 private static AnnotationDescriptor getAnnotationDescriptorForJavaLangDeprecated(@NotNull ClassDescriptor annotationClass) {
109 AnnotationDescriptorImpl annotation = new AnnotationDescriptorImpl();
110 annotation.setAnnotationType(annotationClass.getDefaultType());
111 ValueParameterDescriptor value = DescriptorResolverUtils.getAnnotationParameterByName(
112 JavaAnnotationResolver.DEFAULT_ANNOTATION_MEMBER_NAME, annotationClass);
113 assert value != null : "jet.deprecated must have one parameter called value";
114 annotation.setValueArgument(value, new StringValue("Deprecated in Java"));
115 return annotation;
116 }
117
118 @Override
119 protected void register(@NotNull Class<?> javaClass, @NotNull ClassDescriptor kotlinDescriptor, @NotNull Direction direction) {
120 if (direction == Direction.BOTH || direction == Direction.JAVA_TO_KOTLIN) {
121 register(fqNameByClass(javaClass), kotlinDescriptor);
122 }
123 }
124
125 @Override
126 protected void register(
127 @NotNull Class<?> javaClass,
128 @NotNull ClassDescriptor kotlinDescriptor,
129 @NotNull ClassDescriptor kotlinMutableDescriptor,
130 @NotNull Direction direction
131 ) {
132 if (direction == Direction.BOTH || direction == Direction.JAVA_TO_KOTLIN) {
133 FqName javaClassName = fqNameByClass(javaClass);
134 register(javaClassName, kotlinDescriptor);
135 registerCovariant(javaClassName, kotlinMutableDescriptor);
136 }
137 }
138
139 private void register(@NotNull FqName javaClassName, @NotNull ClassDescriptor kotlinDescriptor) {
140 classDescriptorMap.put(javaClassName, kotlinDescriptor);
141 registerClassInPackage(javaClassName.parent(), kotlinDescriptor);
142 }
143
144 private void registerCovariant(@NotNull FqName javaClassName, @NotNull ClassDescriptor kotlinDescriptor) {
145 classDescriptorMapForCovariantPositions.put(javaClassName, kotlinDescriptor);
146 registerClassInPackage(javaClassName.parent(), kotlinDescriptor);
147 }
148
149 private void registerClassInPackage(@NotNull FqName packageFqName, @NotNull ClassDescriptor kotlinDescriptor) {
150 Collection<ClassDescriptor> classesInPackage = packagesWithMappedClasses.get(packageFqName);
151 if (classesInPackage == null) {
152 classesInPackage = new HashSet<ClassDescriptor>();
153 packagesWithMappedClasses.put(packageFqName, classesInPackage);
154 }
155 classesInPackage.add(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 Collection<ClassDescriptor> result = packagesWithMappedClasses.get(fqName.toSafe());
190 return result == null ? Collections.<ClassDescriptor>emptySet() : Collections.unmodifiableCollection(result);
191 }
192 }