Forbid suspend functions annotated with @kotlin.test.Test
#KT-26200 Fixed
This commit is contained in:
@@ -116,7 +116,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
|||||||
DynamicReceiverChecker,
|
DynamicReceiverChecker,
|
||||||
DelegationChecker(),
|
DelegationChecker(),
|
||||||
KClassWithIncorrectTypeArgumentChecker,
|
KClassWithIncorrectTypeArgumentChecker,
|
||||||
SuspendOperatorsCheckers,
|
SuspendLimitationsChecker,
|
||||||
InlineClassDeclarationChecker,
|
InlineClassDeclarationChecker,
|
||||||
PropertiesWithBackingFieldsInsideInlineClass(),
|
PropertiesWithBackingFieldsInsideInlineClass(),
|
||||||
AnnotationClassTargetAndRetentionChecker(),
|
AnnotationClassTargetAndRetentionChecker(),
|
||||||
|
|||||||
+19
-3
@@ -18,12 +18,17 @@ package org.jetbrains.kotlin.resolve.checkers
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.abbreviationFqName
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||||
|
import org.jetbrains.kotlin.types.getAbbreviation
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
object SuspendOperatorsCheckers : DeclarationChecker {
|
object SuspendLimitationsChecker : DeclarationChecker {
|
||||||
private val UNSUPPORTED_OPERATOR_NAMES = setOf(
|
private val UNSUPPORTED_OPERATOR_NAMES = setOf(
|
||||||
OperatorNameConventions.CONTAINS,
|
OperatorNameConventions.CONTAINS,
|
||||||
OperatorNameConventions.GET, OperatorNameConventions.SET,
|
OperatorNameConventions.GET, OperatorNameConventions.SET,
|
||||||
@@ -31,11 +36,22 @@ object SuspendOperatorsCheckers : DeclarationChecker {
|
|||||||
)
|
)
|
||||||
|
|
||||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||||
if (descriptor is FunctionDescriptor && descriptor.isSuspend && descriptor.isOperator &&
|
if (descriptor !is FunctionDescriptor || !descriptor.isSuspend) return
|
||||||
descriptor.name in UNSUPPORTED_OPERATOR_NAMES) {
|
|
||||||
|
if (descriptor.isOperator && descriptor.name in UNSUPPORTED_OPERATOR_NAMES) {
|
||||||
declaration.modifierList?.getModifier(KtTokens.OPERATOR_KEYWORD)?.let {
|
declaration.modifierList?.getModifier(KtTokens.OPERATOR_KEYWORD)?.let {
|
||||||
context.trace.report(Errors.UNSUPPORTED.on(it, "suspend operator \"${descriptor.name}\""))
|
context.trace.report(Errors.UNSUPPORTED.on(it, "suspend operator \"${descriptor.name}\""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (descriptor.annotations.any(AnnotationDescriptor::isKotlinTestAnnotation)) {
|
||||||
|
declaration.modifierList?.getModifier(KtTokens.SUSPEND_KEYWORD)?.let {
|
||||||
|
context.trace.report(Errors.UNSUPPORTED.on(it, "suspend test functions"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val KOTLIN_TEST_TEST_FQNAME = FqName("kotlin.test.Test")
|
||||||
|
private fun AnnotationDescriptor.isKotlinTestAnnotation() =
|
||||||
|
fqName == KOTLIN_TEST_TEST_FQNAME || abbreviationFqName == KOTLIN_TEST_TEST_FQNAME
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// SKIP_TXT
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
package kotlin.test
|
||||||
|
|
||||||
|
annotation class IrrelevantClass
|
||||||
|
|
||||||
|
public typealias Test = IrrelevantClass
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
class A {
|
||||||
|
@Test
|
||||||
|
<!UNSUPPORTED!>suspend<!> fun test() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
<!UNSUPPORTED!>suspend<!> fun test() {}
|
||||||
+5
@@ -1653,6 +1653,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("suspendTest.kt")
|
||||||
|
public void testSuspendTest() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("suspesionInDefaultValue.kt")
|
@TestMetadata("suspesionInDefaultValue.kt")
|
||||||
public void testSuspesionInDefaultValue() throws Exception {
|
public void testSuspesionInDefaultValue() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspesionInDefaultValue.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspesionInDefaultValue.kt");
|
||||||
|
|||||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+5
@@ -1653,6 +1653,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("suspendTest.kt")
|
||||||
|
public void testSuspendTest() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("suspesionInDefaultValue.kt")
|
@TestMetadata("suspesionInDefaultValue.kt")
|
||||||
public void testSuspesionInDefaultValue() throws Exception {
|
public void testSuspesionInDefaultValue() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspesionInDefaultValue.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspesionInDefaultValue.kt");
|
||||||
|
|||||||
+6
-3
@@ -18,21 +18,24 @@ package org.jetbrains.kotlin.descriptors.annotations
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.getAbbreviation
|
||||||
|
|
||||||
interface AnnotationDescriptor {
|
interface AnnotationDescriptor {
|
||||||
val type: KotlinType
|
val type: KotlinType
|
||||||
|
|
||||||
val fqName: FqName?
|
val fqName: FqName?
|
||||||
get() = annotationClass?.takeUnless(ErrorUtils::isError)?.fqNameUnsafe?.takeIf(FqNameUnsafe::isSafe)?.toSafe()
|
get() = annotationClass?.takeUnless(ErrorUtils::isError)?.fqNameOrNull()
|
||||||
|
|
||||||
val allValueArguments: Map<Name, ConstantValue<*>>
|
val allValueArguments: Map<Name, ConstantValue<*>>
|
||||||
|
|
||||||
val source: SourceElement
|
val source: SourceElement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val AnnotationDescriptor.abbreviationFqName: FqName?
|
||||||
|
get() = type.getAbbreviation()?.constructor?.declarationDescriptor?.fqNameOrNull()
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ val DeclarationDescriptor.parents: Sequence<DeclarationDescriptor>
|
|||||||
val CallableMemberDescriptor.propertyIfAccessor: CallableMemberDescriptor
|
val CallableMemberDescriptor.propertyIfAccessor: CallableMemberDescriptor
|
||||||
get() = if (this is PropertyAccessorDescriptor) correspondingProperty else this
|
get() = if (this is PropertyAccessorDescriptor) correspondingProperty else this
|
||||||
|
|
||||||
fun CallableDescriptor.fqNameOrNull(): FqName? = fqNameUnsafe.takeIf { it.isSafe }?.toSafe()
|
fun DeclarationDescriptor.fqNameOrNull(): FqName? = fqNameUnsafe.takeIf { it.isSafe }?.toSafe()
|
||||||
|
|
||||||
fun CallableMemberDescriptor.firstOverridden(
|
fun CallableMemberDescriptor.firstOverridden(
|
||||||
useOriginal: Boolean = false,
|
useOriginal: Boolean = false,
|
||||||
|
|||||||
Reference in New Issue
Block a user