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_UPPER_BOUND -> MEMBER_SIGNATURE_CONTRAVARIANT
// 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
javaToKotlin.mapPlatformClass(fqName, c.module.builtIns).isEmpty() -> attr.howThisTypeIsUsed
// 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
!javaToKotlin.isJavaPlatformClass(fqName) -> attr.howThisTypeIsUsed
// Read (possibly external) annotations
// Read (possibly external) annotations
else -> attr.howThisTypeIsUsedAccordingToAnnotations
}
@@ -172,6 +172,10 @@ public class JavaToKotlinClassMap implements PlatformToKotlinClassMap {
: classId(outer).createNestedClassId(Name.identifier(clazz.getSimpleName()));
}
public boolean isJavaPlatformClass(@NotNull FqName fqName) {
return mapJavaToKotlin(fqName) != null;
}
@NotNull
public Collection<ClassDescriptor> mapPlatformClass(@NotNull FqName fqName, @NotNull KotlinBuiltIns builtIns) {
ClassDescriptor kotlinAnalog = mapJavaToKotlin(fqName, builtIns);
@@ -93,4 +93,4 @@ class ImportableFqNameClassifier(private val file: KtFile) {
}
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.util.TextRange
import com.intellij.psi.*
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.psi.psiUtil.*
import java.util.ArrayList
import org.jetbrains.kotlin.psi.psiUtil.allChildren
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(
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 {
val fqName = FqNameUnsafe(qualifiedName)
// skip explicit imports of platform classes mapped into Kotlin classes
if (fqName.isSafe
&& JavaToKotlinClassMap.INSTANCE.mapPlatformClass(
fqName.toSafe(), DefaultBuiltIns.Instance).isNotEmpty()) continue
if (fqName.isSafe && JavaToKotlinClassMap.INSTANCE.isJavaPlatformClass(fqName.toSafe())) continue
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.BindingTrace
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.Opcodes.ASM5
import org.jetbrains.org.objectweb.asm.Type
@@ -549,8 +550,10 @@ fun Type.getClassDescriptor(scope: GlobalSearchScope): ClassDescriptor? {
val jvmName = JvmClassName.byInternalName(internalName).fqNameForClassNameWithoutDollars
val platformClasses = JavaToKotlinClassMap.INSTANCE.mapPlatformClass(jvmName, DefaultBuiltIns.Instance)
if (platformClasses.isNotEmpty()) return platformClasses.first()
// TODO: use the correct built-ins from the module instead of DefaultBuiltIns here
JavaToKotlinClassMap.INSTANCE.mapJavaToKotlin(jvmName)?.let(
DefaultBuiltIns.Instance.builtInsModule::findClassAcrossModuleDependencies
)?.let { return it }
return runReadAction {
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.elements.KtLightDeclaration
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.j2k.ast.Import
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 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?