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 017package org.jetbrains.jet.lang.resolve.java; 018 019import com.google.common.collect.*; 020import com.intellij.psi.CommonClassNames; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.PlatformToKotlinClassMap; 024import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 025import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 026import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 027import org.jetbrains.jet.lang.resolve.DescriptorUtils; 028import org.jetbrains.jet.lang.resolve.name.FqName; 029import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; 030import org.jetbrains.jet.lang.types.JetType; 031import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 032import org.jetbrains.jet.lang.types.lang.PrimitiveType; 033 034import java.util.*; 035 036public 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}