[FIR] Report UNSUPPORTED on array literals not from annotation classes ^KT-50750 Fixed
This commit is contained in:
+5
@@ -147,4 +147,9 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
|||||||
get() = setOf(
|
get() = setOf(
|
||||||
FirEqualityCompatibilityChecker,
|
FirEqualityCompatibilityChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override val arrayOfCallCheckers: Set<FirArrayOfCallChecker>
|
||||||
|
get() = setOf(
|
||||||
|
FirUnsupportedArrayLiteralChecker
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+90
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
annotation class AnnE(val i: String)
|
||||||
|
|
||||||
|
enum class MyEnum {
|
||||||
|
A
|
||||||
|
}
|
||||||
|
|
||||||
|
@AnnE(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>"1" + MyEnum.A<!>)
|
||||||
|
class Test
|
||||||
|
|
||||||
|
@AnnE(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>"1" + MyEnum::class<!>)
|
||||||
|
class Test2
|
||||||
|
|
||||||
|
@AnnE(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>"1" + AnnE("23")<!>)
|
||||||
|
class Test3
|
||||||
|
|
||||||
|
@AnnE(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>"1" + <!UNSUPPORTED!>arrayOf("23", "34")<!><!>)
|
||||||
|
class Test4
|
||||||
|
|
||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// FIR_IDENTICAL
|
|
||||||
annotation class AnnE(val i: String)
|
annotation class AnnE(val i: String)
|
||||||
|
|
||||||
enum class MyEnum {
|
enum class MyEnum {
|
||||||
|
|||||||
Vendored
-48
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// LANGUAGE: +ProhibitArrayLiteralsInCompanionOfAnnotation
|
// LANGUAGE: +ProhibitArrayLiteralsInCompanionOfAnnotation
|
||||||
// ISSUE: KT-39041
|
// ISSUE: KT-39041
|
||||||
|
|
||||||
|
|||||||
Vendored
+13
-13
@@ -3,46 +3,46 @@
|
|||||||
|
|
||||||
annotation class Ann(val x: IntArray = [1, 2, 3]) { // OK
|
annotation class Ann(val x: IntArray = [1, 2, 3]) { // OK
|
||||||
companion object {
|
companion object {
|
||||||
val y1: IntArray = [1, 2, 3] // Error
|
val y1: IntArray = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
|
|
||||||
val z1: IntArray
|
val z1: IntArray
|
||||||
get() = [1, 2, 3] // Error
|
get() = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
|
|
||||||
fun test_1(): IntArray {
|
fun test_1(): IntArray {
|
||||||
return [1, 2, 3] // Error
|
return <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
}
|
}
|
||||||
|
|
||||||
class Nested {
|
class Nested {
|
||||||
val y2: IntArray = [1, 2, 3] // Error
|
val y2: IntArray = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
|
|
||||||
val z2: IntArray
|
val z2: IntArray
|
||||||
get() = [1, 2, 3] // Error
|
get() = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
|
|
||||||
fun test_2(): IntArray {
|
fun test_2(): IntArray {
|
||||||
return [1, 2, 3] // Error
|
return <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Foo {
|
object Foo {
|
||||||
val y3: IntArray = [1, 2, 3] // Error
|
val y3: IntArray = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
|
|
||||||
val z3: IntArray
|
val z3: IntArray
|
||||||
get() = [1, 2, 3] // Error
|
get() = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
|
|
||||||
fun test_3(): IntArray {
|
fun test_3(): IntArray {
|
||||||
return [1, 2, 3] // Error
|
return <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Nested {
|
class Nested {
|
||||||
val y4: IntArray = [1, 2, 3] // Error
|
val y4: IntArray = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
|
|
||||||
val z4: IntArray
|
val z4: IntArray
|
||||||
get() = [1, 2, 3] // Error
|
get() = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
|
|
||||||
fun test_4(): IntArray {
|
fun test_4(): IntArray {
|
||||||
return [1, 2, 3] // Error
|
return <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsOutsideOfAnnotations.fir.kt
Vendored
-21
@@ -1,21 +0,0 @@
|
|||||||
// !LANGUAGE: +NewInference
|
|
||||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
|
||||||
|
|
||||||
fun takeArray(array: Array<String>) {}
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
"foo bar".<!UNRESOLVED_REFERENCE!>split<!>([""])
|
|
||||||
<!UNRESOLVED_REFERENCE!>unresolved<!>([""])
|
|
||||||
takeArray([""])
|
|
||||||
val v = [""]
|
|
||||||
[""]
|
|
||||||
[1, 2, 3].size
|
|
||||||
}
|
|
||||||
|
|
||||||
fun baz(arg: Array<Int> = []) {
|
|
||||||
if (true) ["yes"] else {["no"]}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Foo(
|
|
||||||
val v: Array<Int> = []
|
|
||||||
)
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !LANGUAGE: +NewInference
|
// !LANGUAGE: +NewInference
|
||||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -1,15 +1,15 @@
|
|||||||
fun test(): Array<Int> {
|
fun test(): Array<Int> {
|
||||||
[1, 2]
|
<!UNSUPPORTED!>[1, 2]<!>
|
||||||
[1, 2][0]
|
<!UNSUPPORTED!>[1, 2]<!>[0]
|
||||||
[1, 2].get(0)
|
<!UNSUPPORTED!>[1, 2]<!>.get(0)
|
||||||
|
|
||||||
foo([""])
|
foo(<!UNSUPPORTED!>[""]<!>)
|
||||||
|
|
||||||
val p = [1, 2] <!UNRESOLVED_REFERENCE!>+<!> [3, 4]
|
val p = <!UNSUPPORTED!>[1, 2]<!> <!UNRESOLVED_REFERENCE!>+<!> <!UNSUPPORTED!>[3, 4]<!>
|
||||||
|
|
||||||
return [1, 2]
|
return <!UNSUPPORTED!>[1, 2]<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun foo(a: Array<String> = [""]) {}
|
fun foo(a: Array<String> = <!UNSUPPORTED!>[""]<!>) {}
|
||||||
|
|
||||||
class A(val a: Array<Int> = [])
|
class A(val a: Array<Int> = <!UNSUPPORTED!>[]<!>)
|
||||||
|
|||||||
Vendored
+2
-2
@@ -3,5 +3,5 @@
|
|||||||
fun foo(l: () -> Unit) {}
|
fun foo(l: () -> Unit) {}
|
||||||
fun bar(l: () -> String) {}
|
fun bar(l: () -> String) {}
|
||||||
|
|
||||||
val a = foo { [] }
|
val a = foo { <!UNSUPPORTED!>[]<!> }
|
||||||
val b = bar { [] }
|
val b = bar { <!UNSUPPORTED!>[]<!> }
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ annotation class Ann(val i: IntArray)
|
|||||||
@Ann(intArrayOf(i2))
|
@Ann(intArrayOf(i2))
|
||||||
@Ann(<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)<!>)
|
@Ann(<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)<!>)
|
||||||
@Ann(<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i<!>, i2, <!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)<!>)
|
@Ann(<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i<!>, i2, <!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)<!>)
|
||||||
@Ann(<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ARGUMENT_TYPE_MISMATCH, NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i<!>, i2, <!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)<!>)<!>)
|
@Ann(<!NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION!>intArrayOf(<!ARGUMENT_TYPE_MISMATCH, NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION, UNSUPPORTED!>intArrayOf(<!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i<!>, i2, <!ANNOTATION_ARGUMENT_MUST_BE_CONST!>i3<!>)<!>)<!>)
|
||||||
class Test
|
class Test
|
||||||
|
|
||||||
var i = 1
|
var i = 1
|
||||||
|
|||||||
Reference in New Issue
Block a user