Prohibit synchronized methods on interface members
#KT-9310 Fixed
This commit is contained in:
-9
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
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.annotations.findJvmFieldAnnotation
|
||||||
import org.jetbrains.kotlin.resolve.jvm.checkers.JvmFieldApplicabilityChecker.Problem.*
|
import org.jetbrains.kotlin.resolve.jvm.checkers.JvmFieldApplicabilityChecker.Problem.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||||
@@ -112,12 +111,4 @@ class JvmFieldApplicabilityChecker : DeclarationChecker {
|
|||||||
|
|
||||||
private fun PropertyDescriptor.hasBackingField(bindingContext: BindingContext) =
|
private fun PropertyDescriptor.hasBackingField(bindingContext: BindingContext) =
|
||||||
bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, this) ?: false
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-3
@@ -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.DeclarationChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
|
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.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.VOLATILE_ANNOTATION_FQ_NAME
|
||||||
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
|
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
|
||||||
import org.jetbrains.kotlin.resolve.jvm.annotations.findSynchronizedAnnotation
|
import org.jetbrains.kotlin.resolve.jvm.annotations.findSynchronizedAnnotation
|
||||||
@@ -183,11 +183,20 @@ class VolatileAnnotationChecker : DeclarationChecker {
|
|||||||
class SynchronizedAnnotationChecker : DeclarationChecker {
|
class SynchronizedAnnotationChecker : DeclarationChecker {
|
||||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||||
val synchronizedAnnotation = descriptor.findSynchronizedAnnotation()
|
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
|
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 {
|
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
|
||||||
|
}
|
||||||
|
|||||||
+1
@@ -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(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_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_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_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_CANNOT_HAVE_BODY, "External declaration can not have a body");
|
||||||
MAP.put(EXTERNAL_DECLARATION_IN_INTERFACE, "Members of interfaces can not be external");
|
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> VOLATILE_ON_DELEGATE = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<KtAnnotationEntry> SYNCHRONIZED_ON_ABSTRACT = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtAnnotationEntry> SYNCHRONIZED_ON_ABSTRACT = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<KtElement> SYNCHRONIZED_ON_INLINE = DiagnosticFactory0.create(WARNING);
|
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_WITHOUT_DEFAULT_ARGUMENTS = DiagnosticFactory0.create(WARNING);
|
||||||
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_ABSTRACT = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_ABSTRACT = DiagnosticFactory0.create(ERROR);
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import kotlin.jvm.Synchronized
|
import kotlin.jvm.Synchronized
|
||||||
|
|
||||||
interface My {
|
interface My {
|
||||||
<!SYNCHRONIZED_ON_ABSTRACT!>@Synchronized<!> fun foo()
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> fun foo()
|
||||||
|
|
||||||
@Synchronized fun bar() = 1
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> fun bar() = 1
|
||||||
|
|
||||||
@Synchronized fun baz(): String {
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> fun baz(): String {
|
||||||
return "abc"
|
return "abc"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var v: String
|
||||||
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> get() = ""
|
||||||
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> set(<!UNUSED_PARAMETER!>value<!>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Your {
|
abstract class Your {
|
||||||
@@ -18,6 +22,10 @@ abstract class Your {
|
|||||||
@Synchronized open fun baz(): String {
|
@Synchronized open fun baz(): String {
|
||||||
return "xyz"
|
return "xyz"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var v: String
|
||||||
|
@Synchronized get() = ""
|
||||||
|
@Synchronized set(<!UNUSED_PARAMETER!>value<!>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized fun gav() = 1
|
@Synchronized fun gav() = 1
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package
|
|||||||
@kotlin.jvm.Synchronized public fun gav(): kotlin.Int
|
@kotlin.jvm.Synchronized public fun gav(): kotlin.Int
|
||||||
|
|
||||||
public interface My {
|
public interface My {
|
||||||
|
@get:kotlin.jvm.Synchronized @set:kotlin.jvm.Synchronized public open var v: kotlin.String
|
||||||
@kotlin.jvm.Synchronized public open fun bar(): kotlin.Int
|
@kotlin.jvm.Synchronized public open fun bar(): kotlin.Int
|
||||||
@kotlin.jvm.Synchronized public open fun baz(): kotlin.String
|
@kotlin.jvm.Synchronized public open fun baz(): kotlin.String
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
@@ -13,6 +14,7 @@ public interface My {
|
|||||||
|
|
||||||
public abstract class Your {
|
public abstract class Your {
|
||||||
public constructor Your()
|
public constructor Your()
|
||||||
|
@get:kotlin.jvm.Synchronized @set:kotlin.jvm.Synchronized public final var v: kotlin.String
|
||||||
@kotlin.jvm.Synchronized public final fun bar(): kotlin.Int
|
@kotlin.jvm.Synchronized public final fun bar(): kotlin.Int
|
||||||
@kotlin.jvm.Synchronized public open fun baz(): kotlin.String
|
@kotlin.jvm.Synchronized public open fun baz(): kotlin.String
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
|||||||
Vendored
+23
@@ -0,0 +1,23 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// !LANGUAGE: +JvmStaticInInterface
|
||||||
|
// !JVM_TARGET: 1.8
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
companion object {
|
||||||
|
@Synchronized fun syncFun() {}
|
||||||
|
|
||||||
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> @JvmStatic fun syncFunJvmStatic() {}
|
||||||
|
|
||||||
|
var syncProp: String
|
||||||
|
@Synchronized get() = ""
|
||||||
|
@Synchronized set(value) {}
|
||||||
|
|
||||||
|
@JvmStatic var syncPropJvmStatic: String
|
||||||
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> get() = ""
|
||||||
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> set(value) {}
|
||||||
|
|
||||||
|
var syncPropJvmStaticAccessors: String
|
||||||
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> @JvmStatic get() = ""
|
||||||
|
<!SYNCHRONIZED_IN_INTERFACE!>@Synchronized<!> @JvmStatic set(value) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
compiler/testData/diagnostics/testsWithStdLib/annotations/SynchronizedOnInterfaceCompanionMember.txt
Vendored
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public interface I {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
public companion object Companion {
|
||||||
|
private constructor Companion()
|
||||||
|
@get:kotlin.jvm.Synchronized @set:kotlin.jvm.Synchronized public final var syncProp: kotlin.String
|
||||||
|
@kotlin.jvm.JvmStatic @get:kotlin.jvm.Synchronized @set:kotlin.jvm.Synchronized public final var syncPropJvmStatic: kotlin.String
|
||||||
|
@get:kotlin.jvm.Synchronized @get:kotlin.jvm.JvmStatic @set:kotlin.jvm.Synchronized @set:kotlin.jvm.JvmStatic public final var syncPropJvmStaticAccessors: kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
@kotlin.jvm.Synchronized public final fun syncFun(): kotlin.Unit
|
||||||
|
@kotlin.jvm.Synchronized @kotlin.jvm.JvmStatic public final fun syncFunJvmStatic(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -5,7 +5,7 @@ interface Test {
|
|||||||
<!INAPPLICABLE_JVM_NAME!>@get:JvmName("1")<!>
|
<!INAPPLICABLE_JVM_NAME!>@get:JvmName("1")<!>
|
||||||
val b: Int
|
val b: Int
|
||||||
|
|
||||||
<!SYNCHRONIZED_ON_ABSTRACT!>@get:Synchronized<!>
|
<!SYNCHRONIZED_IN_INTERFACE!>@get:Synchronized<!>
|
||||||
val c: Int
|
val c: Int
|
||||||
|
|
||||||
<!OVERLOADS_INTERFACE, WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@get:JvmOverloads<!>
|
<!OVERLOADS_INTERFACE, WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@get:JvmOverloads<!>
|
||||||
|
|||||||
+5
@@ -206,6 +206,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/Synchronized.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/Synchronized.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SynchronizedOnInterfaceCompanionMember.kt")
|
||||||
|
public void testSynchronizedOnInterfaceCompanionMember() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/SynchronizedOnInterfaceCompanionMember.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("targetuse.kt")
|
@TestMetadata("targetuse.kt")
|
||||||
public void testTargetuse() throws Exception {
|
public void testTargetuse() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/targetuse.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/targetuse.kt");
|
||||||
|
|||||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+5
@@ -206,6 +206,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/Synchronized.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/Synchronized.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SynchronizedOnInterfaceCompanionMember.kt")
|
||||||
|
public void testSynchronizedOnInterfaceCompanionMember() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/SynchronizedOnInterfaceCompanionMember.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("targetuse.kt")
|
@TestMetadata("targetuse.kt")
|
||||||
public void testTargetuse() throws Exception {
|
public void testTargetuse() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/targetuse.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/targetuse.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user