Warn about val reassignment via backing field

#KT-16681 In Progress
This commit is contained in:
Mikhail Zarechenskiy
2017-05-04 13:34:25 +03:00
parent e821b25288
commit 7530a9426f
5 changed files with 11 additions and 17 deletions
@@ -34,7 +34,6 @@ import org.jetbrains.kotlin.cfg.pseudocodeTraverser.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.referencedProperty
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors
@@ -400,18 +399,6 @@ class ControlFlowInformationProvider private constructor(
varWithValReassignErrorGenerated: MutableCollection<VariableDescriptor>
): Boolean {
val variableDescriptor = ctxt.variableDescriptor
val propertyDescriptor = variableDescriptor?.referencedProperty
if (KtPsiUtil.isBackingFieldReference(variableDescriptor) && propertyDescriptor != null) {
val accessor = getParentOfType(expression, KtPropertyAccessor::class.java)
if (accessor != null) {
val accessorDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, accessor)
if (propertyDescriptor.getter === accessorDescriptor) {
//val can be reassigned through backing field inside its own getter
return false
}
}
}
val mayBeInitializedNotHere = ctxt.enterInitState?.mayBeInitialized() ?: false
val hasBackingField = (variableDescriptor as? PropertyDescriptor)?.let {
trace.get(BindingContext.BACKING_FIELD_REQUIRED, it)
@@ -469,7 +456,12 @@ class ControlFlowInformationProvider private constructor(
}
}
else {
report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor), ctxt)
if (KtPsiUtil.isBackingFieldReference(variableDescriptor)) {
report(Errors.VAL_REASSIGNMENT_VIA_BACKING_FIELD.on(expression, variableDescriptor), ctxt)
}
else {
report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor), ctxt)
}
}
}
if (isThisOrNoDispatchReceiver) {
@@ -761,6 +761,7 @@ public interface Errors {
DiagnosticFactory0<KtLambdaExpression> UNUSED_LAMBDA_EXPRESSION = DiagnosticFactory0.create(WARNING);
DiagnosticFactory1<KtExpression, DeclarationDescriptor> VAL_REASSIGNMENT = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtExpression, DeclarationDescriptor> VAL_REASSIGNMENT_VIA_BACKING_FIELD = DiagnosticFactory1.create(WARNING);
DiagnosticFactory1<KtExpression, DeclarationDescriptor> CAPTURED_VAL_INITIALIZATION = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtExpression, DeclarationDescriptor> CAPTURED_MEMBER_VAL_INITIALIZATION = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtExpression, DeclarationDescriptor> SETTER_PROJECTED_OUT = DiagnosticFactory1.create(ERROR);
@@ -299,6 +299,7 @@ public class DefaultErrorMessages {
MAP.put(UNUSED_LAMBDA_EXPRESSION, "The lambda expression is unused. If you mean a block, you can use 'run { ... }'");
MAP.put(VAL_REASSIGNMENT, "Val cannot be reassigned", NAME);
MAP.put(VAL_REASSIGNMENT_VIA_BACKING_FIELD, "Val cannot be reassigned via backing field", NAME);
MAP.put(CAPTURED_VAL_INITIALIZATION, "Captured values initialization is forbidden due to possible reassignment", NAME);
MAP.put(CAPTURED_MEMBER_VAL_INITIALIZATION, "Captured member values initialization is forbidden due to possible reassignment", NAME);
MAP.put(SETTER_PROJECTED_OUT, "Setter for ''{0}'' is removed by type projection", NAME);
@@ -1,5 +1,5 @@
val my: Int = 1
get() {
field++
<!VAL_REASSIGNMENT_VIA_BACKING_FIELD!>field<!>++
return field
}
@@ -5,7 +5,7 @@ import java.util.HashSet
val a: MutableSet<String>? = null
get() {
if (a == null) {
field = HashSet()
<!VAL_REASSIGNMENT_VIA_BACKING_FIELD!>field<!> = HashSet()
}
return a
}
@@ -14,7 +14,7 @@ class R {
val b: String? = null
get() {
if (b == null) {
field = "b"
<!VAL_REASSIGNMENT_VIA_BACKING_FIELD!>field<!> = "b"
}
return b
}