diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java index 9f7763864cb..bf42c3ec570 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java @@ -167,7 +167,7 @@ public class JetControlFlowGraphTraverser { } public D getResultInfo() { - return dataMap.get(pseudocode.getSinkInstruction()).getFirst(); + return dataMap.get(pseudocode.getExitInstruction()).getFirst(); } interface InstructionDataMergeStrategy { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 17546d5fb6e..7cc4d35a892 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -711,6 +711,14 @@ public class JetControlFlowProcessor { value(initializer, false); builder.write(property, property); } + for (JetPropertyAccessor accessor : property.getAccessors()) { + value(accessor, false); + } + } + + @Override + public void visitPropertyAccessor(JetPropertyAccessor accessor) { + processLocalDeclaration(accessor); } @Override 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 081b6a894d1..8951b9eaa0c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -41,6 +41,7 @@ import org.jetbrains.jet.plugin.JetMainDetector; import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.resolve.BindingContext.MUST_BE_WRAPPED_IN_A_REF; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; /** @@ -254,7 +255,7 @@ public class JetFlowInformationProvider { if (!error && !processLocalDeclaration) { // error has been generated before, while processing outer function of this local declaration error = checkValReassignment(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), varWithValReassignErrorGenerated); } - if (!error) { + if (!error && processClassOrObject) { error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor)); } if (!error && processClassOrObject) { @@ -265,7 +266,7 @@ public class JetFlowInformationProvider { }); recordInitializedVariables(declaredVariables, traverser.getResultInfo()); - analyzeLocalDeclarations(processLocalDeclaration, pseudocode); + analyzeLocalDeclarations(pseudocode, processLocalDeclaration); } private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, @@ -442,7 +443,7 @@ public class JetFlowInformationProvider { } } - private void analyzeLocalDeclarations(boolean processLocalDeclaration, Pseudocode pseudocode) { + private void analyzeLocalDeclarations(Pseudocode pseudocode, boolean processLocalDeclaration) { for (Instruction instruction : pseudocode.getInstructions()) { if (instruction instanceof LocalDeclarationInstruction) { JetElement element = ((LocalDeclarationInstruction) instruction).getElement(); @@ -595,6 +596,7 @@ public class JetFlowInformationProvider { !DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return; VariableStatus variableStatus = enterData.get(variableDescriptor); if (instruction instanceof WriteValueInstruction) { + if (trace.get(MUST_BE_WRAPPED_IN_A_REF, variableDescriptor)) return; JetElement element = ((WriteValueInstruction) instruction).getElement(); if (variableStatus != VariableStatus.READ) { if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java index 1cb41c0d92a..8a3d69534ac 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -66,12 +66,14 @@ public class ControlFlowAnalyzer { } for (Map.Entry entry : context.getProperties().entrySet()) { JetProperty property = entry.getKey(); + if (!context.completeAnalysisNeeded(property)) continue; PropertyDescriptor propertyDescriptor = entry.getValue(); checkProperty(property, propertyDescriptor); } } private void checkClassOrObject(JetClassOrObject klass) { + // A pseudocode of class initialization corresponds to a class JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) klass, (JetExpression) klass, flowDataTraceFactory, context.getTrace()); flowInformationProvider.markUninitializedVariables((JetElement) klass, context.isDeclaredLocally()); } @@ -95,7 +97,9 @@ public class ControlFlowAnalyzer { flowInformationProvider.checkDefiniteReturn(function, expectedReturnType); - flowInformationProvider.markUninitializedVariables(function.asElement(), context.isDeclaredLocally()); + // Property accessor is checked through initialization of a class check (at 'checkClassOrObject') + boolean isPropertyAccessor = function instanceof JetPropertyAccessor; + flowInformationProvider.markUninitializedVariables(function.asElement(), context.isDeclaredLocally() || isPropertyAccessor); flowInformationProvider.markUnusedVariables(function.asElement()); diff --git a/compiler/testData/cfg/AnonymousInitializers.instructions b/compiler/testData/cfg/AnonymousInitializers.instructions index d7025fa1f2a..4636a66a836 100644 --- a/compiler/testData/cfg/AnonymousInitializers.instructions +++ b/compiler/testData/cfg/AnonymousInitializers.instructions @@ -1,3 +1,16 @@ +== get_j == +get() = 20 +--------------------- +l0: + NEXT:[r(20)] PREV:[] + r(20) NEXT:[] PREV:[] +l1: + NEXT:[] PREV:[r(20)] +error: + NEXT:[] PREV:[] +sink: + NEXT:[] PREV:[] +===================== == AnonymousInitializers == class AnonymousInitializers() { val k = 34 @@ -24,23 +37,22 @@ l0: r(12) NEXT:[w($i)] PREV:[v(val i: Int)] w($i) NEXT:[v(val j: Int get() = 20) ] PREV:[r(12)] v(val j: Int - get() = 20) NEXT:[r(13)] PREV:[w($i)] - r(13) NEXT:[w($i)] PREV:[v(val j: Int get() = 20) ] + get() = 20) NEXT:[jmp?(l2)] PREV:[w($i)] + jmp?(l2) NEXT:[r(13), d(get() = 20)] PREV:[v(val j: Int get() = 20) ] + d(get() = 20) NEXT:[] PREV:[jmp?(l2)] +l2: + r(13) NEXT:[w($i)] PREV:[jmp?(l2)] w($i) NEXT:[] PREV:[r(13)] l1: NEXT:[] PREV:[w($i)] error: NEXT:[] PREV:[] sink: - NEXT:[] PREV:[] -===================== -== get_j == -get() = 20 ---------------------- -l0: + NEXT:[] PREV:[d(get() = 20), ] +l3: NEXT:[r(20)] PREV:[] r(20) NEXT:[] PREV:[] -l1: +l4: NEXT:[] PREV:[r(20)] error: NEXT:[] PREV:[] diff --git a/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.jet b/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.jet index 964b8dfbb54..f46d35ca6c3 100644 --- a/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.jet +++ b/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.jet @@ -328,7 +328,7 @@ fun func() { val a = object { val x = b { - b = 4 + b = 4 $b = 3 } } diff --git a/compiler/testData/diagnostics/tests/UnusedVariables.jet b/compiler/testData/diagnostics/tests/UnusedVariables.jet index a623c336836..4ec287864b8 100644 --- a/compiler/testData/diagnostics/tests/UnusedVariables.jet +++ b/compiler/testData/diagnostics/tests/UnusedVariables.jet @@ -93,7 +93,7 @@ class MyTest() { fun testInnerFunctions() { var y = 1 fun foo() { - y = 1 + y = 1 } var z = 1 fun bar() { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1191.jet b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1191.jet new file mode 100644 index 00000000000..97a32cf86dd --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1191.jet @@ -0,0 +1,21 @@ +//KT-1191 Wrong detection of unused parameters +package kt1191 + +trait FunctionalList { + val size: Int + val head: T + val tail: FunctionalList +} + +fun FunctionalList.plus(element: T) : FunctionalList = object: FunctionalList { + override val size: Int + get() = 1 + this@plus.size + override val tail: FunctionalList + get() = this@plus + override val head: T + get() = element +} + +fun foo(unused: Int) = object { + val a : Int get() = unused +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1219.1301.jet b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1219.1301.jet new file mode 100644 index 00000000000..1716e79fa54 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt1219.1301.jet @@ -0,0 +1,25 @@ +//KT-1219 Incorrect 'unused value' error in closures +//+JDK + +package kt1219 + +fun Iterable.fold(var r: R, op: (T, R) -> R) : R { + this.foreach { r = op(it, r) } //unused value here + return r +} + +//KT-1301 Modification of local of outer function in a local function should not be marked as unused assignment +fun foo(){ + var local = 0 + fun bar(){ + local = 1 + } + + bar() + System.out?.println(local) +} + +fun Iterable.foreach(operation: (element: T) -> Unit) { + for (elem in this) + operation(elem) +} diff --git a/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet b/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet index 50a52f77d22..e2590a060af 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet +++ b/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet @@ -23,7 +23,7 @@ fun foo() { 2 } else { - z = 34 + z = 34 } } val f: ()-> Int = r @@ -74,7 +74,7 @@ fun testCoercionToUnit() { var x = 43 val checkType = { if (true) { - x = 4 + x = 4 } else { 45 } diff --git a/compiler/testData/diagnostics/tests/regressions/kt235.jet b/compiler/testData/diagnostics/tests/regressions/kt235.jet index 0fd87b03479..33bdd59a7e4 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt235.jet +++ b/compiler/testData/diagnostics/tests/regressions/kt235.jet @@ -31,7 +31,7 @@ fun main(args: Array) { var m: MyNumber = MyNumber() val a = { (): MyNumber -> - m++ + m++ } } diff --git a/idea/testData/checker/infos/WrapIntoRef.jet b/idea/testData/checker/infos/WrapIntoRef.jet index 886b601bbfa..93458833d84 100644 --- a/idea/testData/checker/infos/WrapIntoRef.jet +++ b/idea/testData/checker/infos/WrapIntoRef.jet @@ -1,19 +1,19 @@ fun refs() { var a = 1 val v = { - a = 2 + a = 2 } var x = 1 val b = object { fun foo() { - x = 2 + x = 2 } } var y = 1 fun foo() { - y = 1 + y = 1 } }