diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt new file mode 100644 index 00000000000..7007a05b541 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt @@ -0,0 +1,7 @@ +annotation class A() { + constructor(s: Nothing?) {} + init {} + fun foo() {} + val bar: Nothing? + val baz get() = Unit +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.txt new file mode 100644 index 00000000000..ffdcb13fcba --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.txt @@ -0,0 +1,25 @@ +FILE: annotationClassMember.kt + public final annotation class A : R|kotlin/Annotation| { + public constructor(): R|A| { + super() + } + + public constructor(s: R|kotlin/Nothing?|): R|A| { + this() + } + + init { + } + + public final fun foo(): R|kotlin/Unit| { + } + + public final val bar: R|kotlin/Nothing?| + public get(): R|kotlin/Nothing?| + + public final val baz: R|kotlin/Unit| + public get(): R|kotlin/Unit| { + ^ Q|kotlin/Unit| + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt new file mode 100644 index 00000000000..c897e0dcda6 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt @@ -0,0 +1,8 @@ +fun foo() { + annotation class Ann + + @Anno class Local { + // There should also be NESTED_CLASS_NOT_ALLOWED report here. + annotation class Nested + } +} diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.txt new file mode 100644 index 00000000000..f36179ad115 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.txt @@ -0,0 +1,24 @@ +FILE: localAnnotationClass.kt + public final fun foo(): R|kotlin/Unit| { + local final annotation class Ann : R|kotlin/Annotation| { + public[local] constructor(): R|Ann| { + super() + } + + } + + @R|ERROR CLASS: Symbol not found, for `Anno`|() local final class Local : R|kotlin/Any| { + public[local] constructor(): R|Local| { + super() + } + + local final annotation class Nested : R|kotlin/Annotation| { + public[local] constructor(): R|Local.Nested| { + super() + } + + } + + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.kt new file mode 100644 index 00000000000..7cc5b967fa4 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.kt @@ -0,0 +1,4 @@ +annotation class A( + var a: Int, + b: String +) \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.txt new file mode 100644 index 00000000000..e5d28180f79 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.txt @@ -0,0 +1,11 @@ +FILE: valOnAnnotationParameter.kt + public final annotation class A : R|kotlin/Annotation| { + public constructor(a: R|kotlin/Int|, b: R|kotlin/String|): R|A| { + super() + } + + public final var a: R|kotlin/Int| = R|/a| + public get(): R|kotlin/Int| + public set(value: R|kotlin/Int|): R|kotlin/Unit| + + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index a481248a52e..54effa6cb82 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -855,6 +855,21 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { public void testSuperclassNotAccessibleFromInterface() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superclassNotAccessibleFromInterface.kt"); } + + @TestMetadata("annotationClassMember.kt") + public void testAnnotationClassMember() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt"); + } + + @TestMetadata("localAnnotationClass.kt") + public void testLocalAnnotationClass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt"); + } + + @TestMetadata("valOnAnnotationParameter.kt") + public void testValOnAnnotationParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.kt"); + } } @TestMetadata("compiler/fir/analysis-tests/testData/resolve/expresssions") diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index b6de05db993..0ec8f30495a 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -855,6 +855,21 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos public void testSuperclassNotAccessibleFromInterface() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superclassNotAccessibleFromInterface.kt"); } + + @TestMetadata("annotationClassMember.kt") + public void testAnnotationClassMember() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt"); + } + + @TestMetadata("localAnnotationClass.kt") + public void testLocalAnnotationClass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt"); + } + + @TestMetadata("valOnAnnotationParameter.kt") + public void testValOnAnnotationParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.kt"); + } } @TestMetadata("compiler/fir/analysis-tests/testData/resolve/expresssions") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt index 485d21c1e5e..fbb8a6ee34c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration object DeclarationCheckers { val DECLARATIONS: List> = listOf( + FirAnnotationClassDeclarationChecker, FirModifierChecker ) val MEMBER_DECLARATIONS: List> = DECLARATIONS + listOf( diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationClassDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationClassDeclarationChecker.kt new file mode 100644 index 00000000000..ad3702191ff --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationClassDeclarationChecker.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2010-2020 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.fir.analysis.checkers.declaration + +import com.intellij.lang.LighterASTNode +import com.intellij.openapi.util.Ref +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.ClassKind.ANNOTATION_CLASS +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0 +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.FirLightSourceElement +import org.jetbrains.kotlin.fir.FirPsiSourceElement +import org.jetbrains.kotlin.fir.FirSourceElement +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression +import org.jetbrains.kotlin.KtNodeTypes.FUN +import org.jetbrains.kotlin.lexer.KtTokens.VAL_KEYWORD +import org.jetbrains.kotlin.lexer.KtTokens.VAR_KEYWORD +import org.jetbrains.kotlin.psi.KtParameter + +object FirAnnotationClassDeclarationChecker : FirDeclarationChecker() { + override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration !is FirRegularClass) return + if (declaration.classKind != ANNOTATION_CLASS) return + if (declaration.isLocal) reporter.report(declaration.source, FirErrors.LOCAL_ANNOTATION_CLASS_ERROR) + for (it in declaration.declarations) { + when { + it is FirConstructor && it.isPrimary -> + for (parameter in it.valueParameters) + when (val parameterSourceElement = parameter.source) { + is FirPsiSourceElement<*> -> { + val parameterPsiElement = parameterSourceElement.psi as KtParameter + if (!parameterPsiElement.hasValOrVar()) + reporter.report(parameterSourceElement, FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER) + else if (parameterPsiElement.isMutable) + reporter.report(parameterSourceElement, FirErrors.VAR_ANNOTATION_PARAMETER) + } + is FirLightSourceElement -> { + val kidsRef = Ref>() + parameterSourceElement.tree.getChildren(parameterSourceElement.element, kidsRef) + if (kidsRef.get().any { it?.tokenType == VAR_KEYWORD }) + reporter.report(parameterSourceElement, FirErrors.VAR_ANNOTATION_PARAMETER) + else if (kidsRef.get().all { it?.tokenType != VAL_KEYWORD }) + reporter.report(parameterSourceElement, FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER) + } + } + it is FirRegularClass + || it is FirProperty && it.initializer is FirQualifiedAccessExpression + || it is FirSimpleFunction && it.source?.elementType != FUN -> { + // DO NOTHING + } + else -> reporter.report(it.source, FirErrors.ANNOTATION_CLASS_MEMBER) + } + } + + } + + private inline fun DiagnosticReporter.report( + source: T?, + factory: FirDiagnosticFactory0 + ) { + source?.let { report(factory.on(it)) } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt index de61757da2a..c72deae7e5b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt @@ -143,6 +143,10 @@ abstract class AbstractDiagnosticCollector( visitWithDeclaration(file) } + override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer) { + visitWithDeclaration(anonymousInitializer) + } + private fun visitWithDeclaration(declaration: FirDeclaration) { declaration.runComponents() withDeclaration(declaration) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt index 872821f74a8..08d4007a76a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt @@ -61,6 +61,10 @@ class DeclarationCheckersDiagnosticComponent(collector: AbstractDiagnosticCollec runCheck { DeclarationCheckers.DECLARATIONS.check(anonymousObject, data, it) } } + override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: CheckerContext) { + runCheck { DeclarationCheckers.DECLARATIONS.check(anonymousInitializer, data, it) } + } + private fun List>.check( declaration: D, context: CheckerContext, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 97d92c209b8..d592b59ecb5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -53,6 +53,11 @@ object FirErrors { val NON_PRIVATE_CONSTRUCTOR_IN_ENUM by existing(Errors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM) val NON_PRIVATE_CONSTRUCTOR_IN_SEALED by existing(Errors.NON_PRIVATE_CONSTRUCTOR_IN_SEALED) + val ANNOTATION_CLASS_MEMBER by existing(Errors.ANNOTATION_CLASS_MEMBER) + val LOCAL_ANNOTATION_CLASS_ERROR by existing(Errors.LOCAL_ANNOTATION_CLASS_ERROR) + val MISSING_VAL_ON_ANNOTATION_PARAMETER by existing(Errors.MISSING_VAL_ON_ANNOTATION_PARAMETER) + val VAR_ANNOTATION_PARAMETER by existing(Errors.VAR_ANNOTATION_PARAMETER) + // Exposed visibility group val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3() val EXPOSED_FUNCTION_RETURN_TYPE by error3() diff --git a/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_after.fir.kt b/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_after.fir.kt deleted file mode 100644 index db9574ebd15..00000000000 --- a/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_after.fir.kt +++ /dev/null @@ -1,31 +0,0 @@ -// !LANGUAGE: +NestedClassesInAnnotations - -annotation class Annotation2() { - public val s: String = "" -} - -annotation class Annotation3() { - public fun foo() {} -} - -annotation class Annotation4() { - class Foo() {} -} - -annotation class Annotation5() { - companion object {} -} - -annotation class Annotation6() { - init {} -} - -annotation class Annotation1() {} - -annotation class Annotation7(val name: String) {} - -annotation class Annotation8(var name: String = "") {} - -annotation class Annotation9(val name: String) - -annotation class Annotation10 diff --git a/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_after.kt b/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_after.kt index f659434ca30..c979c7ed8f5 100644 --- a/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_after.kt +++ b/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_after.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +NestedClassesInAnnotations annotation class Annotation2() { diff --git a/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_before.fir.kt b/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_before.fir.kt index 4f8115d7162..4d6bebd4ced 100644 --- a/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_before.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/kt1886annotationBody_before.fir.kt @@ -1,11 +1,11 @@ // !LANGUAGE: -NestedClassesInAnnotations annotation class Annotation2() { - public val s: String = "" + public val s: String = "" } annotation class Annotation3() { - public fun foo() {} + public fun foo() {} } annotation class Annotation4() { @@ -17,14 +17,14 @@ annotation class Annotation5() { } annotation class Annotation6() { - init {} + init {} } annotation class Annotation1() {} annotation class Annotation7(val name: String) {} -annotation class Annotation8(var name: String = "") {} +annotation class Annotation8(var name: String = "") {} annotation class Annotation9(val name: String) diff --git a/compiler/testData/diagnostics/tests/annotations/missingValOnParameter.fir.kt b/compiler/testData/diagnostics/tests/annotations/missingValOnParameter.fir.kt deleted file mode 100644 index 41d19140eb0..00000000000 --- a/compiler/testData/diagnostics/tests/annotations/missingValOnParameter.fir.kt +++ /dev/null @@ -1,5 +0,0 @@ -annotation class Ann( - val a: Int, - var b: Int, - c: String - ) diff --git a/compiler/testData/diagnostics/tests/annotations/missingValOnParameter.kt b/compiler/testData/diagnostics/tests/annotations/missingValOnParameter.kt index 178fe4ab723..2fa96168654 100644 --- a/compiler/testData/diagnostics/tests/annotations/missingValOnParameter.kt +++ b/compiler/testData/diagnostics/tests/annotations/missingValOnParameter.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL annotation class Ann( val a: Int, var b: Int, diff --git a/compiler/testData/diagnostics/tests/annotations/nestedClassesInAnnotations.fir.kt b/compiler/testData/diagnostics/tests/annotations/nestedClassesInAnnotations.fir.kt index b347ffd50f9..15ecebd3b50 100644 --- a/compiler/testData/diagnostics/tests/annotations/nestedClassesInAnnotations.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/nestedClassesInAnnotations.fir.kt @@ -16,8 +16,8 @@ annotation class Foo { } - constructor(s: Int) {} - init {} - fun function() {} - val property get() = Unit + constructor(s: Int) {} + init {} + fun function() {} + val property get() = Unit } diff --git a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClass.fir.kt b/compiler/testData/diagnostics/tests/localClasses/localAnnotationClass.fir.kt index f152deb620b..816f17a81b1 100644 --- a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClass.fir.kt +++ b/compiler/testData/diagnostics/tests/localClasses/localAnnotationClass.fir.kt @@ -1,9 +1,9 @@ // !LANGUAGE: -ProhibitLocalAnnotations fun f() { - annotation class Anno + annotation class Anno @Anno class Local { - annotation class Nested + annotation class Nested } } diff --git a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.fir.kt b/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.fir.kt index d8dac02ea1b..6237efead02 100644 --- a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.fir.kt +++ b/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.fir.kt @@ -1,9 +1,9 @@ // !LANGUAGE: +ProhibitLocalAnnotations fun f() { - annotation class Anno + annotation class Anno @Anno class Local { - annotation class Nested + annotation class Nested } }