Forbid @Synchronized annotation on suspend functions
and lambdas. With warning for now. #KT-27333
This commit is contained in:
+6
@@ -36134,6 +36134,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
public void testSynchronizedOnInline() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inline/synchronizedOnInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("synchronizedOnSuspend.kt")
|
||||
public void testSynchronizedOnSuspend() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inline/synchronizedOnSuspend.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+6
@@ -36134,6 +36134,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
public void testSynchronizedOnInline() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inline/synchronizedOnInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("synchronizedOnSuspend.kt")
|
||||
public void testSynchronizedOnSuspend() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inline/synchronizedOnSuspend.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.resolve.jvm.checkers
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.psi.KtAnnotated
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.unwrapParenthesesLabelsAndAnnotations
|
||||
import org.jetbrains.kotlin.resolve.AdditionalAnnotationChecker
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.SYNCHRONIZED_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
|
||||
object SynchronizedAnnotationOnLambdaChecker : AdditionalAnnotationChecker {
|
||||
override fun checkEntries(
|
||||
entries: List<KtAnnotationEntry>,
|
||||
actualTargets: List<KotlinTarget>,
|
||||
trace: BindingTrace,
|
||||
annotated: KtAnnotated?,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
if (entries.isEmpty()) return
|
||||
|
||||
val annotation = entries.find { trace.get(BindingContext.ANNOTATION, it)?.fqName == SYNCHRONIZED_ANNOTATION_FQ_NAME } ?: return
|
||||
|
||||
val literal = (annotated?.unwrapParenthesesLabelsAndAnnotations() as? KtLambdaExpression)?.functionLiteral ?: return
|
||||
val descriptor = trace.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, literal]
|
||||
if (descriptor is FunctionDescriptor && descriptor.isSuspend) {
|
||||
trace.report(ErrorsJvm.SYNCHRONIZED_ON_SUSPEND.on(annotation))
|
||||
}
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.resolve.jvm.checkers
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.findSynchronizedAnnotation
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
|
||||
object SynchronizedOnInlineMethodChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (descriptor is FunctionDescriptor && descriptor.isInline) {
|
||||
val annotation = descriptor.findSynchronizedAnnotation()
|
||||
if (annotation != null) {
|
||||
val reportOn = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: declaration
|
||||
context.trace.report(ErrorsJvm.SYNCHRONIZED_ON_INLINE.on(reportOn))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -195,6 +195,10 @@ class SynchronizedAnnotationChecker : DeclarationChecker {
|
||||
context.trace.report(ErrorsJvm.SYNCHRONIZED_IN_INTERFACE.on(annotationEntry))
|
||||
} else if (descriptor.modality == Modality.ABSTRACT) {
|
||||
context.trace.report(ErrorsJvm.SYNCHRONIZED_ON_ABSTRACT.on(annotationEntry))
|
||||
} else if (descriptor.isInline) {
|
||||
context.trace.report(ErrorsJvm.SYNCHRONIZED_ON_INLINE.on(annotationEntry))
|
||||
} else if (descriptor.isSuspend) {
|
||||
context.trace.report(ErrorsJvm.SYNCHRONIZED_ON_SUSPEND.on(annotationEntry))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -217,6 +217,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, "Value classes without @JvmInline annotation are not supported yet");
|
||||
MAP.put(JVM_INLINE_WITHOUT_VALUE_CLASS, "@JvmInline annotation is only applicable to value classes");
|
||||
|
||||
MAP.put(SYNCHRONIZED_ON_SUSPEND, "@Synchronized annotation is not applicable to suspend functions and lambdas");
|
||||
|
||||
MAP.put(TYPEOF_SUSPEND_TYPE, "Suspend functional types are not supported in typeOf");
|
||||
MAP.put(TYPEOF_EXTENSION_FUNCTION_TYPE, "Extension function types are not supported in typeOf");
|
||||
MAP.put(TYPEOF_ANNOTATED_TYPE, "Annotated types are not supported in typeOf");
|
||||
|
||||
@@ -52,6 +52,7 @@ public interface ErrorsJvm {
|
||||
DiagnosticFactory0<KtAnnotationEntry> VOLATILE_ON_DELEGATE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> SYNCHRONIZED_ON_ABSTRACT = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtElement> SYNCHRONIZED_ON_INLINE = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> SYNCHRONIZED_ON_SUSPEND = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<KtAnnotationEntry> SYNCHRONIZED_IN_INTERFACE = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
+3
-3
@@ -39,7 +39,6 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
|
||||
SuspendInFunInterfaceChecker(),
|
||||
BadInheritedJavaSignaturesChecker,
|
||||
JvmMultifileClassStateChecker,
|
||||
SynchronizedOnInlineMethodChecker,
|
||||
DefaultCheckerInTailrec,
|
||||
FunctionDelegateMemberNameClashChecker,
|
||||
ClassInheritsJavaSealedClassChecker
|
||||
@@ -57,7 +56,7 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
|
||||
RuntimeAssertionsOnExtensionReceiverCallChecker,
|
||||
ApiVersionIsAtLeastArgumentsChecker,
|
||||
InconsistentOperatorFromJavaCallChecker,
|
||||
PolymorphicSignatureCallChecker
|
||||
PolymorphicSignatureCallChecker,
|
||||
),
|
||||
|
||||
additionalTypeCheckers = listOf(
|
||||
@@ -74,7 +73,8 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
|
||||
|
||||
additionalAnnotationCheckers = listOf(
|
||||
FileClassAnnotationsChecker,
|
||||
ExplicitMetadataChecker
|
||||
ExplicitMetadataChecker,
|
||||
SynchronizedAnnotationOnLambdaChecker,
|
||||
),
|
||||
|
||||
additionalClashResolvers = listOf(
|
||||
|
||||
@@ -101,7 +101,12 @@ class AnnotationChecker(
|
||||
}
|
||||
|
||||
fun checkExpression(expression: KtExpression, trace: BindingTrace) {
|
||||
checkEntries(expression.getAnnotationEntries(), getActualTargetList(expression, null, trace.bindingContext), trace)
|
||||
checkEntries(
|
||||
expression.getAnnotationEntries(),
|
||||
getActualTargetList(expression, null, trace.bindingContext),
|
||||
trace,
|
||||
expression.parent as? KtAnnotated
|
||||
)
|
||||
if (expression is KtCallElement && languageVersionSettings.supportsFeature(ProperCheckAnnotationsTargetInTypeUsePositions)) {
|
||||
val typeArguments = expression.typeArguments.mapNotNull { it.typeReference }
|
||||
for (typeArgument in typeArguments) {
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// SKIP_TXT
|
||||
|
||||
@Synchronized
|
||||
suspend fun foo(f: () -> Unit): Unit = f()
|
||||
|
||||
fun builder(c: suspend () -> Unit) {}
|
||||
|
||||
val a: suspend () -> Unit
|
||||
get() = @Synchronized {}
|
||||
val b: suspend () -> Unit = @Synchronized {}
|
||||
val c = builder (@Synchronized {})
|
||||
val d = suspend @Synchronized {}
|
||||
val e = <!WRONG_ANNOTATION_TARGET!>@Synchronized<!> suspend {}
|
||||
|
||||
fun test() {
|
||||
@Synchronized
|
||||
suspend fun foo(f: () -> Unit): Unit = f()
|
||||
|
||||
val b: suspend () -> Unit = @Synchronized {}
|
||||
val c = builder (@Synchronized {})
|
||||
val d = suspend @Synchronized {}
|
||||
val e = <!WRONG_ANNOTATION_TARGET!>@Synchronized<!> suspend {}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// SKIP_TXT
|
||||
|
||||
<!SYNCHRONIZED_ON_SUSPEND!>@Synchronized<!>
|
||||
suspend fun foo(f: () -> Unit): Unit = f()
|
||||
|
||||
fun builder(c: suspend () -> Unit) {}
|
||||
|
||||
val a: suspend () -> Unit
|
||||
get() = <!SYNCHRONIZED_ON_SUSPEND!>@Synchronized<!> {}
|
||||
val b: suspend () -> Unit = <!SYNCHRONIZED_ON_SUSPEND!>@Synchronized<!> {}
|
||||
val c = builder (<!SYNCHRONIZED_ON_SUSPEND!>@Synchronized<!> {})
|
||||
val d = suspend <!SYNCHRONIZED_ON_SUSPEND!>@Synchronized<!> {}
|
||||
val e = <!WRONG_ANNOTATION_TARGET!>@Synchronized<!> suspend {}
|
||||
|
||||
fun test() {
|
||||
<!SYNCHRONIZED_ON_SUSPEND!>@Synchronized<!>
|
||||
suspend fun foo(f: () -> Unit): Unit = f()
|
||||
|
||||
val b: suspend () -> Unit = <!SYNCHRONIZED_ON_SUSPEND!>@Synchronized<!> {}
|
||||
val c = builder (<!SYNCHRONIZED_ON_SUSPEND!>@Synchronized<!> {})
|
||||
val d = suspend <!SYNCHRONIZED_ON_SUSPEND!>@Synchronized<!> {}
|
||||
val e = <!WRONG_ANNOTATION_TARGET!>@Synchronized<!> suspend {}
|
||||
}
|
||||
Generated
+6
@@ -36230,6 +36230,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
public void testSynchronizedOnInline() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inline/synchronizedOnInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("synchronizedOnSuspend.kt")
|
||||
public void testSynchronizedOnSuspend() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inline/synchronizedOnSuspend.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+6
@@ -36134,6 +36134,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
public void testSynchronizedOnInline() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inline/synchronizedOnInline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("synchronizedOnSuspend.kt")
|
||||
public void testSynchronizedOnSuspend() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/inline/synchronizedOnSuspend.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
Reference in New Issue
Block a user