From 517cc84f4d5ccd0aac7a43d8719dd9343626f493 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 6 Aug 2019 16:11:21 +0300 Subject: [PATCH] Add initial support for codeanalysis annotations --- .../tests/jspecify/simple.kt | 33 ++++++++++++++ .../tests/jspecify/simple.txt | 13 ++++++ ...sNoAnnotationInClasspathTestGenerated.java | 18 ++++++++ ...spathWithPsiClassReadingTestGenerated.java | 18 ++++++++ .../ForeignJava8AnnotationsTestGenerated.java | 18 ++++++++ ...cForeignJava8AnnotationsTestGenerated.java | 18 ++++++++ .../kotlin/load/java/JvmAnnotationNames.kt | 44 +++++++++++++------ .../jspecify/annotations/DefaultNotNull.java | 16 +++++++ .../jspecify/annotations/DefaultNullable.java | 16 +++++++ .../annotations/DefaultNullnessUnknown.java | 16 +++++++ .../jspecify/annotations/NotNull.java | 11 +++++ .../jspecify/annotations/Nullable.java | 11 +++++ .../jspecify/annotations/UnknownNullness.java | 16 +++++++ 13 files changed, 234 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt create mode 100644 compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.txt create mode 100644 third-party/jdk8-annotations/jspecify/annotations/DefaultNotNull.java create mode 100644 third-party/jdk8-annotations/jspecify/annotations/DefaultNullable.java create mode 100644 third-party/jdk8-annotations/jspecify/annotations/DefaultNullnessUnknown.java create mode 100644 third-party/jdk8-annotations/jspecify/annotations/NotNull.java create mode 100644 third-party/jdk8-annotations/jspecify/annotations/Nullable.java create mode 100644 third-party/jdk8-annotations/jspecify/annotations/UnknownNullness.java diff --git a/compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt new file mode 100644 index 00000000000..dec22f6b2ee --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt @@ -0,0 +1,33 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// FILE: A.java + +import jspecify.annotations.*; + +public class A { + @Nullable public String field = null; + + @Nullable + public String foo(@NotNull String x, @UnknownNullness CharSequence y) { + return ""; + } + + @NotNull + public String bar() { + return ""; + } + +} + +// FILE: main.kt + +fun main(a: A) { + a.foo("", null)?.length + a.foo("", null).length + a.foo(null, "").length + + a.bar().length + a.bar()!!.length + + a.field?.length + a.field.length +} diff --git a/compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.txt b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.txt new file mode 100644 index 00000000000..9232ebfbb40 --- /dev/null +++ b/compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.txt @@ -0,0 +1,13 @@ +package + +public fun main(/*0*/ a: A): kotlin.Unit + +public open class A { + public constructor A() + @jspecify.annotations.Nullable public final var field: kotlin.String? + @jspecify.annotations.NotNull public open fun bar(): kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @jspecify.annotations.Nullable public open fun foo(/*0*/ @jspecify.annotations.NotNull x: kotlin.String, /*1*/ @jspecify.annotations.UnknownNullness 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 +} diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java index 87089200c00..2c8247ab74c 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated.java @@ -43,6 +43,24 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathTestGenerated extends runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); } + @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Jspecify extends AbstractForeignJava8AnnotationsNoAnnotationInClasspathTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInJspecify() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jspecify"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); + } + } + @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java index 14d60102cf0..b6d85dbb4cb 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTestGenerated.java @@ -43,6 +43,24 @@ public class ForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTe runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); } + @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Jspecify extends AbstractForeignJava8AnnotationsNoAnnotationInClasspathWithPsiClassReadingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInJspecify() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jspecify"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); + } + } + @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java index 3efefa0725f..2c0a8de967c 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/ForeignJava8AnnotationsTestGenerated.java @@ -43,6 +43,24 @@ public class ForeignJava8AnnotationsTestGenerated extends AbstractForeignJava8An runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); } + @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Jspecify extends AbstractForeignJava8AnnotationsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInJspecify() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jspecify"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); + } + } + @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java index e60a35f8a82..4241e260506 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/checkers/javac/JavacForeignJava8AnnotationsTestGenerated.java @@ -43,6 +43,24 @@ public class JavacForeignJava8AnnotationsTestGenerated extends AbstractJavacFore runTest("compiler/testData/foreignAnnotationsJava8/tests/typeUseOnObject.kt"); } + @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jspecify") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Jspecify extends AbstractJavacForeignJava8AnnotationsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInJspecify() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/foreignAnnotationsJava8/tests/jspecify"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/foreignAnnotationsJava8/tests/jspecify/simple.kt"); + } + } + @TestMetadata("compiler/testData/foreignAnnotationsJava8/tests/jsr305") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.kt index f4fae096123..fd5e33ecad6 100644 --- a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.kt +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAnnotationNames.kt @@ -18,7 +18,15 @@ package org.jetbrains.kotlin.load.java import org.jetbrains.kotlin.name.FqName -val NULLABLE_ANNOTATIONS: List = listOf( +val JSPECIFY_NULLABLE = FqName("jspecify.annotations.Nullable") +val JSPECIFY_NOT_NULL = FqName("jspecify.annotations.NotNull") +val JSPECIFY_NULLNESS_UNKNOWN = FqName("jspecify.annotations.NullnessUnknown") + +val JSPECIFY_DEFAULT_NULLABLE = FqName("jspecify.annotations.DefaultNullable") +val JSPECIFY_DEFAULT_NOT_NULL = FqName("jspecify.annotations.DefaultNotNull") +val JSPECIFY_DEFAULT_NULLNESS_UNKNOWN = FqName("jspecify.annotations.DefaultNullnessUnknown") + +val NULLABLE_ANNOTATIONS = listOf( JvmAnnotationNames.JETBRAINS_NULLABLE_ANNOTATION, FqName("androidx.annotation.Nullable"), FqName("android.support.annotation.Nullable"), @@ -31,13 +39,14 @@ val NULLABLE_ANNOTATIONS: List = listOf( FqName("edu.umd.cs.findbugs.annotations.CheckForNull"), FqName("edu.umd.cs.findbugs.annotations.Nullable"), FqName("edu.umd.cs.findbugs.annotations.PossiblyNull"), - FqName("io.reactivex.annotations.Nullable") + FqName("io.reactivex.annotations.Nullable"), + JSPECIFY_NULLABLE ) -val JAVAX_NONNULL_ANNOTATION: FqName = FqName("javax.annotation.Nonnull") -val JAVAX_CHECKFORNULL_ANNOTATION: FqName = FqName("javax.annotation.CheckForNull") +val JAVAX_NONNULL_ANNOTATION = FqName("javax.annotation.Nonnull") +val JAVAX_CHECKFORNULL_ANNOTATION = FqName("javax.annotation.CheckForNull") -val NOT_NULL_ANNOTATIONS: List = listOf( +val NOT_NULL_ANNOTATIONS = listOf( JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION, FqName("edu.umd.cs.findbugs.annotations.NonNull"), FqName("androidx.annotation.NonNull"), @@ -47,30 +56,37 @@ val NOT_NULL_ANNOTATIONS: List = listOf( FqName("org.eclipse.jdt.annotation.NonNull"), FqName("org.checkerframework.checker.nullness.qual.NonNull"), FqName("lombok.NonNull"), - FqName("io.reactivex.annotations.NonNull") + FqName("io.reactivex.annotations.NonNull"), + JSPECIFY_NOT_NULL ) -val COMPATQUAL_NULLABLE_ANNOTATION: FqName = FqName("org.checkerframework.checker.nullness.compatqual.NullableDecl") -val COMPATQUAL_NONNULL_ANNOTATION: FqName = FqName("org.checkerframework.checker.nullness.compatqual.NonNullDecl") +val COMPATQUAL_NULLABLE_ANNOTATION = FqName("org.checkerframework.checker.nullness.compatqual.NullableDecl") +val COMPATQUAL_NONNULL_ANNOTATION = FqName("org.checkerframework.checker.nullness.compatqual.NonNullDecl") -val ANDROIDX_RECENTLY_NULLABLE_ANNOTATION: FqName = FqName("androidx.annotation.RecentlyNullable") -val ANDROIDX_RECENTLY_NON_NULL_ANNOTATION: FqName = FqName("androidx.annotation.RecentlyNonNull") +val ANDROIDX_RECENTLY_NULLABLE_ANNOTATION = FqName("androidx.annotation.RecentlyNullable") +val ANDROIDX_RECENTLY_NON_NULL_ANNOTATION = FqName("androidx.annotation.RecentlyNonNull") -val NULLABILITY_ANNOTATIONS: Set = mutableSetOf() + +val NULLABILITY_ANNOTATIONS = mutableSetOf() + NULLABLE_ANNOTATIONS + JAVAX_NONNULL_ANNOTATION + NOT_NULL_ANNOTATIONS + COMPATQUAL_NULLABLE_ANNOTATION + COMPATQUAL_NONNULL_ANNOTATION + ANDROIDX_RECENTLY_NULLABLE_ANNOTATION + - ANDROIDX_RECENTLY_NON_NULL_ANNOTATION + ANDROIDX_RECENTLY_NON_NULL_ANNOTATION + + JSPECIFY_NULLABLE + + JSPECIFY_NOT_NULL + + JSPECIFY_NULLNESS_UNKNOWN + + JSPECIFY_DEFAULT_NULLABLE + + JSPECIFY_DEFAULT_NOT_NULL + + JSPECIFY_DEFAULT_NULLNESS_UNKNOWN -val READ_ONLY_ANNOTATIONS: List = listOf( +val READ_ONLY_ANNOTATIONS = listOf( JvmAnnotationNames.JETBRAINS_READONLY_ANNOTATION, JvmAnnotationNames.READONLY_ANNOTATION ) -val MUTABLE_ANNOTATIONS: List = listOf( +val MUTABLE_ANNOTATIONS = listOf( JvmAnnotationNames.JETBRAINS_MUTABLE_ANNOTATION, JvmAnnotationNames.MUTABLE_ANNOTATION ) diff --git a/third-party/jdk8-annotations/jspecify/annotations/DefaultNotNull.java b/third-party/jdk8-annotations/jspecify/annotations/DefaultNotNull.java new file mode 100644 index 00000000000..975baa347be --- /dev/null +++ b/third-party/jdk8-annotations/jspecify/annotations/DefaultNotNull.java @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package jspecify.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface DefaultNotNull { + +} diff --git a/third-party/jdk8-annotations/jspecify/annotations/DefaultNullable.java b/third-party/jdk8-annotations/jspecify/annotations/DefaultNullable.java new file mode 100644 index 00000000000..d7bc86d5ca4 --- /dev/null +++ b/third-party/jdk8-annotations/jspecify/annotations/DefaultNullable.java @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package jspecify.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface DefaultNullable { + +} diff --git a/third-party/jdk8-annotations/jspecify/annotations/DefaultNullnessUnknown.java b/third-party/jdk8-annotations/jspecify/annotations/DefaultNullnessUnknown.java new file mode 100644 index 00000000000..da18425e8de --- /dev/null +++ b/third-party/jdk8-annotations/jspecify/annotations/DefaultNullnessUnknown.java @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package jspecify.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface DefaultNullnessUnknown { + +} diff --git a/third-party/jdk8-annotations/jspecify/annotations/NotNull.java b/third-party/jdk8-annotations/jspecify/annotations/NotNull.java new file mode 100644 index 00000000000..73ca7121955 --- /dev/null +++ b/third-party/jdk8-annotations/jspecify/annotations/NotNull.java @@ -0,0 +1,11 @@ +package jspecify.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface NotNull { + +} diff --git a/third-party/jdk8-annotations/jspecify/annotations/Nullable.java b/third-party/jdk8-annotations/jspecify/annotations/Nullable.java new file mode 100644 index 00000000000..f14b0abf0f9 --- /dev/null +++ b/third-party/jdk8-annotations/jspecify/annotations/Nullable.java @@ -0,0 +1,11 @@ +package jspecify.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface Nullable { + +} diff --git a/third-party/jdk8-annotations/jspecify/annotations/UnknownNullness.java b/third-party/jdk8-annotations/jspecify/annotations/UnknownNullness.java new file mode 100644 index 00000000000..a2eb39f140d --- /dev/null +++ b/third-party/jdk8-annotations/jspecify/annotations/UnknownNullness.java @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package jspecify.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface UnknownNullness { + +}