KT-2667 Support multi-declarations in for-loops in control flow analysis

#KT-2667 fixed
This commit is contained in:
Svetlana Isakova
2012-08-23 14:25:13 +04:00
parent 21774f5288
commit ac39daace6
6 changed files with 68 additions and 34 deletions
@@ -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.LocalDeclarationInstruction;
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; 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.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingContextUtils;
@@ -529,9 +530,13 @@ public class JetControlFlowProcessor {
} }
JetParameter loopParameter = expression.getLoopParameter(); JetParameter loopParameter = expression.getLoopParameter();
if (loopParameter != null) { if (loopParameter != null) {
builder.declare(loopParameter); value(loopParameter, inCondition);
builder.write(loopParameter, loopParameter);
} }
else {
JetMultiDeclaration multiParameter = expression.getMultiParameter();
value(multiParameter, inCondition);
}
// TODO : primitive cases // TODO : primitive cases
Label loopExitPoint = builder.createUnboundLabel(); Label loopExitPoint = builder.createUnboundLabel();
Label conditionEntryPoint = builder.createUnboundLabel(); Label conditionEntryPoint = builder.createUnboundLabel();
@@ -632,8 +637,8 @@ public class JetControlFlowProcessor {
@Override @Override
public void visitParameter(JetParameter parameter) { public void visitParameter(JetParameter parameter) {
JetExpression defaultValue = parameter.getDefaultValue();
builder.declare(parameter); builder.declare(parameter);
JetExpression defaultValue = parameter.getDefaultValue();
if (defaultValue != null) { if (defaultValue != null) {
value(defaultValue, inCondition); value(defaultValue, inCondition);
} }
@@ -447,40 +447,39 @@ public class JetFlowInformationProvider {
} }
else if (instruction instanceof VariableDeclarationInstruction) { else if (instruction instanceof VariableDeclarationInstruction) {
JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
if (element instanceof JetNamedDeclaration) { if (!(element instanceof JetNamedDeclaration)) return;
PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier(); PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier();
if (nameIdentifier == null) return; if (nameIdentifier == null) return;
if (!VariableUseState.isUsed(variableUseState)) { if (!VariableUseState.isUsed(variableUseState)) {
if (element instanceof JetVariableDeclaration) { if (JetPsiUtil.isVariableNotParameterDeclaration(element)) {
trace.report(Errors.UNUSED_VARIABLE.on((JetVariableDeclaration) element, variableDescriptor)); trace.report(Errors.UNUSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor));
} }
else if (element instanceof JetParameter) { else if (element instanceof JetParameter) {
PsiElement psiElement = element.getParent().getParent(); PsiElement psiElement = element.getParent().getParent();
if (psiElement instanceof JetFunction) { if (psiElement instanceof JetFunction) {
boolean isMain = (psiElement instanceof JetNamedFunction) && JetMainDetector.isMain((JetNamedFunction) psiElement); boolean isMain = (psiElement instanceof JetNamedFunction) && JetMainDetector.isMain((JetNamedFunction) psiElement);
if (psiElement instanceof JetFunctionLiteral) return; if (psiElement instanceof JetFunctionLiteral) return;
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement); DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement);
assert descriptor instanceof FunctionDescriptor : psiElement.getText(); assert descriptor instanceof FunctionDescriptor : psiElement.getText();
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) { if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) {
trace.report(Errors.UNUSED_PARAMETER.on((JetParameter) element, variableDescriptor)); 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) { else if (element instanceof JetMultiDeclarationEntry) {
if (element instanceof JetProperty) { trace.report(VARIABLE_WITH_REDUNDANT_INITIALIZER.on(element, variableDescriptor));
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));
}
} }
} }
} }
@@ -149,7 +149,7 @@ public interface Errors {
DiagnosticFactory1<JetSimpleNameExpression, VariableDescriptor> UNINITIALIZED_VARIABLE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<JetSimpleNameExpression, VariableDescriptor> UNINITIALIZED_VARIABLE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<JetSimpleNameExpression, ValueParameterDescriptor> UNINITIALIZED_PARAMETER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<JetSimpleNameExpression, ValueParameterDescriptor> UNINITIALIZED_PARAMETER = DiagnosticFactory1.create(ERROR);
UnusedElementDiagnosticFactory<JetVariableDeclaration, VariableDescriptor> UNUSED_VARIABLE = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER); UnusedElementDiagnosticFactory<JetNamedDeclaration, VariableDescriptor> UNUSED_VARIABLE = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER);
UnusedElementDiagnosticFactory<JetParameter, VariableDescriptor> UNUSED_PARAMETER = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER); UnusedElementDiagnosticFactory<JetParameter, VariableDescriptor> UNUSED_PARAMETER = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER);
UnusedElementDiagnosticFactory<JetNamedDeclaration, DeclarationDescriptor> ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER); UnusedElementDiagnosticFactory<JetNamedDeclaration, DeclarationDescriptor> ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE = UnusedElementDiagnosticFactory.create(WARNING, NAME_IDENTIFIER);
DiagnosticFactory1<JetExpression, DeclarationDescriptor> VARIABLE_WITH_REDUNDANT_INITIALIZER = DiagnosticFactory1.create(WARNING); DiagnosticFactory1<JetExpression, DeclarationDescriptor> VARIABLE_WITH_REDUNDANT_INITIALIZER = DiagnosticFactory1.create(WARNING);
@@ -336,4 +336,12 @@ public class JetPsiUtil {
return null; 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);
}
} }
@@ -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<A>) {
for (var (c1, c2, c3) in list) {
c1 = <!UNUSED_VALUE!>1<!>
c3 + 1
}
}
@@ -1058,6 +1058,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/declarationChecks/ComponentFunctionReturnTypeMismatch.kt"); 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") @TestMetadata("DataFlowInfoInMultiDecl.kt")
public void testDataFlowInfoInMultiDecl() throws Exception { public void testDataFlowInfoInMultiDecl() throws Exception {
doTest("compiler/testData/diagnostics/tests/declarationChecks/DataFlowInfoInMultiDecl.kt"); doTest("compiler/testData/diagnostics/tests/declarationChecks/DataFlowInfoInMultiDecl.kt");