Recognize Checker Framework declaration annotations.
We are migrating Guava to use these annotations rather than jsr305's @Nullable. We can't use the Checker Framework's _@Nullable_ yet because we promise compatibility with Java 7, which doesn't support type annotations. This is related to but distinct from https://youtrack.jetbrains.com/issue/KT-21408, which is about a different jsr305 annotation we use, @ParametersAreNonnullByDefault. I've also updated some docs to mention Kotlin's existing support for the Checker Framework _@NonNull_.
This commit is contained in:
committed by
Alexander Udalov
parent
79359b7bc2
commit
ac87ad422d
@@ -0,0 +1,33 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||
// FILE: A.java
|
||||
|
||||
import org.checkerframework.checker.nullness.compatqual.*;
|
||||
|
||||
public class A {
|
||||
@NullableDecl public String field = null;
|
||||
|
||||
@NullableDecl
|
||||
public String foo(@NonNullDecl String x, @NullableDecl CharSequence y) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@NonNullDecl
|
||||
public String bar() {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
fun main(a: A) {
|
||||
a.foo("", null)?.length
|
||||
a.foo("", null)<!UNSAFE_CALL!>.<!>length
|
||||
a.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
a.bar().length
|
||||
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
|
||||
|
||||
a.field?.length
|
||||
a.field<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package
|
||||
|
||||
public fun main(/*0*/ a: A): kotlin.Unit
|
||||
|
||||
public open class A {
|
||||
public constructor A()
|
||||
@org.checkerframework.checker.nullness.compatqual.NullableDecl public final var field: kotlin.String?
|
||||
@org.checkerframework.checker.nullness.compatqual.NonNullDecl public open fun bar(): kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
@org.checkerframework.checker.nullness.compatqual.NullableDecl public open fun foo(/*0*/ @org.checkerframework.checker.nullness.compatqual.NonNullDecl x: kotlin.String, /*1*/ @org.checkerframework.checker.nullness.compatqual.NullableDecl y: kotlin.CharSequence?): kotlin.String?
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+6
@@ -48,6 +48,12 @@ public class ForeignAnnotationsNoAnnotationInClasspathTestGenerated extends Abst
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("checkerFramework.kt")
|
||||
public void testCheckerFramework() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/checkerFramework.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("eclipse.kt")
|
||||
public void testEclipse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/eclipse.kt");
|
||||
|
||||
+6
@@ -48,6 +48,12 @@ public class ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGe
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("checkerFramework.kt")
|
||||
public void testCheckerFramework() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/checkerFramework.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("eclipse.kt")
|
||||
public void testEclipse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/eclipse.kt");
|
||||
|
||||
@@ -48,6 +48,12 @@ public class ForeignAnnotationsTestGenerated extends AbstractForeignAnnotationsT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("checkerFramework.kt")
|
||||
public void testCheckerFramework() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/checkerFramework.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("eclipse.kt")
|
||||
public void testEclipse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/eclipse.kt");
|
||||
|
||||
+6
@@ -48,6 +48,12 @@ public class JavacForeignAnnotationsTestGenerated extends AbstractJavacForeignAn
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("checkerFramework.kt")
|
||||
public void testCheckerFramework() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/checkerFramework.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("eclipse.kt")
|
||||
public void testEclipse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/eclipse.kt");
|
||||
|
||||
@@ -24,6 +24,7 @@ val NULLABLE_ANNOTATIONS = listOf(
|
||||
FqName("com.android.annotations.Nullable"),
|
||||
FqName("org.eclipse.jdt.annotation.Nullable"),
|
||||
FqName("org.checkerframework.checker.nullness.qual.Nullable"),
|
||||
FqName("org.checkerframework.checker.nullness.compatqual.NullableDecl"),
|
||||
FqName("javax.annotation.Nullable"),
|
||||
FqName("javax.annotation.CheckForNull"),
|
||||
FqName("edu.umd.cs.findbugs.annotations.CheckForNull"),
|
||||
@@ -42,6 +43,7 @@ val NOT_NULL_ANNOTATIONS = listOf(
|
||||
FqName("com.android.annotations.NonNull"),
|
||||
FqName("org.eclipse.jdt.annotation.NonNull"),
|
||||
FqName("org.checkerframework.checker.nullness.qual.NonNull"),
|
||||
FqName("org.checkerframework.checker.nullness.compatqual.NonNullDecl"),
|
||||
FqName("lombok.NonNull"),
|
||||
FqName("io.reactivex.annotations.NonNull")
|
||||
)
|
||||
|
||||
@@ -498,4 +498,8 @@ We can also support the following annotations out-of-the-box:
|
||||
* `NotNull` and `NotNull.List`
|
||||
* [Project Lombok](http://projectlombok.org/features/NonNull.html)
|
||||
* [`org.eclipse.jdt.annotation`](https://wiki.eclipse.org/JDT_Core/Null_Analysis)
|
||||
* [`org.checkerframework.checker.nullness.qual`](http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#nullness-checker)
|
||||
* [`org.checkerframework.checker.nullness`](https://checkerframework.org/manual/#nullness-checker)
|
||||
* [`*.qual.Nullable`](https://checkerframework.org/api/org/checkerframework/checker/nullness/qual/Nullable.html)
|
||||
* [`*.qual.NonNull`](https://checkerframework.org/api/org/checkerframework/checker/nullness/qual/NonNull.html)
|
||||
* [`*.compatqual.NullableDecl`](https://checkerframework.org/api/org/checkerframework/checker/nullness/compatqual/NullableDecl.html)
|
||||
* [`*.compatqual.NonNullDecl`](https://checkerframework.org/api/org/checkerframework/checker/nullness/compatqual/NonNullDecl.html)
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.checkerframework.checker.nullness.compatqual;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Java 7 compatibility annotation without dependency on Java 8 classes.
|
||||
*
|
||||
* @see org.checkerframework.checker.nullness.qual.NonNull
|
||||
* @checker_framework.manual #nullness-checker Nullness Checker
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NonNullDecl {}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.checkerframework.checker.nullness.compatqual;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Java 7 compatibility annotation without dependency on Java 8 classes.
|
||||
*
|
||||
* @see org.checkerframework.checker.nullness.qual.Nullable
|
||||
* @checker_framework.manual #nullness-checker Nullness Checker
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NullableDecl {}
|
||||
Reference in New Issue
Block a user