From a4af9dd5d16140cbd8939cd72ffcf929f85bd152 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 7 Feb 2018 16:20:47 +0100 Subject: [PATCH] Always consider container's experimentality in ExperimentalUsageChecker This results in more diagnostics usually, but allows library authors to avoid annotating everything in each experimental class with the marker (only the class needs to be annotated now) #KT-22759 --- .../checkers/ExperimentalUsageChecker.kt | 4 +- .../experimental/deeplyNestedClass.kt | 61 +++++++++++++++ .../experimental/deeplyNestedClass.txt | 76 +++++++++++++++++++ .../DiagnosticsTestWithStdLibGenerated.java | 6 ++ ...ticsTestWithStdLibUsingJavacGenerated.java | 6 ++ 5 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt index 776c773e835..c9dbfb21593 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt @@ -142,9 +142,7 @@ class ExperimentalUsageChecker(project: Project) : CallChecker { val container = containingDeclaration if (container is ClassDescriptor && this !is ConstructorDescriptor) { - for (annotation in container.annotations) { - result.addIfNotNull(annotation.annotationClass?.loadExperimentalityForMarkerAnnotation()) - } + result.addAll(container.loadExperimentalities(moduleAnnotationsResolver)) } for (moduleAnnotationClassId in moduleAnnotationsResolver.getAnnotationsOnContainingModule(this)) { diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.kt b/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.kt new file mode 100644 index 00000000000..62cac35f0e1 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.kt @@ -0,0 +1,61 @@ +// !API_VERSION: 1.3 +// MODULE: api +// FILE: api.kt + +package api + +@Experimental(Experimental.Level.WARNING, [Experimental.Impact.COMPILATION]) +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) +annotation class ExperimentalAPI + +@ExperimentalAPI +class C { + class D { + class E { + class F + } + } +} + +// MODULE: usage1(api) +// FILE: usage-propagate.kt + +package usage1 + +import api.* + +@ExperimentalAPI +fun use1() { + C.D.E.F() +} + +@ExperimentalAPI +fun use2(f: C.D.E.F) = f.hashCode() + +// MODULE: usage2(api) +// FILE: usage-use.kt + +package usage2 + +import api.* + +@UseExperimental(ExperimentalAPI::class) +fun use1() { + C.D.E.F() +} + +@UseExperimental(ExperimentalAPI::class) +fun use2(f: C.D.E.F) = f.hashCode() + +// MODULE: usage3(api) +// FILE: usage-none.kt + +package usage3 + +import api.* + +fun use1() { + C.D.E.F() +} + +fun use2(f: C.D.E.F) = f.hashCode() diff --git a/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.txt b/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.txt new file mode 100644 index 00000000000..306bb5b8103 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.txt @@ -0,0 +1,76 @@ +// -- Module: -- +package + +package api { + + @api.ExperimentalAPI public final class C { + public constructor C() + 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 + + public final class D { + public constructor D() + 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 + + public final class E { + public constructor E() + 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 + + public final class F { + public constructor F() + 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.Experimental(changesMayBreak = {Impact.COMPILATION}, level = Level.WARNING) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION}) public final annotation class ExperimentalAPI : kotlin.Annotation { + public constructor ExperimentalAPI() + 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 + } +} + + +// -- Module: -- +package + +package api { +} + +package usage1 { + @api.ExperimentalAPI public fun use1(): kotlin.Unit + @api.ExperimentalAPI public fun use2(/*0*/ f: api.C.D.E.F): kotlin.Int +} + + +// -- Module: -- +package + +package api { +} + +package usage2 { + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public fun use1(): kotlin.Unit + @kotlin.UseExperimental(markerClass = {api.ExperimentalAPI::class}) public fun use2(/*0*/ f: api.C.D.E.F): kotlin.Int +} + + +// -- Module: -- +package + +package api { +} + +package usage3 { + public fun use1(): kotlin.Unit + public fun use2(/*0*/ f: api.C.D.E.F): kotlin.Int +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 73aec19c76d..9b37d742940 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -1839,6 +1839,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } + @TestMetadata("deeplyNestedClass.kt") + public void testDeeplyNestedClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.kt"); + doTest(fileName); + } + @TestMetadata("errors.kt") public void testErrors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/errors.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index b6733823c02..9030d9b3209 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -1839,6 +1839,12 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno doTest(fileName); } + @TestMetadata("deeplyNestedClass.kt") + public void testDeeplyNestedClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/deeplyNestedClass.kt"); + doTest(fileName); + } + @TestMetadata("errors.kt") public void testErrors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/experimental/errors.kt");