From 217931622ed4126d6078964999fe5f9fb4d3fc67 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Fri, 27 Dec 2013 14:40:52 +0400 Subject: [PATCH] Fix for IDEA complains when assigning Kotlin objects where java.lang.Object is expected #KT-4355 Fixed --- ...otlinLightClassForExplicitDeclaration.java | 51 ++++++++++++++----- .../jet/lang/resolve/descriptorUtils.kt | 38 -------------- .../AssignKotlinClassToObjectInJava.java | 10 ++++ .../AssignKotlinClassToObjectInJava.kt | 2 + .../AssignMappedKotlinType.java | 23 +++++++++ .../AssignMappedKotlinType.kt | 11 ++++ .../UseKotlinSubclassesOfMappedTypes.java | 6 +++ .../UseKotlinSubclassesOfMappedTypes.kt | 11 ++++ .../checkers/KotlinAndJavaCheckerTest.java | 12 +++++ 9 files changed, 114 insertions(+), 50 deletions(-) delete mode 100644 core/descriptors/src/org/jetbrains/jet/lang/resolve/descriptorUtils.kt create mode 100644 idea/testData/kotlinAndJavaChecker/AssignKotlinClassToObjectInJava.java create mode 100644 idea/testData/kotlinAndJavaChecker/AssignKotlinClassToObjectInJava.kt create mode 100644 idea/testData/kotlinAndJavaChecker/AssignMappedKotlinType.java create mode 100644 idea/testData/kotlinAndJavaChecker/AssignMappedKotlinType.kt create mode 100644 idea/testData/kotlinAndJavaChecker/UseKotlinSubclassesOfMappedTypes.java create mode 100644 idea/testData/kotlinAndJavaChecker/UseKotlinSubclassesOfMappedTypes.kt diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForExplicitDeclaration.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForExplicitDeclaration.java index efe0f9581f5..eba35bb82a7 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForExplicitDeclaration.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForExplicitDeclaration.java @@ -48,10 +48,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.resolve.ResolvePackage; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -518,19 +518,24 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC @Override public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) { - String qualifiedName; - if (baseClass instanceof KotlinLightClassForExplicitDeclaration) { - ClassDescriptor baseDescriptor = ((KotlinLightClassForExplicitDeclaration) baseClass).getDescriptor(); - qualifiedName = baseDescriptor != null ? DescriptorUtils.getFqName(baseDescriptor).asString() : null; - } - else { - qualifiedName = baseClass.getQualifiedName(); + // Java inheritor check doesn't work when trait (interface in Java) subclasses Java class and for Kotlin local classes + if (baseClass instanceof KotlinLightClassForExplicitDeclaration || (isInterface() && !baseClass.isInterface())) { + String qualifiedName; + if (baseClass instanceof KotlinLightClassForExplicitDeclaration) { + ClassDescriptor baseDescriptor = ((KotlinLightClassForExplicitDeclaration) baseClass).getDescriptor(); + qualifiedName = baseDescriptor != null ? DescriptorUtils.getFqName(baseDescriptor).asString() : null; + } + else { + qualifiedName = baseClass.getQualifiedName(); + } + + ClassDescriptor thisDescriptor = getDescriptor(); + return qualifiedName != null + && thisDescriptor != null + && checkSuperTypeByFQName(thisDescriptor, qualifiedName, checkDeep); } - ClassDescriptor thisDescriptor = getDescriptor(); - return qualifiedName != null - && thisDescriptor != null - && ResolvePackage.checkSuperTypeByFQName(thisDescriptor, qualifiedName, checkDeep); + return super.isInheritor(baseClass, checkDeep); } @Override @@ -616,4 +621,26 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC return false; } } + + private static boolean checkSuperTypeByFQName(@NotNull ClassDescriptor classDescriptor, @NotNull String qualifiedName, Boolean deep) { + if (CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName)) return true; + + if (qualifiedName.equals(DescriptorUtils.getFqName(classDescriptor).asString())) return true; + + for (JetType superType : classDescriptor.getTypeConstructor().getSupertypes()) { + ClassifierDescriptor superDescriptor = superType.getConstructor().getDeclarationDescriptor(); + + if (superDescriptor instanceof ClassDescriptor) { + if (qualifiedName.equals(DescriptorUtils.getFqName(superDescriptor).asString())) return true; + + if (deep) { + if (checkSuperTypeByFQName((ClassDescriptor)superDescriptor, qualifiedName, true)) { + return true; + } + } + } + } + + return false; + } } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/descriptorUtils.kt b/core/descriptors/src/org/jetbrains/jet/lang/resolve/descriptorUtils.kt deleted file mode 100644 index df7e888d24f..00000000000 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/descriptorUtils.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.resolve - -import org.jetbrains.jet.lang.descriptors.ClassDescriptor -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor - -public fun ClassDescriptor.checkSuperTypeByFQName(qualifiedName: String, deep: Boolean): Boolean { - fun checkDescriptor(descriptor: DeclarationDescriptor): Boolean { - return qualifiedName == DescriptorUtils.getFqName(descriptor).asString() - } - - if (deep && checkDescriptor(this)) return true - - for (superType in getTypeConstructor().getSupertypes()) { - val superDescriptor = superType.getConstructor().getDeclarationDescriptor() - if (superDescriptor is ClassDescriptor) { - if (checkDescriptor(superDescriptor)) return true - if (deep && superDescriptor.checkSuperTypeByFQName(qualifiedName, deep)) return true - } - } - - return false -} diff --git a/idea/testData/kotlinAndJavaChecker/AssignKotlinClassToObjectInJava.java b/idea/testData/kotlinAndJavaChecker/AssignKotlinClassToObjectInJava.java new file mode 100644 index 00000000000..e24a5b5a0ac --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/AssignKotlinClassToObjectInJava.java @@ -0,0 +1,10 @@ +// KT-4355 IDEA complains when assigning Kotlin objects where java.lang.Object is expected +class AssignKotlinClassToObjectInJava { + void test(KotlinTrait trait) { + Object kotlinClass = new KotlinClass(); + Object kotlinTrait = trait; + + KotlinClass foo = null; + foo.equals(foo); + } +} diff --git a/idea/testData/kotlinAndJavaChecker/AssignKotlinClassToObjectInJava.kt b/idea/testData/kotlinAndJavaChecker/AssignKotlinClassToObjectInJava.kt new file mode 100644 index 00000000000..197c1d06979 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/AssignKotlinClassToObjectInJava.kt @@ -0,0 +1,2 @@ +class KotlinClass +trait KotlinTrait diff --git a/idea/testData/kotlinAndJavaChecker/AssignMappedKotlinType.java b/idea/testData/kotlinAndJavaChecker/AssignMappedKotlinType.java new file mode 100644 index 00000000000..4311917200d --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/AssignMappedKotlinType.java @@ -0,0 +1,23 @@ +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import test.TestPackage; + +class AssignMappedKotlinType { + void test() { + int i1 = TestPackage.getInt(); + Integer i2 = TestPackage.getInt(); + Number number = TestPackage.getNumber(); + String str = TestPackage.getString(); + + Collection intCollection = TestPackage.getList(); + List intList = TestPackage.getList(); + + Collection intMutableCollection = TestPackage.getMutableList(); + List intMutableList = TestPackage.getMutableList(); + + Collection stringsCollection = TestPackage.getArrayList(); + ArrayList arrayListCollection = TestPackage.getArrayList(); + } +} diff --git a/idea/testData/kotlinAndJavaChecker/AssignMappedKotlinType.kt b/idea/testData/kotlinAndJavaChecker/AssignMappedKotlinType.kt new file mode 100644 index 00000000000..4bcd3025ee3 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/AssignMappedKotlinType.kt @@ -0,0 +1,11 @@ +package test + +import java.util.ArrayList + +fun getInt(): Int = 12 +fun getString(): String = "Test" +fun getNumber(): Number? = null + +fun getList(): List = listOf(1, 2, 3) +fun getMutableList(): MutableList = ArrayList() +fun getArrayList(): ArrayList = ArrayList() \ No newline at end of file diff --git a/idea/testData/kotlinAndJavaChecker/UseKotlinSubclassesOfMappedTypes.java b/idea/testData/kotlinAndJavaChecker/UseKotlinSubclassesOfMappedTypes.java new file mode 100644 index 00000000000..ae60682d178 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/UseKotlinSubclassesOfMappedTypes.java @@ -0,0 +1,6 @@ +class UseKotlinSubclassesOfMappedTypes { + void test() { + Iterable iterable = new KotlinIterableTraitTest(); + Comparable comparable = new KotlinComparableTest(); + } +} \ No newline at end of file diff --git a/idea/testData/kotlinAndJavaChecker/UseKotlinSubclassesOfMappedTypes.kt b/idea/testData/kotlinAndJavaChecker/UseKotlinSubclassesOfMappedTypes.kt new file mode 100644 index 00000000000..f9b67eb5266 --- /dev/null +++ b/idea/testData/kotlinAndJavaChecker/UseKotlinSubclassesOfMappedTypes.kt @@ -0,0 +1,11 @@ +class KotlinComparableTest : Comparable { + override fun compareTo(other: Int): Int { + throw UnsupportedOperationException() + } +} + +class KotlinIterableTraitTest : Iterable { + override fun iterator(): Iterator { + throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/checkers/KotlinAndJavaCheckerTest.java b/idea/tests/org/jetbrains/jet/checkers/KotlinAndJavaCheckerTest.java index 8817d8222bc..6dae9d7007a 100644 --- a/idea/tests/org/jetbrains/jet/checkers/KotlinAndJavaCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/checkers/KotlinAndJavaCheckerTest.java @@ -47,4 +47,16 @@ public class KotlinAndJavaCheckerTest extends DaemonAnalyzerTestCase { public void testUsingKotlinPackageDeclarations() throws Exception { doTest(true, true, "UsingKotlinPackageDeclarations.java", "UsingKotlinPackageDeclarations.kt"); } + + public void testAssignKotlinClassToObjectInJava() throws Exception { + doTest(true, true, "AssignKotlinClassToObjectInJava.java", "AssignKotlinClassToObjectInJava.kt"); + } + + public void testAssignMappedKotlinType() throws Exception { + doTest(true, true, "AssignMappedKotlinType.java", "AssignMappedKotlinType.kt"); + } + + public void testUseKotlinSubclassesOfMappedTypes() throws Exception { + doTest(true, true, "UseKotlinSubclassesOfMappedTypes.java", "UseKotlinSubclassesOfMappedTypes.kt"); + } }