From 73b45a12545092e27f58524f2f3060c8cf894490 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Wed, 9 Feb 2022 17:14:23 +0300 Subject: [PATCH] [FIR] Report UNSUPPORTED on array literals not from annotation classes ^KT-50750 Fixed --- .../checkers/CommonExpressionCheckers.kt | 5 ++ .../FirUnsupportedArrayLiteralChecker.kt | 90 +++++++++++++++++++ .../standaloneInExpression.fir.kt | 18 ++++ .../standaloneInExpression.kt | 1 - ...yLiteralInAnnotationCompanion_after.fir.kt | 48 ---------- ...arrayLiteralInAnnotationCompanion_after.kt | 1 + ...LiteralInAnnotationCompanion_before.fir.kt | 26 +++--- ...lectionLiteralsOutsideOfAnnotations.fir.kt | 21 ----- .../collectionLiteralsOutsideOfAnnotations.kt | 1 + .../noCollectionLiterals.fir.kt | 16 ++-- ...esolveCollectionLiteralInsideLambda.fir.kt | 4 +- .../array.fir.kt | 2 +- 12 files changed, 139 insertions(+), 94 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUnsupportedArrayLiteralChecker.kt create mode 100644 compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_after.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsOutsideOfAnnotations.fir.kt diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt index 76fafec0b2a..f5ba79f8fbc 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt @@ -147,4 +147,9 @@ object CommonExpressionCheckers : ExpressionCheckers() { get() = setOf( FirEqualityCompatibilityChecker, ) + + override val arrayOfCallCheckers: Set + get() = setOf( + FirUnsupportedArrayLiteralChecker + ) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUnsupportedArrayLiteralChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUnsupportedArrayLiteralChecker.kt new file mode 100644 index 00000000000..0ad84fe236b --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUnsupportedArrayLiteralChecker.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2022 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.expression + +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor +import org.jetbrains.kotlin.fir.declarations.utils.isCompanion +import org.jetbrains.kotlin.fir.expressions.* + +object FirUnsupportedArrayLiteralChecker : FirArrayOfCallChecker() { + override fun check(expression: FirArrayOfCall, context: CheckerContext, reporter: DiagnosticReporter) { + if (!isInsideAnnotationCall(expression, context) && + (context.qualifiedAccessOrAnnotationCalls.isNotEmpty() || !isInsideAnnotationClass(context)) + ) { + reporter.reportOn( + expression.source, + FirErrors.UNSUPPORTED, + "Collection literals outside of annotations", + context + ) + } + } + + private fun isInsideAnnotationCall(expression: FirArrayOfCall, context: CheckerContext): Boolean { + context.qualifiedAccessOrAnnotationCalls.lastOrNull()?.let { + val arguments = when (it) { + is FirFunctionCall -> + if (it.typeRef.toRegularClassSymbol(context.session)?.classKind == ClassKind.ANNOTATION_CLASS) { + it.arguments + } else { + return false + } + is FirAnnotationCall -> it.arguments + else -> return false + } + + return arguments.any { argument -> + val unwrappedArguments = + if (argument is FirVarargArgumentsExpression) { + argument.arguments.map { arg -> arg.unwrapArgument() } + } else { + listOf(argument.unwrapArgument()) + } + + for (unwrapped in unwrappedArguments) { + if (unwrapped == expression || + unwrapped is FirArrayOfCall && + unwrapped.arguments.any { arrayOfCallElement -> arrayOfCallElement.unwrapArgument() == expression } + ) { + return@any true + } + } + + return@any false + } + } + + return false + } + + private fun isInsideAnnotationClass(context: CheckerContext): Boolean { + for (declaration in context.containingDeclarations.asReversed()) { + if (declaration is FirRegularClass) { + if (declaration.isCompanion) { + continue + } + + if (declaration.classKind == ClassKind.ANNOTATION_CLASS) { + return true + } + } else if (declaration is FirValueParameter || declaration is FirPrimaryConstructor) { + continue + } + + break + } + + return false + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.fir.kt b/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.fir.kt new file mode 100644 index 00000000000..20a40bd64dc --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.fir.kt @@ -0,0 +1,18 @@ +annotation class AnnE(val i: String) + +enum class MyEnum { + A +} + +@AnnE("1" + MyEnum.A) +class Test + +@AnnE("1" + MyEnum::class) +class Test2 + +@AnnE("1" + AnnE("23")) +class Test3 + +@AnnE("1" + arrayOf("23", "34")) +class Test4 + diff --git a/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.kt b/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.kt index f9f9e533d54..abb407b4f6c 100644 --- a/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.kt +++ b/compiler/testData/diagnostics/tests/annotations/annotationParameterMustBeConstant/standaloneInExpression.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL annotation class AnnE(val i: String) enum class MyEnum { diff --git a/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_after.fir.kt b/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_after.fir.kt deleted file mode 100644 index 12e6783c531..00000000000 --- a/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_after.fir.kt +++ /dev/null @@ -1,48 +0,0 @@ -// LANGUAGE: +ProhibitArrayLiteralsInCompanionOfAnnotation -// ISSUE: KT-39041 - -annotation class Ann(val x: IntArray = [1, 2, 3]) { // OK - companion object { - val y1: IntArray = [1, 2, 3] // Error - - val z1: IntArray - get() = [1, 2, 3] // Error - - fun test_1(): IntArray { - return [1, 2, 3] // Error - } - - class Nested { - val y2: IntArray = [1, 2, 3] // Error - - val z2: IntArray - get() = [1, 2, 3] // Error - - fun test_2(): IntArray { - return [1, 2, 3] // Error - } - } - } - - object Foo { - val y3: IntArray = [1, 2, 3] // Error - - val z3: IntArray - get() = [1, 2, 3] // Error - - fun test_3(): IntArray { - return [1, 2, 3] // Error - } - } - - class Nested { - val y4: IntArray = [1, 2, 3] // Error - - val z4: IntArray - get() = [1, 2, 3] // Error - - fun test_4(): IntArray { - return [1, 2, 3] // Error - } - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_after.kt b/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_after.kt index 37859a12253..549ccbd36f9 100644 --- a/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_after.kt +++ b/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_after.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // LANGUAGE: +ProhibitArrayLiteralsInCompanionOfAnnotation // ISSUE: KT-39041 diff --git a/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_before.fir.kt b/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_before.fir.kt index 675a9b25d30..ccba2e03ecf 100644 --- a/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_before.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/arrayLiteralInAnnotationCompanion_before.fir.kt @@ -3,46 +3,46 @@ annotation class Ann(val x: IntArray = [1, 2, 3]) { // OK companion object { - val y1: IntArray = [1, 2, 3] // Error + val y1: IntArray = [1, 2, 3] // Error val z1: IntArray - get() = [1, 2, 3] // Error + get() = [1, 2, 3] // Error fun test_1(): IntArray { - return [1, 2, 3] // Error + return [1, 2, 3] // Error } class Nested { - val y2: IntArray = [1, 2, 3] // Error + val y2: IntArray = [1, 2, 3] // Error val z2: IntArray - get() = [1, 2, 3] // Error + get() = [1, 2, 3] // Error fun test_2(): IntArray { - return [1, 2, 3] // Error + return [1, 2, 3] // Error } } } object Foo { - val y3: IntArray = [1, 2, 3] // Error + val y3: IntArray = [1, 2, 3] // Error val z3: IntArray - get() = [1, 2, 3] // Error + get() = [1, 2, 3] // Error fun test_3(): IntArray { - return [1, 2, 3] // Error + return [1, 2, 3] // Error } } class Nested { - val y4: IntArray = [1, 2, 3] // Error + val y4: IntArray = [1, 2, 3] // Error val z4: IntArray - get() = [1, 2, 3] // Error + get() = [1, 2, 3] // Error fun test_4(): IntArray { - return [1, 2, 3] // Error + return [1, 2, 3] // Error } } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsOutsideOfAnnotations.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsOutsideOfAnnotations.fir.kt deleted file mode 100644 index 9b0241c016f..00000000000 --- a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsOutsideOfAnnotations.fir.kt +++ /dev/null @@ -1,21 +0,0 @@ -// !LANGUAGE: +NewInference -// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER - -fun takeArray(array: Array) {} - -fun test() { - "foo bar".split([""]) - unresolved([""]) - takeArray([""]) - val v = [""] - [""] - [1, 2, 3].size -} - -fun baz(arg: Array = []) { - if (true) ["yes"] else {["no"]} -} - -class Foo( - val v: Array = [] -) diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsOutsideOfAnnotations.kt b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsOutsideOfAnnotations.kt index 79955940594..4a741d80718 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsOutsideOfAnnotations.kt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsOutsideOfAnnotations.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +NewInference // !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/noCollectionLiterals.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/noCollectionLiterals.fir.kt index 1eef9de37b8..60fea642d68 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/noCollectionLiterals.fir.kt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/noCollectionLiterals.fir.kt @@ -1,15 +1,15 @@ fun test(): Array { - [1, 2] - [1, 2][0] - [1, 2].get(0) + [1, 2] + [1, 2][0] + [1, 2].get(0) - foo([""]) + foo([""]) - val p = [1, 2] + [3, 4] + val p = [1, 2] + [3, 4] - return [1, 2] + return [1, 2] } -fun foo(a: Array = [""]) {} +fun foo(a: Array = [""]) {} -class A(val a: Array = []) +class A(val a: Array = []) diff --git a/compiler/testData/diagnostics/tests/regressions/resolveCollectionLiteralInsideLambda.fir.kt b/compiler/testData/diagnostics/tests/regressions/resolveCollectionLiteralInsideLambda.fir.kt index 00fae356ed0..320ab3f96a4 100644 --- a/compiler/testData/diagnostics/tests/regressions/resolveCollectionLiteralInsideLambda.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/resolveCollectionLiteralInsideLambda.fir.kt @@ -3,5 +3,5 @@ fun foo(l: () -> Unit) {} fun bar(l: () -> String) {} -val a = foo { [] } -val b = bar { [] } \ No newline at end of file +val a = foo { [] } +val b = bar { [] } diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.fir.kt index e97514f7769..69debb93c1b 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant/array.fir.kt @@ -6,7 +6,7 @@ annotation class Ann(val i: IntArray) @Ann(intArrayOf(i2)) @Ann(intArrayOf(i3)) @Ann(intArrayOf(i, i2, i3)) -@Ann(intArrayOf(intArrayOf(i, i2, i3))) +@Ann(intArrayOf(intArrayOf(i, i2, i3))) class Test var i = 1