diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 527c4d6e58e..8b56bc98933 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -681,6 +681,7 @@ public interface Errors { DiagnosticFactory0 ACTUAL_MISSING = DiagnosticFactory0.create(ERROR, ACTUAL_DECLARATION_NAME); DiagnosticFactory0 OPTIONAL_EXPECTATION_NOT_ON_EXPECTED = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 NESTED_OPTIONAL_EXPECTATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 31b16ee8149..c5c8c113eb3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -306,6 +306,7 @@ public class DefaultErrorMessages { MAP.put(ACTUAL_MISSING, "Declaration must be marked with 'actual'"); MAP.put(OPTIONAL_EXPECTATION_NOT_ON_EXPECTED, "'@OptionalExpectation' can only be used on an expected annotation class"); + MAP.put(NESTED_OPTIONAL_EXPECTATION, "'@OptionalExpectation' cannot be used on a nested class"); MAP.put(OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY, "Declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry"); MAP.put(OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE, "Declaration annotated with '@OptionalExpectation' can only be used in common module sources"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java index aeef55c395e..d9d3c71ed6d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java @@ -276,7 +276,7 @@ public class ModifiersChecker { } OperatorModifierChecker.INSTANCE.check(declaration, descriptor, trace, languageVersionSettings); PublishedApiUsageChecker.INSTANCE.check(declaration, descriptor, trace); - OptionalExpectationTargetChecker.INSTANCE.check(declaration, descriptor, trace); + OptionalExpectationChecker.INSTANCE.check(declaration, descriptor, trace); } public void checkTypeParametersModifiers(@NotNull KtModifierListOwner modifierListOwner) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt new file mode 100644 index 00000000000..8a03c699f33 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2018 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 org.jetbrains.kotlin.resolve.checkers + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.MemberDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.KtAnnotationEntry +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.DescriptorUtils + +object OptionalExpectationChecker { + fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, trace: BindingTrace) { + val isExpect = descriptor is MemberDescriptor && descriptor.isExpect + if (isExpect) { + if (DescriptorUtils.isAnnotationClass(descriptor) && descriptor.containingDeclaration !is PackageFragmentDescriptor) { + getOptionalExpectationEntry(declaration, trace)?.let { + trace.report(Errors.NESTED_OPTIONAL_EXPECTATION.on(it)) + } + } + } else { + getOptionalExpectationEntry(declaration, trace)?.let { + trace.report(Errors.OPTIONAL_EXPECTATION_NOT_ON_EXPECTED.on(it)) + } + } + } + + private fun getOptionalExpectationEntry(declaration: KtDeclaration, trace: BindingTrace): KtAnnotationEntry? = + declaration.annotationEntries.find { entry -> + val annotationDescriptor = trace.get(BindingContext.ANNOTATION, entry) + annotationDescriptor?.fqName == ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationTargetChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationTargetChecker.kt deleted file mode 100644 index 4e40be90197..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationTargetChecker.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010-2018 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 org.jetbrains.kotlin.resolve.checkers - -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.MemberDescriptor -import org.jetbrains.kotlin.diagnostics.Errors -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.BindingTrace - -object OptionalExpectationTargetChecker { - fun check( - declaration: KtDeclaration, - descriptor: DeclarationDescriptor, - trace: BindingTrace - ) { - if (descriptor is MemberDescriptor && descriptor.isExpect) return - - for (entry in declaration.annotationEntries) { - val annotationDescriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue - if (annotationDescriptor.fqName == ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME) { - trace.report(Errors.OPTIONAL_EXPECTATION_NOT_ON_EXPECTED.on(entry)) - } - } - } -} diff --git a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt index 5b0b11d7d42..709dd725e5f 100644 --- a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt +++ b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt @@ -18,3 +18,10 @@ annotation class InOtherAnnotation(val a: A) @InOtherAnnotation(A()) fun useInOtherAnnotation() {} + + + +expect class C { + @OptionalExpectation + annotation class Nested +} diff --git a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt index fa2b69af303..b9e13920d44 100644 --- a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt +++ b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt @@ -4,3 +4,7 @@ annotation class AnotherAnnotation(val a: A) @AnotherAnnotation(A()) fun useInAnotherAnnotation() {} + +actual class C { + actual annotation class Nested +} diff --git a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/output.txt b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/output.txt index d3f482bea17..7b44c395564 100644 --- a/compiler/testData/multiplatform/optionalExpectationIncorrectUse/output.txt +++ b/compiler/testData/multiplatform/optionalExpectationIncorrectUse/output.txt @@ -16,6 +16,9 @@ annotation class InOtherAnnotation(val a: A) compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:19:20: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry @InOtherAnnotation(A()) ^ +compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:25:5: error: '@OptionalExpectation' cannot be used on a nested class + @OptionalExpectation + ^ -- JVM -- Exit code: COMPILATION_ERROR @@ -38,6 +41,9 @@ annotation class InOtherAnnotation(val a: A) compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:19:20: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry @InOtherAnnotation(A()) ^ +compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:25:5: error: '@OptionalExpectation' cannot be used on a nested class + @OptionalExpectation + ^ compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:1:24: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry fun useInReturnType(): A? = null ^