diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 73910d351b4..7a55aaa41e3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -255,10 +255,12 @@ public class JetFlowInformationProvider { } } - private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, - @NotNull JetExpression expression, - @NotNull VariableInitState enterInitState, - @NotNull Collection varWithValReassignErrorGenerated) { + private boolean checkValReassignment( + @NotNull VariableDescriptor variableDescriptor, + @NotNull JetExpression expression, + @NotNull VariableInitState enterInitState, + @NotNull Collection varWithValReassignErrorGenerated + ) { boolean isInitializedNotHere = enterInitState.isInitialized; if (expression.getParent() instanceof JetProperty && ((JetProperty)expression).getInitializer() != null) { isInitializedNotHere = false; @@ -267,6 +269,14 @@ public class JetFlowInformationProvider { if (variableDescriptor instanceof PropertyDescriptor) { hasBackingField = trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor); } + if (variableDescriptor.isVar() && variableDescriptor instanceof PropertyDescriptor) { + DeclarationDescriptor descriptor = BindingContextUtils.getEnclosingDescriptor(trace.getBindingContext(), expression); + PropertySetterDescriptor setterDescriptor = ((PropertyDescriptor) variableDescriptor).getSetter(); + if (Visibilities.isVisible(variableDescriptor, descriptor) && !Visibilities.isVisible(setterDescriptor, descriptor) && setterDescriptor != null) { + trace.report(Errors.INVISIBLE_SETTER.on(expression, variableDescriptor, setterDescriptor.getVisibility(), variableDescriptor.getContainingDeclaration())); + return true; + } + } if ((isInitializedNotHere || !hasBackingField) && !variableDescriptor.isVar() && !varWithValReassignErrorGenerated.contains(variableDescriptor)) { boolean hasReassignMethodReturningUnit = false; JetSimpleNameExpression operationReference = null; @@ -365,9 +375,7 @@ public class JetFlowInformationProvider { } if (insideSelfAccessors) return false; - JetNamedDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class); - DeclarationDescriptor declarationDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, parentDeclaration); - if (declarationDescriptor == null) return false; + DeclarationDescriptor declarationDescriptor = BindingContextUtils.getEnclosingDescriptor(trace.getBindingContext(), element); DeclarationDescriptor containingDeclaration = variableDescriptor.getContainingDeclaration(); if ((containingDeclaration instanceof ClassDescriptor) && DescriptorUtils.isAncestor(containingDeclaration, declarationDescriptor, false)) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 500918719f7..dd7ac85a16f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -173,6 +173,7 @@ public interface Errors { SimpleDiagnosticFactory UNUSED_FUNCTION_LITERAL = SimpleDiagnosticFactory.create(WARNING); DiagnosticFactory1 VAL_REASSIGNMENT = DiagnosticFactory1.create(ERROR); + DiagnosticFactory3 INVISIBLE_SETTER = DiagnosticFactory3.create(ERROR); DiagnosticFactory1 INITIALIZATION_BEFORE_DECLARATION = DiagnosticFactory1.create(ERROR); SimpleDiagnosticFactory VARIABLE_EXPECTED = SimpleDiagnosticFactory.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index adb4ec7b05b..126a5a7a46c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -184,6 +184,7 @@ public class DefaultErrorMessages { MAP.put(UNUSED_FUNCTION_LITERAL, "The function literal is unused. If you mean block, you can use 'run { ... }'"); MAP.put(VAL_REASSIGNMENT, "Val cannot be reassigned", NAME); + MAP.put(INVISIBLE_SETTER, "Cannot assign to ''{0}'': the setter is ''{1}'' in ''{2}''", NAME, TO_STRING, NAME); MAP.put(INITIALIZATION_BEFORE_DECLARATION, "Variable cannot be initialized before declaration", NAME); MAP.put(VARIABLE_EXPECTED, "Variable expected"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java index f044c21436b..34d09977ebb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Lists; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -30,6 +31,8 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import static org.jetbrains.jet.lang.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR; + /** * @author abreslav * @author svtk @@ -226,4 +229,15 @@ public class BindingContextUtils { } return value; } + + @NotNull + public static DeclarationDescriptor getEnclosingDescriptor(@NotNull BindingContext context, @NotNull JetElement element) { + JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class); + if (declaration instanceof JetFunctionLiteral) { + return getEnclosingDescriptor(context, declaration); + } + DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, declaration); + assert descriptor != null : "No descriptor for named declaration: " + declaration.getText() + "\n(of type " + declaration.getClass() + ")"; + return descriptor; + } } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2330.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2330.kt new file mode 100644 index 00000000000..3f2373486d5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2330.kt @@ -0,0 +1,53 @@ +//KT-2330 Check visibility of getters and setters correspondingly +package a + +class P { + var x : Int = 0 + private set + + var y : Int = 0 + + val other = P(); + + { + x = 23 + other.x = 4 + } + + val testInGetter : Int + get() { + x = 33 + return 3 + } +} + +fun foo() { + val p = P() + p.x = 34 //should be an error here + p.y = 23 + + fun inner() { + p.x = 44 + } +} + +class R { + val p = P(); + { + p.x = 42 + } + + val testInGetterInOtherClass : Int + get() { + p.x = 33 + return 3 + } +} + +fun test() { + val o = object { + fun run() { + p.x = 43 + } + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 33ba5f88744..203a9b3a443 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -869,6 +869,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2226.kt"); } + @TestMetadata("kt2330.kt") + public void testKt2330() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2330.kt"); + } + @TestMetadata("kt510.kt") public void testKt510() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt510.kt");