Fix wrong nullability enhancement for annotated java.lang.Object type

Effectively, this commit drops cached value for j.l.Object type
This cache was introduced when types were immutable, but they
became mutable after starting reading top-level TYPE_USE annotations,
that lead to changing shared JAVA_LANG_OBJECT_CLASSIFIER_TYPE instance

 #KT-20826 Fixed
This commit is contained in:
Denis Zharkov
2017-10-20 09:43:25 +03:00
parent 3c9ef6d319
commit da52716bfd
8 changed files with 69 additions and 26 deletions
@@ -80,7 +80,7 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
private val signatureParsingComponent =
BinaryClassSignatureParser(ClassifierResolutionContext { findClass(it, allScope) })
BinaryClassSignatureParser()
override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? {
val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null
@@ -16,14 +16,11 @@
package org.jetbrains.kotlin.load.java.structure.impl.classFiles
import com.intellij.psi.CommonClassNames
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
import org.jetbrains.kotlin.load.java.structure.JavaType
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.flattenTo
import org.jetbrains.kotlin.utils.compact
@@ -33,14 +30,11 @@ import java.text.StringCharacterIterator
/**
* Take a look at com.intellij.psi.impl.compiled.SignatureParsing
* NOTE: currently this class can simply be converted to an object, but there are postponed plans
* to introduce cached instance for java.lang.Object type that would require injected class finder.
* So please, do not convert it to object
*/
class BinaryClassSignatureParser(globalContext: ClassifierResolutionContext) {
companion object {
private val JAVA_LANG_OBJECT = ClassId.topLevel(FqName(CommonClassNames.JAVA_LANG_OBJECT))
}
private val JAVA_LANG_OBJECT_CLASSIFIER_TYPE: JavaClassifierType =
PlainJavaClassifierType({ globalContext.resolveClass(JAVA_LANG_OBJECT) }, emptyList())
class BinaryClassSignatureParser {
fun parseTypeParametersDeclaration(signature: CharacterIterator, context: ClassifierResolutionContext): List<JavaTypeParameter> {
if (signature.current() != '<') {
@@ -68,25 +62,14 @@ class BinaryClassSignatureParser(globalContext: ClassifierResolutionContext) {
val parameterName = name.toString()
// postpone list allocation till a second bound is seen; ignore sole Object bound
var bounds: MutableList<JavaClassifierType>? = null
var jlo = false
val bounds: MutableList<JavaClassifierType> = ContainerUtil.newSmartList()
while (signature.current() == ':') {
signature.next()
val bound = parseClassifierRefSignature(signature, context) ?: continue
if (bounds == null) {
if (JAVA_LANG_OBJECT_CLASSIFIER_TYPE === bound) {
jlo = true
continue
}
bounds = ContainerUtil.newSmartList()
if (jlo) {
bounds.add(JAVA_LANG_OBJECT_CLASSIFIER_TYPE)
}
}
bounds.add(bound)
}
return BinaryJavaTypeParameter(Name.identifier(parameterName), bounds ?: emptyList())
return BinaryJavaTypeParameter(Name.identifier(parameterName), bounds)
}
fun parseClassifierRefSignature(signature: CharacterIterator, context: ClassifierResolutionContext): JavaClassifierType? {
@@ -148,8 +131,6 @@ class BinaryClassSignatureParser(globalContext: ClassifierResolutionContext) {
}
signature.next()
if (canonicalName.toString() == "java/lang/Object") return JAVA_LANG_OBJECT_CLASSIFIER_TYPE
return PlainJavaClassifierType(
{ context.resolveByInternalName(canonicalName.toString()) },
argumentGroups.reversed().flattenTo(arrayListOf()).compact()
@@ -0,0 +1,17 @@
// FILE: A.java
import org.checkerframework.checker.nullness.qual.*;
public class A {
@NonNull
public Object foo() { return null; }
}
// FILE: B.java
public class B {
public static void assertNonNull(Object x) {}
}
// FILE: main.kt
fun main() {
A()
B.assertNonNull(null)
}
@@ -0,0 +1,21 @@
package
public fun main(): kotlin.Unit
public open class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@org.checkerframework.checker.nullness.qual.NonNull public open fun foo(): @org.checkerframework.checker.nullness.qual.NonNull kotlin.Any
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class B {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open fun assertNonNull(/*0*/ x: kotlin.Any!): kotlin.Unit
}
@@ -48,6 +48,12 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated extends
doTest(fileName);
}
@TestMetadata("typeUseOnObject.kt")
public void testTypeUseOnObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -48,6 +48,12 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathWithFastClassReadingT
doTest(fileName);
}
@TestMetadata("typeUseOnObject.kt")
public void testTypeUseOnObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -48,6 +48,12 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An
doTest(fileName);
}
@TestMetadata("typeUseOnObject.kt")
public void testTypeUseOnObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -48,6 +48,12 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore
doTest(fileName);
}
@TestMetadata("typeUseOnObject.kt")
public void testTypeUseOnObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)