Forbid suspend functions annotated with @kotlin.test.Test

#KT-26200 Fixed
This commit is contained in:
Denis Zharkov
2018-08-24 15:19:42 +03:00
parent a18770fbbb
commit b9f141d4aa
7 changed files with 57 additions and 8 deletions
@@ -116,7 +116,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
DynamicReceiverChecker,
DelegationChecker(),
KClassWithIncorrectTypeArgumentChecker,
SuspendOperatorsCheckers,
SuspendLimitationsChecker,
InlineClassDeclarationChecker,
PropertiesWithBackingFieldsInsideInlineClass(),
AnnotationClassTargetAndRetentionChecker(),
@@ -18,12 +18,17 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
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.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
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
object SuspendOperatorsCheckers : DeclarationChecker {
object SuspendLimitationsChecker : DeclarationChecker {
private val UNSUPPORTED_OPERATOR_NAMES = setOf(
OperatorNameConventions.CONTAINS,
OperatorNameConventions.GET, OperatorNameConventions.SET,
@@ -31,11 +36,22 @@ object SuspendOperatorsCheckers : DeclarationChecker {
)
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor is FunctionDescriptor && descriptor.isSuspend && descriptor.isOperator &&
descriptor.name in UNSUPPORTED_OPERATOR_NAMES) {
if (descriptor !is FunctionDescriptor || !descriptor.isSuspend) return
if (descriptor.isOperator && descriptor.name in UNSUPPORTED_OPERATOR_NAMES) {
declaration.modifierList?.getModifier(KtTokens.OPERATOR_KEYWORD)?.let {
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() {}
@@ -1653,6 +1653,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
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")
public void testSuspesionInDefaultValue() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspesionInDefaultValue.kt");
@@ -1653,6 +1653,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
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")
public void testSuspesionInDefaultValue() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspesionInDefaultValue.kt");
@@ -18,21 +18,24 @@ package org.jetbrains.kotlin.descriptors.annotations
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ConstantValue
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.KotlinType
import org.jetbrains.kotlin.types.getAbbreviation
interface AnnotationDescriptor {
val type: KotlinType
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 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
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(
useOriginal: Boolean = false,