Fix diagnostic for uninitialized extension property without accessors

#KT-8612 Fixed
This commit is contained in:
Dmitry Petrov
2017-05-24 17:00:54 +03:00
parent 902d3af280
commit d850f01c39
8 changed files with 83 additions and 10 deletions
@@ -462,6 +462,8 @@ public interface Errors {
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_BE_ABSTRACT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtProperty> EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT =
DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtProperty> UNNECESSARY_LATEINIT = DiagnosticFactory0.create(WARNING, LATEINIT_MODIFIER);
DiagnosticFactory0<KtExpression> EXTENSION_PROPERTY_WITH_BACKING_FIELD = DiagnosticFactory0.create(ERROR);
@@ -231,6 +231,7 @@ public class DefaultErrorMessages {
MAP.put(BACKING_FIELD_IN_INTERFACE, "Property in an interface cannot have a backing field");
MAP.put(MUST_BE_INITIALIZED, "Property must be initialized");
MAP.put(MUST_BE_INITIALIZED_OR_BE_ABSTRACT, "Property must be initialized or be abstract");
MAP.put(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, "Extension property must have accessors or be abstract");
MAP.put(UNNECESSARY_LATEINIT, "Lateinit is unnecessary: definitely initialized in constructors");
MAP.put(PROPERTY_INITIALIZER_IN_INTERFACE, "Property initializers are not allowed in interfaces");
MAP.put(PRIVATE_PROPERTY_IN_INTERFACE, "Abstract property in an interface cannot be private");
@@ -668,19 +668,19 @@ class DeclarationsChecker(
val hasAccessorImplementation = propertyDescriptor.hasAccessorImplementation()
val containingDeclaration = propertyDescriptor.containingDeclaration
val inTrait = containingDeclaration is ClassDescriptor && containingDeclaration.kind == ClassKind.INTERFACE
val inInterface = DescriptorUtils.isInterface(containingDeclaration)
if (propertyDescriptor.modality == Modality.ABSTRACT) {
if (!property.hasDelegateExpressionOrInitializer() && property.typeReference == null) {
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
}
if (inTrait && property.hasModifier(KtTokens.PRIVATE_KEYWORD) && !property.hasModifier(KtTokens.ABSTRACT_KEYWORD)) {
if (inInterface && property.hasModifier(KtTokens.PRIVATE_KEYWORD) && !property.hasModifier(KtTokens.ABSTRACT_KEYWORD)) {
trace.report(PRIVATE_PROPERTY_IN_INTERFACE.on(property))
}
return
}
val backingFieldRequired = trace.bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false
if (inTrait && backingFieldRequired && hasAccessorImplementation) {
if (inInterface && backingFieldRequired && hasAccessorImplementation) {
trace.report(BACKING_FIELD_IN_INTERFACE.on(property))
}
@@ -688,7 +688,7 @@ class DeclarationsChecker(
val delegate = property.delegate
val isHeader = propertyDescriptor.isHeader
if (initializer != null) {
if (inTrait) {
if (inInterface) {
trace.report(PROPERTY_INITIALIZER_IN_INTERFACE.on(initializer))
}
else if (isHeader) {
@@ -702,15 +702,18 @@ class DeclarationsChecker(
}
}
else if (delegate != null) {
if (inTrait) {
if (inInterface) {
trace.report(DELEGATED_PROPERTY_IN_INTERFACE.on(delegate))
}
}
else {
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
val isExternal = propertyDescriptor.isEffectivelyExternal()
if (backingFieldRequired && !inTrait && !propertyDescriptor.isLateInit && !isHeader && isUninitialized && !isExternal) {
if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isHeader && isUninitialized && !isExternal) {
if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) {
trace.report(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT.on(property))
}
else if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
trace.report(MUST_BE_INITIALIZED.on(property))
}
else {
@@ -723,7 +726,7 @@ class DeclarationsChecker(
else if (noExplicitTypeOrGetterType(property)) {
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
}
if (backingFieldRequired && !inTrait && propertyDescriptor.isLateInit && !isUninitialized &&
if (backingFieldRequired && !inInterface && propertyDescriptor.isLateInit && !isUninitialized &&
trace[MUST_BE_LATEINIT, propertyDescriptor] != true) {
trace.report(UNNECESSARY_LATEINIT.on(property))
}
@@ -36,7 +36,7 @@ fun test() {
val Int.abs : Int
get() = if (this > 0) this else -this;
<!MUST_BE_INITIALIZED!>val <T> T.foo : T<!>
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>val <T> T.foo : T<!>
fun Int.foo() = this
@@ -0,0 +1,25 @@
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>val String.test1: Int<!>
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>var String.test2: Int<!>
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>var String.test3: Int<!>; public set
class C {
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>val String.test1: Int<!>
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>var String.test2: Int<!>
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>var String.test3: Int<!>; public set
}
interface I {
val String.test1: Int
var String.test2: Int
var String.test3: Int; public set
}
abstract class A {
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>val String.test1: Int<!>
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>var String.test2: Int<!>
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>var String.test3: Int<!>; public set
abstract val String.testA1: Int
abstract var String.testA2: Int
}
@@ -0,0 +1,36 @@
package
public val kotlin.String.test1: kotlin.Int
public var kotlin.String.test2: kotlin.Int
public var kotlin.String.test3: kotlin.Int
public abstract class A {
public constructor A()
public final val kotlin.String.test1: kotlin.Int
public final var kotlin.String.test2: kotlin.Int
public final var kotlin.String.test3: kotlin.Int
public abstract val kotlin.String.testA1: kotlin.Int
public abstract var kotlin.String.testA2: kotlin.Int
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 final class C {
public constructor C()
public final val kotlin.String.test1: kotlin.Int
public final var kotlin.String.test2: kotlin.Int
public final var kotlin.String.test3: kotlin.Int
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 interface I {
public abstract val kotlin.String.test1: kotlin.Int
public abstract var kotlin.String.test2: kotlin.Int
public abstract var kotlin.String.test3: kotlin.Int
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
}
@@ -34,6 +34,6 @@ set(value) {}
<!UNRESOLVED_REFERENCE!>get<!>() = 42
<!UNRESOLVED_REFERENCE!>set<!>(<!UNRESOLVED_REFERENCE!>value<!>) {}
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var String.testExtVarLineBreakSemi: Int<!>;
<!EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT!>var String.testExtVarLineBreakSemi: Int<!>;
<!UNRESOLVED_REFERENCE!>get<!>() = 42
<!UNRESOLVED_REFERENCE!>set<!>(<!UNRESOLVED_REFERENCE!>value<!>) {}
@@ -15838,6 +15838,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/properties"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("extensionPropertyMustHaveAccessorsOrBeAbstract.kt")
public void testExtensionPropertyMustHaveAccessorsOrBeAbstract() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/extensionPropertyMustHaveAccessorsOrBeAbstract.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/diagnostics/tests/properties/inferenceFromGetters")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)