Forbid private functions with no body and private properties in traits which are abstract by default

This commit is contained in:
Mikhail Glukhikh
2015-09-29 15:14:57 +03:00
parent 930402d910
commit 7a99b3872b
11 changed files with 59 additions and 14 deletions
@@ -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)
@@ -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
}
+3 -3
View File
@@ -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
}
@@ -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
}
@@ -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");