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 a6fd8be1299..b3d499f97bd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator import org.jetbrains.jet.lang.cfg.pseudocode.LocalDeclarationInstruction; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; +import org.jetbrains.jet.lang.diagnostics.AbstractDiagnosticFactory; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; @@ -529,9 +530,13 @@ public class JetControlFlowProcessor { } JetParameter loopParameter = expression.getLoopParameter(); if (loopParameter != null) { - builder.declare(loopParameter); - builder.write(loopParameter, loopParameter); + value(loopParameter, inCondition); } + else { + JetMultiDeclaration multiParameter = expression.getMultiParameter(); + value(multiParameter, inCondition); + } + // TODO : primitive cases Label loopExitPoint = builder.createUnboundLabel(); Label conditionEntryPoint = builder.createUnboundLabel(); @@ -632,8 +637,8 @@ public class JetControlFlowProcessor { @Override public void visitParameter(JetParameter parameter) { - JetExpression defaultValue = parameter.getDefaultValue(); builder.declare(parameter); + JetExpression defaultValue = parameter.getDefaultValue(); if (defaultValue != null) { value(defaultValue, inCondition); } 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 183d5081d68..73910d351b4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -447,40 +447,39 @@ public class JetFlowInformationProvider { } else if (instruction instanceof VariableDeclarationInstruction) { JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); - if (element instanceof JetNamedDeclaration) { - PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier(); - if (nameIdentifier == null) return; - if (!VariableUseState.isUsed(variableUseState)) { - if (element instanceof JetVariableDeclaration) { - trace.report(Errors.UNUSED_VARIABLE.on((JetVariableDeclaration) element, variableDescriptor)); - } - else if (element instanceof JetParameter) { - PsiElement psiElement = element.getParent().getParent(); - if (psiElement instanceof JetFunction) { - boolean isMain = (psiElement instanceof JetNamedFunction) && JetMainDetector.isMain((JetNamedFunction) psiElement); - if (psiElement instanceof JetFunctionLiteral) return; - DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement); - assert descriptor instanceof FunctionDescriptor : psiElement.getText(); - FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; - if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) { - trace.report(Errors.UNUSED_PARAMETER.on((JetParameter) element, variableDescriptor)); - } + if (!(element instanceof JetNamedDeclaration)) return; + PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier(); + if (nameIdentifier == null) return; + if (!VariableUseState.isUsed(variableUseState)) { + if (JetPsiUtil.isVariableNotParameterDeclaration(element)) { + trace.report(Errors.UNUSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor)); + } + else if (element instanceof JetParameter) { + PsiElement psiElement = element.getParent().getParent(); + if (psiElement instanceof JetFunction) { + boolean isMain = (psiElement instanceof JetNamedFunction) && JetMainDetector.isMain((JetNamedFunction) psiElement); + if (psiElement instanceof JetFunctionLiteral) return; + DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement); + assert descriptor instanceof FunctionDescriptor : psiElement.getText(); + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; + if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) { + trace.report(Errors.UNUSED_PARAMETER.on((JetParameter) 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 == ONLY_WRITTEN_NEVER_READ && JetPsiUtil.isVariableNotParameterDeclaration(element)) { + trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, 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 (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)); - } + else if (element instanceof JetMultiDeclarationEntry) { + trace.report(VARIABLE_WITH_REDUNDANT_INITIALIZER.on(element, variableDescriptor)); } } } 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 e85e93c6689..7149e854787 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -149,7 +149,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/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 1200c788e7e..2c1303c0586 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -336,4 +336,12 @@ public class JetPsiUtil { return null; } } + + public static boolean isVariableNotParameterDeclaration(@NotNull JetDeclaration declaration) { + if (!(declaration instanceof JetVariableDeclaration)) return false; + if (declaration instanceof JetProperty) return true; + assert declaration instanceof JetMultiDeclarationEntry; + JetMultiDeclarationEntry multiDeclarationEntry = (JetMultiDeclarationEntry) declaration; + return !(multiDeclarationEntry.getParent().getParent() instanceof JetForExpression); + } } diff --git a/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt b/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt new file mode 100644 index 00000000000..0b8cac68f51 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt @@ -0,0 +1,17 @@ +// KT-2667 Support multi-declarations in for-loops in control flow analysis +package d + +import java.util.List + +class A { + fun component1() = 1 + fun component2() = 2 + fun component3() = 3 +} + +fun foo(list: List) { + for (var (c1, c2, c3) in list) { + c1 = 1 + c3 + 1 + } +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index d7f2a905697..81a90ea22cb 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1058,6 +1058,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/declarationChecks/ComponentFunctionReturnTypeMismatch.kt"); } + @TestMetadata("DataFlowInMultiDeclInFor.kt") + public void testDataFlowInMultiDeclInFor() throws Exception { + doTest("compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt"); + } + @TestMetadata("DataFlowInfoInMultiDecl.kt") public void testDataFlowInfoInMultiDecl() throws Exception { doTest("compiler/testData/diagnostics/tests/declarationChecks/DataFlowInfoInMultiDecl.kt");