[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(
|
||||
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)
|
||||
|
||||
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
|
||||
// ISSUE: KT-39041
|
||||
|
||||
|
||||
Vendored
+13
-13
@@ -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 = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
|
||||
val z1: IntArray
|
||||
get() = [1, 2, 3] // Error
|
||||
get() = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
|
||||
fun test_1(): IntArray {
|
||||
return [1, 2, 3] // Error
|
||||
return <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
}
|
||||
|
||||
class Nested {
|
||||
val y2: IntArray = [1, 2, 3] // Error
|
||||
val y2: IntArray = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
|
||||
val z2: IntArray
|
||||
get() = [1, 2, 3] // Error
|
||||
get() = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
|
||||
fun test_2(): IntArray {
|
||||
return [1, 2, 3] // Error
|
||||
return <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Foo {
|
||||
val y3: IntArray = [1, 2, 3] // Error
|
||||
val y3: IntArray = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
|
||||
val z3: IntArray
|
||||
get() = [1, 2, 3] // Error
|
||||
get() = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
|
||||
fun test_3(): IntArray {
|
||||
return [1, 2, 3] // Error
|
||||
return <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
}
|
||||
}
|
||||
|
||||
class Nested {
|
||||
val y4: IntArray = [1, 2, 3] // Error
|
||||
val y4: IntArray = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
|
||||
val z4: IntArray
|
||||
get() = [1, 2, 3] // Error
|
||||
get() = <!UNSUPPORTED!>[1, 2, 3]<!> // Error
|
||||
|
||||
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
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||
|
||||
|
||||
+8
-8
@@ -1,15 +1,15 @@
|
||||
fun test(): Array<Int> {
|
||||
[1, 2]
|
||||
[1, 2][0]
|
||||
[1, 2].get(0)
|
||||
<!UNSUPPORTED!>[1, 2]<!>
|
||||
<!UNSUPPORTED!>[1, 2]<!>[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 bar(l: () -> String) {}
|
||||
|
||||
val a = foo { [] }
|
||||
val b = bar { [] }
|
||||
val a = foo { <!UNSUPPORTED!>[]<!> }
|
||||
val b = bar { <!UNSUPPORTED!>[]<!> }
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ annotation class Ann(val i: IntArray)
|
||||
@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!>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
|
||||
|
||||
var i = 1
|
||||
|
||||
Reference in New Issue
Block a user