Fix diagnostic for uninitialized extension property without accessors
#KT-8612 Fixed
This commit is contained in:
@@ -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);
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
|
||||
Vendored
+25
@@ -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
|
||||
}
|
||||
Vendored
+36
@@ -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
|
||||
}
|
||||
+1
-1
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user