Forbid @Synchronized annotation on suspend functions

and lambdas. With warning for now.
 #KT-27333
This commit is contained in:
Ilmir Usmanov
2021-08-25 17:53:48 +02:00
parent 97176b5d60
commit 92fac304e7
13 changed files with 127 additions and 31 deletions
@@ -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))
}
}
}
@@ -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))
}
}
}
}
@@ -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))
}
}
}
@@ -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);
@@ -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(