Prohibit synchronized methods on interface members

#KT-9310 Fixed
This commit is contained in:
Alexander Udalov
2019-08-13 10:05:11 +02:00
parent 815ff3c860
commit 312205f376
11 changed files with 88 additions and 16 deletions
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmFieldAnnotation
import org.jetbrains.kotlin.resolve.jvm.checkers.JvmFieldApplicabilityChecker.Problem.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
@@ -112,12 +111,4 @@ class JvmFieldApplicabilityChecker : DeclarationChecker {
private fun PropertyDescriptor.hasBackingField(bindingContext: BindingContext) =
bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, this) ?: false
private fun PropertyDescriptor.isInsideCompanionObjectOfInterface(): Boolean {
val containingClass = containingDeclaration as? ClassDescriptor ?: return false
if (!DescriptorUtils.isCompanionObject(containingClass)) return false
val outerClassKind = (containingClass.containingDeclaration as? ClassDescriptor)?.kind
return outerClassKind == ClassKind.INTERFACE || outerClassKind == ClassKind.ANNOTATION_CLASS
}
}
@@ -34,8 +34,8 @@ import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithCorres
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
import org.jetbrains.kotlin.resolve.jvm.annotations.findSynchronizedAnnotation
@@ -183,11 +183,20 @@ class VolatileAnnotationChecker : DeclarationChecker {
class SynchronizedAnnotationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val synchronizedAnnotation = descriptor.findSynchronizedAnnotation()
if (synchronizedAnnotation != null && descriptor is FunctionDescriptor && descriptor.modality == Modality.ABSTRACT) {
if (synchronizedAnnotation != null && descriptor is FunctionDescriptor) {
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(synchronizedAnnotation) ?: return
context.trace.report(ErrorsJvm.SYNCHRONIZED_ON_ABSTRACT.on(annotationEntry))
if (isInInterface(descriptor)) {
context.trace.report(ErrorsJvm.SYNCHRONIZED_IN_INTERFACE.on(annotationEntry))
} else if (descriptor.modality == Modality.ABSTRACT) {
context.trace.report(ErrorsJvm.SYNCHRONIZED_ON_ABSTRACT.on(annotationEntry))
}
}
}
private fun isInInterface(descriptor: FunctionDescriptor): Boolean =
DescriptorUtils.isInterface(descriptor.containingDeclaration) ||
(descriptor.propertyIfAccessor.isInsideCompanionObjectOfInterface() &&
(descriptor.hasJvmStaticAnnotation() || descriptor.propertyIfAccessor.hasJvmStaticAnnotation()))
}
class OverloadsAnnotationChecker: DeclarationChecker {
@@ -245,3 +254,11 @@ class TypeParameterBoundIsNotArrayChecker : DeclarationChecker {
}
}
}
internal fun CallableMemberDescriptor.isInsideCompanionObjectOfInterface(): Boolean {
val containingClass = containingDeclaration as? ClassDescriptor ?: return false
if (!DescriptorUtils.isCompanionObject(containingClass)) return false
val outerClassKind = (containingClass.containingDeclaration as? ClassDescriptor)?.kind
return outerClassKind == ClassKind.INTERFACE || outerClassKind == ClassKind.ANNOTATION_CLASS
}
@@ -58,6 +58,7 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
MAP.put(VOLATILE_ON_DELEGATE, "'@Volatile' annotation cannot be used on delegated properties");
MAP.put(SYNCHRONIZED_ON_ABSTRACT, "'@Synchronized' annotation cannot be used on abstract functions");
MAP.put(SYNCHRONIZED_ON_INLINE, "'@Synchronized' annotation has no effect on inline functions");
MAP.put(SYNCHRONIZED_IN_INTERFACE, "'@Synchronized' annotation cannot be used on interface members");
MAP.put(EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT, "External declaration can not be abstract");
MAP.put(EXTERNAL_DECLARATION_CANNOT_HAVE_BODY, "External declaration can not have a body");
MAP.put(EXTERNAL_DECLARATION_IN_INTERFACE, "Members of interfaces can not be external");
@@ -49,6 +49,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<KtAnnotationEntry> SYNCHRONIZED_IN_INTERFACE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_ABSTRACT = DiagnosticFactory0.create(ERROR);