Fix SOE in SignatureEnhancement::extractNullability

The problem was that `resolveTypeQualifierAnnotation` actually doesn't
guarantee that `typeQualifierAnnotation` is javax.annotation.NonNull
with argument

It could be just any type qualifier (see the test)
This commit is contained in:
Denis Zharkov
2017-09-21 17:31:26 +03:00
parent 1953f8e945
commit c7812beea4
7 changed files with 172 additions and 12 deletions
@@ -0,0 +1,85 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// FILE: UnknownQualifier.java
import javax.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifier;
import javax.annotation.meta.When;
@Documented
@TypeQualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface UnknownQualifier {
}
// FILE: UnknownQualifierNickname.java
import javax.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Documented
@TypeQualifierNickname
@UnknownQualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface UnknownQualifierNickname {
}
// FILE: UnknownQualifierDefault.java
import javax.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierDefault;
import javax.annotation.meta.When;
@Documented
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
@UnknownQualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface UnknownQualifierDefault {
}
// FILE: UnknownQualifierNicknameDefault.java
import javax.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierDefault;
import javax.annotation.meta.When;
@Documented
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
@UnknownQualifierNickname
@Retention(RetentionPolicy.RUNTIME)
public @interface UnknownQualifierNicknameDefault {
}
// FILE: A.java
import javax.annotation.*;
@UnknownQualifierDefault
public class A {
@UnknownQualifierNicknameDefault
public static class B {
@UnknownQualifier
public static String foo(@UnknownQualifierNickname String x) { return null; }
}
}
// FILE: main.kt
fun main() {
A.B.foo(null).hashCode()
}
@@ -0,0 +1,48 @@
package
public fun main(): kotlin.Unit
@UnknownQualifierDefault public open class A {
public constructor A()
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
@UnknownQualifierNicknameDefault 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
@UnknownQualifier public open fun foo(/*0*/ @UnknownQualifierNickname x: kotlin.String!): kotlin.String!
}
}
@kotlin.annotation.MustBeDocumented @javax.annotation.meta.TypeQualifier @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class UnknownQualifier : kotlin.Annotation {
public constructor UnknownQualifier()
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
}
@kotlin.annotation.MustBeDocumented @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.METHOD, ElementType.PARAMETER}) @UnknownQualifier @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class UnknownQualifierDefault : kotlin.Annotation {
public constructor UnknownQualifierDefault()
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
}
@kotlin.annotation.MustBeDocumented @javax.annotation.meta.TypeQualifierNickname @UnknownQualifier @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class UnknownQualifierNickname : kotlin.Annotation {
public constructor UnknownQualifierNickname()
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
}
@kotlin.annotation.MustBeDocumented @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.METHOD, ElementType.PARAMETER}) @UnknownQualifierNickname @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class UnknownQualifierNicknameDefault : kotlin.Annotation {
public constructor UnknownQualifierNicknameDefault()
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
}
@@ -60,6 +60,12 @@ public class ForeignAnnotationsNoAnnotationInClasspathTestGenerated extends Abst
doTest(fileName);
}
@TestMetadata("irrelevantQualifierNicknames.kt")
public void testIrrelevantQualifierNicknames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/irrelevantQualifierNicknames.kt");
doTest(fileName);
}
@TestMetadata("jsr305NullabilityNicknames.kt")
public void testJsr305NullabilityNicknames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.kt");
@@ -60,6 +60,12 @@ public class ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGe
doTest(fileName);
}
@TestMetadata("irrelevantQualifierNicknames.kt")
public void testIrrelevantQualifierNicknames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/irrelevantQualifierNicknames.kt");
doTest(fileName);
}
@TestMetadata("jsr305NullabilityNicknames.kt")
public void testJsr305NullabilityNicknames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.kt");
@@ -60,6 +60,12 @@ public class ForeignAnnotationsTestGenerated extends AbstractForeignAnnotationsT
doTest(fileName);
}
@TestMetadata("irrelevantQualifierNicknames.kt")
public void testIrrelevantQualifierNicknames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/irrelevantQualifierNicknames.kt");
doTest(fileName);
}
@TestMetadata("jsr305NullabilityNicknames.kt")
public void testJsr305NullabilityNicknames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.kt");
@@ -60,6 +60,12 @@ public class JavacForeignAnnotationsTestGenerated extends AbstractJavacForeignAn
doTest(fileName);
}
@TestMetadata("irrelevantQualifierNicknames.kt")
public void testIrrelevantQualifierNicknames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/irrelevantQualifierNicknames.kt");
doTest(fileName);
}
@TestMetadata("jsr305NullabilityNicknames.kt")
public void testJsr305NullabilityNicknames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305NullabilityNicknames.kt");
@@ -68,27 +68,30 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati
}
fun extractNullability(annotationDescriptor: AnnotationDescriptor): NullabilityQualifierWithMigrationStatus? {
extractNullabilityFromKnownAnnotations(annotationDescriptor)?.let { return it }
val typeQualifierAnnotation =
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor)
?: return null
val forWarning = annotationTypeQualifierResolver.jsr305State.isWarning()
return extractNullabilityFromKnownAnnotations(typeQualifierAnnotation)?.copy(isForWarningOnly = forWarning)
}
private fun extractNullabilityFromKnownAnnotations(
annotationDescriptor: AnnotationDescriptor
): NullabilityQualifierWithMigrationStatus? {
val annotationFqName = annotationDescriptor.fqName ?: return null
return when (annotationFqName) {
in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument()
else -> {
val forWarning = annotationTypeQualifierResolver.jsr305State.isWarning()
val typeQualifierAnnotation =
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor)
?: return null
// resolveTypeQualifierAnnotation guarantees that `typeQualifierAnnotation` is javax.annotation.NonNull with argument
// or javax.annotation.CheckForNull without arguments
extractNullability(typeQualifierAnnotation)?.copy(isForWarningOnly = forWarning)
}
else -> null
}
}
fun <D : CallableMemberDescriptor> enhanceSignatures(c: LazyJavaResolverContext, platformSignatures: Collection<D>): Collection<D> {
return platformSignatures.map {
it.enhanceSignature(c)