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:
+1
-1
@@ -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
|
||||
|
||||
+6
-25
@@ -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
|
||||
}
|
||||
+6
@@ -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)
|
||||
|
||||
+6
@@ -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)
|
||||
|
||||
+6
@@ -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)
|
||||
|
||||
+6
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user