From 8860bab9f1cdb68213a92966e27e965d725cc37e Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 20 Aug 2012 18:48:09 +0400 Subject: [PATCH] KT-2643 Support multi-declarations in Data-Flow analysis #KT-2643 fixed --- .../jet/lang/cfg/JetControlFlowBuilder.java | 2 +- .../cfg/JetControlFlowBuilderAdapter.java | 2 +- .../jet/lang/cfg/JetControlFlowProcessor.java | 13 ++++++ .../lang/cfg/JetFlowInformationProvider.java | 21 ++++++---- .../JetControlFlowInstructionsGenerator.java | 2 +- .../VariableDeclarationInstruction.java | 3 +- .../jet/lang/diagnostics/Errors.java | 2 +- .../jet/lang/resolve/BindingContextUtils.java | 2 +- compiler/testData/cfg/MultiDecl.instructions | 40 +++++++++++++++++++ compiler/testData/cfg/MultiDecl.jet | 11 +++++ .../ComponentFunctionReturnTypeMismatch.kt | 4 +- .../DataFlowInfoInMultiDecl.kt | 6 +-- .../MultiDeclarationErrors.kt | 2 +- .../RedeclarationsInMultiDecl.kt | 6 +-- .../kt2631_MultipleDeclaration.kt | 2 +- .../kt2643MultiDeclInControlFlow.kt | 27 +++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 +++ 17 files changed, 126 insertions(+), 24 deletions(-) create mode 100644 compiler/testData/cfg/MultiDecl.instructions create mode 100644 compiler/testData/cfg/MultiDecl.jet create mode 100644 compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index b1822200b66..d4629290aa8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -78,7 +78,7 @@ public interface JetControlFlowBuilder { void write(@NotNull JetElement assignment, @NotNull JetElement lValue); void declare(@NotNull JetParameter parameter); - void declare(@NotNull JetProperty property); + void declare(@NotNull JetVariableDeclaration property); // Other void unsupported(JetElement element); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java index cb3d67b2b64..8fde7bb070c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -208,7 +208,7 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder { } @Override - public void declare(@NotNull JetProperty property) { + public void declare(@NotNull JetVariableDeclaration property) { assert builder != null; builder.declare(property); } 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 d467de2ca52..a6fd8be1299 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -742,6 +742,19 @@ public class JetControlFlowProcessor { } } + @Override + public void visitMultiDeclaration(JetMultiDeclaration declaration) { + JetExpression initializer = declaration.getInitializer(); + if (initializer != null) { + builder.read(initializer); + } + List entries = declaration.getEntries(); + for (JetMultiDeclarationEntry entry : entries) { + builder.declare(entry); + builder.write(entry, entry); + } + } + @Override public void visitPropertyAccessor(JetPropertyAccessor accessor) { processLocalDeclaration(accessor); 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 de2f53bf502..183d5081d68 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -451,8 +451,8 @@ public class JetFlowInformationProvider { PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier(); if (nameIdentifier == null) return; if (!VariableUseState.isUsed(variableUseState)) { - if (element instanceof JetProperty) { - trace.report(Errors.UNUSED_VARIABLE.on((JetProperty) element, variableDescriptor)); + if (element instanceof JetVariableDeclaration) { + trace.report(Errors.UNUSED_VARIABLE.on((JetVariableDeclaration) element, variableDescriptor)); } else if (element instanceof JetParameter) { PsiElement psiElement = element.getParent().getParent(); @@ -468,13 +468,18 @@ public class JetFlowInformationProvider { } } } - else if (variableUseState == ONLY_WRITTEN_NEVER_READ && element instanceof JetProperty) { - trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor)); + else if (variableUseState == ONLY_WRITTEN_NEVER_READ && element instanceof JetVariableDeclaration) { + trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetVariableDeclaration) element, variableDescriptor)); } - else if (variableUseState == LAST_WRITTEN && element instanceof JetProperty) { - JetExpression initializer = ((JetProperty) element).getInitializer(); - if (initializer != null) { - trace.report(Errors.VARIABLE_WITH_REDUNDANT_INITIALIZER.on(initializer, variableDescriptor)); + else if (variableUseState == LAST_WRITTEN && element instanceof JetVariableDeclaration) { + if (element instanceof JetProperty) { + JetExpression initializer = ((JetProperty) element).getInitializer(); + if (initializer != null) { + trace.report(Errors.VARIABLE_WITH_REDUNDANT_INITIALIZER.on(initializer, variableDescriptor)); + } + } + else if (element instanceof JetMultiDeclarationEntry) { + trace.report(VARIABLE_WITH_REDUNDANT_INITIALIZER.on(element, variableDescriptor)); } } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index f888d1711ef..86f4dfa7954 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -229,7 +229,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd } @Override - public void declare(@NotNull JetProperty property) { + public void declare(@NotNull JetVariableDeclaration property) { add(new VariableDeclarationInstruction(property)); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/VariableDeclarationInstruction.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/VariableDeclarationInstruction.java index c108d146ead..1e5b4fad9ce 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/VariableDeclarationInstruction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/VariableDeclarationInstruction.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetParameter; import org.jetbrains.jet.lang.psi.JetProperty; +import org.jetbrains.jet.lang.psi.JetVariableDeclaration; /** * @author svtk @@ -29,7 +30,7 @@ public class VariableDeclarationInstruction extends InstructionWithNext { super(element); } - protected VariableDeclarationInstruction(@NotNull JetProperty element) { + protected VariableDeclarationInstruction(@NotNull JetVariableDeclaration element) { super(element); } 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 630aee00a21..fa8ad97e514 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -151,7 +151,7 @@ public interface Errors { DiagnosticFactory1 UNINITIALIZED_VARIABLE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 UNINITIALIZED_PARAMETER = DiagnosticFactory1.create(ERROR); - UnusedElementDiagnosticFactory UNUSED_VARIABLE = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER); + UnusedElementDiagnosticFactory UNUSED_VARIABLE = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER); UnusedElementDiagnosticFactory UNUSED_PARAMETER = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER); UnusedElementDiagnosticFactory ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER); DiagnosticFactory1 VARIABLE_WITH_REDUNDANT_INITIALIZER = DiagnosticFactory1.create(WARNING); 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 aaa97de4b1c..78bfc7e0cf4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java @@ -93,7 +93,7 @@ public class BindingContextUtils { @Nullable public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) { DeclarationDescriptor descriptor = null; - if (!onlyReference && (element instanceof JetProperty || element instanceof JetParameter)) { + if (!onlyReference && (element instanceof JetVariableDeclaration || element instanceof JetParameter)) { descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); } else if (element instanceof JetSimpleNameExpression) { diff --git a/compiler/testData/cfg/MultiDecl.instructions b/compiler/testData/cfg/MultiDecl.instructions new file mode 100644 index 00000000000..5282e4dc62d --- /dev/null +++ b/compiler/testData/cfg/MultiDecl.instructions @@ -0,0 +1,40 @@ +== C == +class C { + fun component1() = 1 + fun component2() = 2 +} +--------------------- +l0: + NEXT:[] PREV:[] +l1: + NEXT:[] PREV:[] +error: + NEXT:[] PREV:[] +sink: + NEXT:[] PREV:[, ] +===================== +== test == +fun test(c: C) { + val (a, b) = c + val d = 1 +} +--------------------- +l0: + NEXT:[v(c: C)] PREV:[] + v(c: C) NEXT:[w(c)] PREV:[] + w(c) NEXT:[r(c)] PREV:[v(c: C)] + r(c) NEXT:[v(a)] PREV:[w(c)] + v(a) NEXT:[w(a)] PREV:[r(c)] + w(a) NEXT:[v(b)] PREV:[v(a)] + v(b) NEXT:[w(b)] PREV:[w(a)] + w(b) NEXT:[v(val d = 1)] PREV:[v(b)] + v(val d = 1) NEXT:[r(1)] PREV:[w(b)] + r(1) NEXT:[w(d)] PREV:[v(val d = 1)] + w(d) NEXT:[] PREV:[r(1)] +l1: + NEXT:[] PREV:[w(d)] +error: + NEXT:[] PREV:[] +sink: + NEXT:[] PREV:[, ] +===================== diff --git a/compiler/testData/cfg/MultiDecl.jet b/compiler/testData/cfg/MultiDecl.jet new file mode 100644 index 00000000000..90ee36555d0 --- /dev/null +++ b/compiler/testData/cfg/MultiDecl.jet @@ -0,0 +1,11 @@ +package n + +class C { + fun component1() = 1 + fun component2() = 2 +} + +fun test(c: C) { + val (a, b) = c + val d = 1 +} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/ComponentFunctionReturnTypeMismatch.kt b/compiler/testData/diagnostics/tests/declarationChecks/ComponentFunctionReturnTypeMismatch.kt index f7b8352d99c..31ece10edbf 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/ComponentFunctionReturnTypeMismatch.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/ComponentFunctionReturnTypeMismatch.kt @@ -3,6 +3,6 @@ class A { fun component2() : Int = 2 } -fun a(aa : A) { - val (a: String, b1: String) = aa +fun a(aa : A) { + val (a: String, b1: String) = aa } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInfoInMultiDecl.kt b/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInfoInMultiDecl.kt index 074e4c00280..1e2ea2247c8 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInfoInMultiDecl.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInfoInMultiDecl.kt @@ -5,10 +5,10 @@ class A { fun a(aa : A?, b : Any) { if (aa != null) { - val (a1, b1) = aa; + val (a1, b1) = aa; } if (b is A) { - val (a1, b1) = b; + val (a1, b1) = b; } -} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/declarationChecks/MultiDeclarationErrors.kt b/compiler/testData/diagnostics/tests/declarationChecks/MultiDeclarationErrors.kt index aa5a66a34a1..f1ba7a307b6 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/MultiDeclarationErrors.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/MultiDeclarationErrors.kt @@ -9,7 +9,7 @@ class MyClass2 {} fun MyClass2.component1() = 1.2 fun MyClass2.component1() = 1.3 -fun test(mc1: MyClass, mc2: MyClass2) { +fun test(mc1: MyClass, mc2: MyClass2) { val (a, b) = mc1 val (c) = mc2 diff --git a/compiler/testData/diagnostics/tests/declarationChecks/RedeclarationsInMultiDecl.kt b/compiler/testData/diagnostics/tests/declarationChecks/RedeclarationsInMultiDecl.kt index 5dadc89b695..bb8c2edb00a 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/RedeclarationsInMultiDecl.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/RedeclarationsInMultiDecl.kt @@ -4,11 +4,11 @@ class A { } fun a() { - val (a, a) = A() - val (x, y) = A(); + val (a, a) = A() + val (x, y) = A(); val b = 1 use(b) - val (b, y) = A(); + val (b, y) = A(); } diff --git a/compiler/testData/diagnostics/tests/declarationChecks/kt2631_MultipleDeclaration.kt b/compiler/testData/diagnostics/tests/declarationChecks/kt2631_MultipleDeclaration.kt index aa72ec07d46..b1a7426ccc3 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/kt2631_MultipleDeclaration.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/kt2631_MultipleDeclaration.kt @@ -10,7 +10,7 @@ class MyClass2 {} fun MyClass2.component1() = 1.2 -fun test(mc1: MyClass, mc2: MyClass2) { +fun test(mc1: MyClass, mc2: MyClass2) { val (a, b) = mc1 a : Int b : String diff --git a/compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt b/compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt new file mode 100644 index 00000000000..50c4de5b042 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt @@ -0,0 +1,27 @@ +//KT-2643 Support multi-declarations in Data-Flow analysis +package n + +class C { + fun component1() = 1 + fun component2() = 2 +} + +fun test1(c: C) { + val (a, b) = c +} + +fun test2(c: C) { + val (a, b) = c + a + 3 +} + +fun test3(c: C) { + var (a, b) = c + a = 3 +} + +fun test4(c: C) { + var (a, b) = c + a = 3 + a + 1 +} \ 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 cc534d0bf54..eb5eb482806 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1088,6 +1088,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/declarationChecks/kt2631_MultipleDeclaration.kt"); } + @TestMetadata("kt2643MultiDeclInControlFlow.kt") + public void testKt2643MultiDeclInControlFlow() throws Exception { + doTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt"); + } + @TestMetadata("kt559.kt") public void testKt559() throws Exception { doTest("compiler/testData/diagnostics/tests/declarationChecks/kt559.kt");