Initializer is now required for mutable properties with backing fields and open or custom setter #KT-9449 Fixed

Setters without body are not taken into account accordingly to KT-9449.
Old INITIALIZATION_USING_BACKING_FIELD_SETTER are both dropped.
This commit is contained in:
Mikhail Glukhikh
2015-10-14 15:25:25 +03:00
parent 9c9ab671b3
commit c0faf82f77
9 changed files with 112 additions and 26 deletions
@@ -70,6 +70,7 @@ import static org.jetbrains.kotlin.cfg.TailRecursionKind.*;
import static org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.FORWARD;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.resolve.BindingContext.CAPTURED_IN_CLOSURE;
import static org.jetbrains.kotlin.resolve.BindingContext.IS_UNINITIALIZED;
import static org.jetbrains.kotlin.resolve.BindingContext.TAIL_RECURSION_CALL;
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
@@ -495,12 +496,14 @@ public class JetFlowInformationProvider {
private boolean checkInitializationUsingBackingField(@NotNull VariableInitContext ctxt, @NotNull JetExpression expression) {
VariableDescriptor variableDescriptor = ctxt.variableDescriptor;
if (variableDescriptor instanceof PropertyDescriptor
&& !ctxt.enterInitState.mayBeInitialized() && ctxt.exitInitState.mayBeInitialized()) {
&& !ctxt.enterInitState.mayBeInitialized()
&& ctxt.exitInitState.mayBeInitialized()) {
if (!variableDescriptor.isVar()) return false;
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) return false;
PsiElement property = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor);
assert property instanceof JetProperty;
if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.FINAL && ((JetProperty) property).getSetter() == null) {
JetPropertyAccessor setter = ((JetProperty) property).getSetter();
if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.FINAL && (setter == null || !setter.hasBody())) {
return false;
}
JetExpression variable = expression;
@@ -512,12 +515,7 @@ public class JetFlowInformationProvider {
if (variable instanceof JetSimpleNameExpression) {
JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) variable;
if (simpleNameExpression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) {
if (((PropertyDescriptor) variableDescriptor).getModality() != Modality.FINAL) {
report(Errors.INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER.on(expression, variableDescriptor), ctxt);
}
else {
report(Errors.INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER.on(expression, variableDescriptor), ctxt);
}
trace.record(IS_UNINITIALIZED, (PropertyDescriptor) variableDescriptor);
return true;
}
}
@@ -659,9 +659,6 @@ public interface Errors {
// Properties / locals
DiagnosticFactory1<JetExpression, DeclarationDescriptor> INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<JetExpression, DeclarationDescriptor> INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<JetTypeReference> LOCAL_EXTENSION_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetPropertyAccessor> LOCAL_VARIABLE_WITH_GETTER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetPropertyAccessor> LOCAL_VARIABLE_WITH_SETTER = DiagnosticFactory0.create(ERROR);
@@ -282,11 +282,6 @@ public class DefaultErrorMessages {
MAP.put(VAL_OR_VAR_ON_CATCH_PARAMETER, "''{0}'' on catch parameter is not allowed", TO_STRING);
MAP.put(VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER, "''{0}'' on secondary constructor parameter is not allowed", TO_STRING);
MAP.put(INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER,
"This property cannot be initialized inside ''init'' block because it has a custom setter", NAME);
MAP.put(INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER,
"This property cannot be initialized inside ''init'' block because it has an open setter", NAME);
MAP.put(UNREACHABLE_CODE, "Unreachable code", TO_STRING);
MAP.put(MANY_COMPANION_OBJECTS, "Only one companion object is allowed per class");
@@ -289,4 +289,11 @@ public object ModifierCheckerCore {
val list = listOwner.modifierList ?: return
checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets)
}
}
fun foo(p: Pair<Int?, Int?>) {
val list: MutableList<Int> = LinkedList()
if (p.first != null) {
list.add(p.first as Int)
}
}