Add JavaToKotlinClassMap#isJavaPlatformClass

Use it instead of mapPlatformClass where we only need to check emptiness
because mapPlatformClass requires built-ins and it's not always easy to come up
with the correct instance of built-ins.

In KotlinEvaluationBuilder, use the nullable function
findClassAcrossModuleDependencies instead of mapPlatformClass which uses the
throwing resolveClassByFqName. This is necessary because DefaultBuiltIns, which
are used there, are not always able to find classes mapped by a _Java_ to
Kotlin class map. (The correct solution would be not to use DefaultBuiltIns at
all, instead obtaining the correct instance of built-ins, which are almost
certainly going to be JvmBuiltIns, from the project configuration.)
This commit is contained in:
Alexander Udalov
2016-10-14 11:37:58 +03:00
parent 2f81d48f5e
commit 0f4b10d37d
6 changed files with 21 additions and 15 deletions
@@ -154,11 +154,11 @@ class JavaTypeResolver(
attr.flexibility == FLEXIBLE_LOWER_BOUND -> MEMBER_SIGNATURE_COVARIANT attr.flexibility == FLEXIBLE_LOWER_BOUND -> MEMBER_SIGNATURE_COVARIANT
attr.flexibility == FLEXIBLE_UPPER_BOUND -> MEMBER_SIGNATURE_CONTRAVARIANT attr.flexibility == FLEXIBLE_UPPER_BOUND -> MEMBER_SIGNATURE_CONTRAVARIANT
// This case has to be checked before isMarkedReadOnly/isMarkedMutable, because those two are slow // This case has to be checked before isMarkedReadOnly/isMarkedMutable, because those two are slow
// not mapped, we don't care about being marked mutable/read-only // not mapped, we don't care about being marked mutable/read-only
javaToKotlin.mapPlatformClass(fqName, c.module.builtIns).isEmpty() -> attr.howThisTypeIsUsed !javaToKotlin.isJavaPlatformClass(fqName) -> attr.howThisTypeIsUsed
// Read (possibly external) annotations // Read (possibly external) annotations
else -> attr.howThisTypeIsUsedAccordingToAnnotations else -> attr.howThisTypeIsUsedAccordingToAnnotations
} }
@@ -172,6 +172,10 @@ public class JavaToKotlinClassMap implements PlatformToKotlinClassMap {
: classId(outer).createNestedClassId(Name.identifier(clazz.getSimpleName())); : classId(outer).createNestedClassId(Name.identifier(clazz.getSimpleName()));
} }
public boolean isJavaPlatformClass(@NotNull FqName fqName) {
return mapJavaToKotlin(fqName) != null;
}
@NotNull @NotNull
public Collection<ClassDescriptor> mapPlatformClass(@NotNull FqName fqName, @NotNull KotlinBuiltIns builtIns) { public Collection<ClassDescriptor> mapPlatformClass(@NotNull FqName fqName, @NotNull KotlinBuiltIns builtIns) {
ClassDescriptor kotlinAnalog = mapJavaToKotlin(fqName, builtIns); ClassDescriptor kotlinAnalog = mapJavaToKotlin(fqName, builtIns);
@@ -93,4 +93,4 @@ class ImportableFqNameClassifier(private val file: KtFile) {
} }
fun isJavaClassNotToBeUsedInKotlin(fqName: FqName): Boolean fun isJavaClassNotToBeUsedInKotlin(fqName: FqName): Boolean
= JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName, DefaultBuiltIns.Instance).isNotEmpty() || JavaAnnotationMapper.javaToKotlinNameMap[fqName] != null = JavaToKotlinClassMap.INSTANCE.isJavaPlatformClass(fqName) || JavaAnnotationMapper.javaToKotlinNameMap[fqName] != null
@@ -20,11 +20,13 @@ import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.* import com.intellij.psi.*
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.psi.psiUtil.allChildren
import java.util.ArrayList import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.psi.psiUtil.siblings
import java.util.*
data class DataForConversion private constructor( data class DataForConversion private constructor(
val elementsAndTexts: Collection<Any> /* list consisting of PsiElement's to convert and plain String's */, val elementsAndTexts: Collection<Any> /* list consisting of PsiElement's to convert and plain String's */,
@@ -243,9 +245,7 @@ data class DataForConversion private constructor(
else { else {
val fqName = FqNameUnsafe(qualifiedName) val fqName = FqNameUnsafe(qualifiedName)
// skip explicit imports of platform classes mapped into Kotlin classes // skip explicit imports of platform classes mapped into Kotlin classes
if (fqName.isSafe if (fqName.isSafe && JavaToKotlinClassMap.INSTANCE.isJavaPlatformClass(fqName.toSafe())) continue
&& JavaToKotlinClassMap.INSTANCE.mapPlatformClass(
fqName.toSafe(), DefaultBuiltIns.Instance).isNotEmpty()) continue
append("import $qualifiedName\n") append("import $qualifiedName\n")
} }
} }
@@ -73,6 +73,7 @@ import org.jetbrains.kotlin.resolve.AnalyzingUtils
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.Opcodes.ASM5 import org.jetbrains.org.objectweb.asm.Opcodes.ASM5
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -549,8 +550,10 @@ fun Type.getClassDescriptor(scope: GlobalSearchScope): ClassDescriptor? {
val jvmName = JvmClassName.byInternalName(internalName).fqNameForClassNameWithoutDollars val jvmName = JvmClassName.byInternalName(internalName).fqNameForClassNameWithoutDollars
val platformClasses = JavaToKotlinClassMap.INSTANCE.mapPlatformClass(jvmName, DefaultBuiltIns.Instance) // TODO: use the correct built-ins from the module instead of DefaultBuiltIns here
if (platformClasses.isNotEmpty()) return platformClasses.first() JavaToKotlinClassMap.INSTANCE.mapJavaToKotlin(jvmName)?.let(
DefaultBuiltIns.Instance.builtInsModule::findClassAcrossModuleDependencies
)?.let { return it }
return runReadAction { return runReadAction {
val classes = JavaPsiFacade.getInstance(scope.project).findClasses(jvmName.asString(), scope) val classes = JavaPsiFacade.getInstance(scope.project).findClasses(jvmName.asString(), scope)
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.j2k.ast.Import import org.jetbrains.kotlin.j2k.ast.Import
import org.jetbrains.kotlin.j2k.ast.ImportList import org.jetbrains.kotlin.j2k.ast.ImportList
@@ -60,7 +59,7 @@ private fun Converter.convertImport(fqName: FqName, ref: PsiJavaCodeReferenceEle
if (annotationConverter.isImportNotRequired(fqName)) return emptyList() if (annotationConverter.isImportNotRequired(fqName)) return emptyList()
// If imported class has a kotlin analog, drop the import // If imported class has a kotlin analog, drop the import
if (!JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName, DefaultBuiltIns.Instance).isEmpty()) return emptyList() if (JavaToKotlinClassMap.INSTANCE.isJavaPlatformClass(fqName)) return emptyList()
} }
//TODO: how to detect compiled Kotlin here? //TODO: how to detect compiled Kotlin here?