Forbid private functions with no body and private properties in traits which are abstract by default
This commit is contained in:
@@ -328,6 +328,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<JetExpression> PROPERTY_INITIALIZER_NO_BACKING_FIELD = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<JetExpression> PROPERTY_INITIALIZER_IN_TRAIT = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<JetProperty> FINAL_PROPERTY_IN_TRAIT = DiagnosticFactory0.create(ERROR, FINAL_MODIFIER);
|
||||
DiagnosticFactory0<JetProperty> PRIVATE_PROPERTY_IN_TRAIT = DiagnosticFactory0.create(ERROR, PRIVATE_MODIFIER);
|
||||
DiagnosticFactory0<JetProperty> BACKING_FIELD_IN_TRAIT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
|
||||
DiagnosticFactory0<JetSimpleNameExpression> BACKING_FIELD_SYNTAX_DEPRECATED = DiagnosticFactory0.create(WARNING);
|
||||
@@ -355,6 +356,7 @@ public interface Errors {
|
||||
DiagnosticFactory1<JetFunction, SimpleFunctionDescriptor> NON_ABSTRACT_FUNCTION_WITH_NO_BODY =
|
||||
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory1<JetFunction, SimpleFunctionDescriptor> FINAL_FUNCTION_WITH_NO_BODY = DiagnosticFactory1.create(ERROR, FINAL_MODIFIER);
|
||||
DiagnosticFactory1<JetFunction, SimpleFunctionDescriptor> PRIVATE_FUNCTION_WITH_NO_BODY = DiagnosticFactory1.create(ERROR, PRIVATE_MODIFIER);
|
||||
|
||||
DiagnosticFactory1<JetFunction, SimpleFunctionDescriptor> NON_MEMBER_FUNCTION_NO_BODY =
|
||||
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE);
|
||||
|
||||
@@ -192,13 +192,11 @@ public object PositioningStrategies {
|
||||
|
||||
public val ABSTRACT_MODIFIER: PositioningStrategy<JetModifierListOwner> = modifierSetPosition(JetTokens.ABSTRACT_KEYWORD)
|
||||
|
||||
public val INNER_MODIFIER: PositioningStrategy<JetModifierListOwner> = modifierSetPosition(JetTokens.INNER_KEYWORD)
|
||||
|
||||
public val OVERRIDE_MODIFIER: PositioningStrategy<JetModifierListOwner> = modifierSetPosition(JetTokens.OVERRIDE_KEYWORD)
|
||||
|
||||
public val FINAL_MODIFIER: PositioningStrategy<JetModifierListOwner> = modifierSetPosition(JetTokens.FINAL_KEYWORD)
|
||||
|
||||
public val SEALED_MODIFIER: PositioningStrategy<JetModifierListOwner> = modifierSetPosition(JetTokens.SEALED_KEYWORD)
|
||||
public val PRIVATE_MODIFIER: PositioningStrategy<JetModifierListOwner> = modifierSetPosition(JetTokens.PRIVATE_KEYWORD)
|
||||
|
||||
public val VARIANCE_MODIFIER: PositioningStrategy<JetModifierListOwner> = modifierSetPosition(JetTokens.IN_KEYWORD, JetTokens.OUT_KEYWORD)
|
||||
|
||||
|
||||
+2
@@ -217,6 +217,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(MUST_BE_INITIALIZED_OR_BE_ABSTRACT, "Property must be initialized or be abstract");
|
||||
MAP.put(PROPERTY_INITIALIZER_IN_TRAIT, "Property initializers are not allowed in interfaces");
|
||||
MAP.put(FINAL_PROPERTY_IN_TRAIT, "Abstract property in an interface cannot be final");
|
||||
MAP.put(PRIVATE_PROPERTY_IN_TRAIT, "Abstract property in an interface cannot be private");
|
||||
MAP.put(EXTENSION_PROPERTY_WITH_BACKING_FIELD, "Extension property cannot be initialized because it has no backing field");
|
||||
MAP.put(PROPERTY_INITIALIZER_NO_BACKING_FIELD, "Initializer is not allowed here because this property has no backing field");
|
||||
MAP.put(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS, "Abstract property ''{0}'' in non-abstract class ''{1}''", STRING, NAME);
|
||||
@@ -224,6 +225,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(ABSTRACT_FUNCTION_WITH_BODY, "A function ''{0}'' with body cannot be abstract", NAME);
|
||||
MAP.put(NON_ABSTRACT_FUNCTION_WITH_NO_BODY, "Function ''{0}'' without a body must be abstract", NAME);
|
||||
MAP.put(FINAL_FUNCTION_WITH_NO_BODY, "Function ''{0}'' without body cannot be final", NAME);
|
||||
MAP.put(PRIVATE_FUNCTION_WITH_NO_BODY, "Function ''{0}'' without body cannot be private", NAME);
|
||||
|
||||
MAP.put(NON_MEMBER_FUNCTION_NO_BODY, "Function ''{0}'' must have a body", NAME);
|
||||
MAP.put(FUNCTION_DECLARATION_WITH_NO_NAME, "Function declaration must have a name");
|
||||
|
||||
@@ -428,14 +428,17 @@ public class DeclarationsChecker {
|
||||
boolean hasAccessorImplementation = (getter != null && getter.hasBody()) ||
|
||||
(setter != null && setter.hasBody());
|
||||
|
||||
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
|
||||
boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.INTERFACE;
|
||||
if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
|
||||
if (!property.hasDelegateExpressionOrInitializer() && property.getTypeReference() == null) {
|
||||
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
|
||||
}
|
||||
if (inTrait && property.hasModifier(JetTokens.PRIVATE_KEYWORD) && !property.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
|
||||
trace.report(PRIVATE_PROPERTY_IN_TRAIT.on(property));
|
||||
}
|
||||
return;
|
||||
}
|
||||
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
|
||||
boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.INTERFACE;
|
||||
JetExpression initializer = property.getInitializer();
|
||||
JetPropertyDelegate delegate = property.getDelegate();
|
||||
boolean backingFieldRequired =
|
||||
@@ -501,8 +504,13 @@ public class DeclarationsChecker {
|
||||
if (hasBody && hasAbstractModifier) {
|
||||
trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor));
|
||||
}
|
||||
if (!hasBody && function.hasModifier(JetTokens.FINAL_KEYWORD) && inTrait) {
|
||||
trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
|
||||
if (!hasBody && inTrait) {
|
||||
if (function.hasModifier(JetTokens.FINAL_KEYWORD)) {
|
||||
trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
|
||||
}
|
||||
if (function.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
|
||||
trace.report(PRIVATE_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
|
||||
}
|
||||
}
|
||||
if (!hasBody && !hasAbstractModifier && !inTrait) {
|
||||
trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
|
||||
|
||||
@@ -10,4 +10,7 @@ compiler/testData/cli/jvm/multipleTextRangesInDiagnosticsOrder.kt:6:14: error: m
|
||||
compiler/testData/cli/jvm/multipleTextRangesInDiagnosticsOrder.kt:6:24: error: modifier 'private' is incompatible with 'override'
|
||||
override protected private val c: Int
|
||||
^
|
||||
compiler/testData/cli/jvm/multipleTextRangesInDiagnosticsOrder.kt:6:24: error: abstract property in an interface cannot be private
|
||||
override protected private val c: Int
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
interface My {
|
||||
<!PRIVATE_PROPERTY_IN_TRAIT!>private<!> val x: Int
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!ABSTRACT_MODIFIER_IN_TRAIT, INCOMPATIBLE_MODIFIERS!>abstract<!> val xx: Int
|
||||
private val xxx: Int
|
||||
get() = 0
|
||||
<!FINAL_PROPERTY_IN_TRAIT, DEPRECATED_MODIFIER_CONTAINING_DECLARATION!>final<!> val y: Int
|
||||
<!DEPRECATED_MODIFIER_CONTAINING_DECLARATION!>final<!> val yy: Int
|
||||
get() = 1
|
||||
<!PRIVATE_FUNCTION_WITH_NO_BODY!>private<!> fun foo(): Int
|
||||
// ok
|
||||
private fun bar() = 42
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package
|
||||
|
||||
public interface My {
|
||||
private abstract val x: kotlin.Int
|
||||
private abstract val xx: kotlin.Int
|
||||
private final val xxx: kotlin.Int
|
||||
public final val y: kotlin.Int
|
||||
public final val yy: kotlin.Int
|
||||
private final fun bar(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
private abstract fun foo(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -2,7 +2,7 @@ interface Test<in I, out O> {
|
||||
val internal_val: <!TYPE_VARIANCE_CONFLICT!>I<!>
|
||||
public val public_val: <!TYPE_VARIANCE_CONFLICT!>I<!>
|
||||
<!DEPRECATED_MODIFIER_CONTAINING_DECLARATION!>protected<!> val protected_val: <!TYPE_VARIANCE_CONFLICT!>I<!>
|
||||
private val private_val: I
|
||||
<!PRIVATE_PROPERTY_IN_TRAIT!>private<!> val private_val: I
|
||||
|
||||
var interlan_private_set: <!TYPE_VARIANCE_CONFLICT!>O<!>
|
||||
private set
|
||||
@@ -10,11 +10,11 @@ interface Test<in I, out O> {
|
||||
private set
|
||||
<!DEPRECATED_MODIFIER_CONTAINING_DECLARATION!>protected<!> var protected_private_set: <!TYPE_VARIANCE_CONFLICT!>O<!>
|
||||
private set
|
||||
private var private_private_set: O
|
||||
<!PRIVATE_PROPERTY_IN_TRAIT!>private<!> var private_private_set: O
|
||||
private set
|
||||
|
||||
fun internal_fun(i: <!TYPE_VARIANCE_CONFLICT!>O<!>) : <!TYPE_VARIANCE_CONFLICT!>I<!>
|
||||
public fun public_fun(i: <!TYPE_VARIANCE_CONFLICT!>O<!>) : <!TYPE_VARIANCE_CONFLICT!>I<!>
|
||||
<!DEPRECATED_MODIFIER_CONTAINING_DECLARATION!>protected<!> fun protected_fun(i: <!TYPE_VARIANCE_CONFLICT!>O<!>) : <!TYPE_VARIANCE_CONFLICT!>I<!>
|
||||
private fun private_fun(i: O) : I
|
||||
<!PRIVATE_FUNCTION_WITH_NO_BODY!>private<!> fun private_fun(i: O) : I
|
||||
}
|
||||
Vendored
+2
-2
@@ -2,11 +2,11 @@ package test
|
||||
|
||||
public interface Super1 {
|
||||
public fun foo(): CharSequence
|
||||
private fun bar(): String
|
||||
private fun bar(): String = ""
|
||||
}
|
||||
|
||||
public interface Super2 {
|
||||
private fun foo(): String
|
||||
private fun foo(): String = ""
|
||||
public fun bar(): CharSequence
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -6,11 +6,11 @@ public interface Sub : test.Super1, test.Super2 {
|
||||
}
|
||||
|
||||
public interface Super1 {
|
||||
private abstract fun bar(): kotlin.String
|
||||
private final fun bar(): kotlin.String
|
||||
public abstract fun foo(): kotlin.CharSequence
|
||||
}
|
||||
|
||||
public interface Super2 {
|
||||
public abstract fun bar(): kotlin.CharSequence
|
||||
private abstract fun foo(): kotlin.String
|
||||
private final fun foo(): kotlin.String
|
||||
}
|
||||
|
||||
@@ -9162,6 +9162,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("privateInInterface.kt")
|
||||
public void testPrivateInInterface() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/privateInInterface.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("redundantTargets.kt")
|
||||
public void testRedundantTargets() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/redundantTargets.kt");
|
||||
|
||||
Reference in New Issue
Block a user