Fix for IDEA complains when assigning Kotlin objects where java.lang.Object is expected

#KT-4355 Fixed
This commit is contained in:
Nikolay Krasko
2013-12-27 14:40:52 +04:00
parent e0f13da108
commit 217931622e
9 changed files with 114 additions and 50 deletions
@@ -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;
}
}
@@ -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
}
@@ -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);
}
}
@@ -0,0 +1,2 @@
class KotlinClass
trait KotlinTrait
@@ -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<Integer> intCollection = TestPackage.getList();
List<Integer> intList = TestPackage.getList();
Collection<Integer> intMutableCollection = TestPackage.getMutableList();
List<Integer> intMutableList = TestPackage.getMutableList();
Collection<String> stringsCollection = TestPackage.getArrayList();
ArrayList<String> arrayListCollection = TestPackage.getArrayList();
}
}
@@ -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<Int> = listOf(1, 2, 3)
fun getMutableList(): MutableList<Int> = ArrayList<Int>()
fun getArrayList(): ArrayList<String> = ArrayList<String>()
@@ -0,0 +1,6 @@
class UseKotlinSubclassesOfMappedTypes {
void test() {
Iterable<String> iterable = new KotlinIterableTraitTest();
Comparable<Integer> comparable = new KotlinComparableTest();
}
}
@@ -0,0 +1,11 @@
class KotlinComparableTest : Comparable<Int> {
override fun compareTo(other: Int): Int {
throw UnsupportedOperationException()
}
}
class KotlinIterableTraitTest : Iterable<String> {
override fun iterator(): Iterator<String> {
throw UnsupportedOperationException()
}
}
@@ -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");
}
}