More tests for dead code detection

This commit is contained in:
Andrey Breslav
2011-04-14 13:18:31 +04:00
parent 96526603e4
commit bd73ef4bd9
11 changed files with 187 additions and 39 deletions
@@ -47,9 +47,9 @@ public interface JetControlFlowBuilder {
@Nullable
JetElement getCurrentSubroutine();
void returnValue(@NotNull JetElement subroutine);
void returnNoValue(@NotNull JetElement expression, @NotNull JetElement subroutine);
void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine);
void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine);
void writeNode(@NotNull JetElement assignment, @NotNull JetElement lValue);
@@ -110,13 +110,13 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
}
@Override
public void returnValue(@NotNull JetElement subroutine) {
builder.returnValue(subroutine);
public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
builder.returnValue(returnExpression, subroutine);
}
@Override
public void returnNoValue(@NotNull JetElement expression, @NotNull JetElement subroutine) {
builder.returnNoValue(expression, subroutine);
public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) {
builder.returnNoValue(returnExpression, subroutine);
}
@Override
@@ -346,7 +346,9 @@ public class JetControlFlowProcessor {
@Override
public void visitForExpression(JetForExpression expression) {
value(expression.getLoopRange(), false, false);
// TODO : primitive cases
Label loopExitPoint = builder.createUnboundLabel();
builder.nondeterministicJump(loopExitPoint);
Label loopEntryPoint = builder.enterLoop(expression, loopExitPoint);
JetExpression body = expression.getBody();
if (body != null) {
@@ -421,7 +423,7 @@ public class JetControlFlowProcessor {
builder.returnNoValue(expression, subroutine);
}
else {
builder.returnValue(subroutine);
builder.returnValue(expression, subroutine);
}
}
}
@@ -9,7 +9,7 @@ import java.util.Collections;
/**
* @author abreslav
*/
public abstract class InstructionWithNext extends JetElementInstruction {
public abstract class InstructionWithNext extends JetElementInstructionImpl {
private Instruction next;
protected InstructionWithNext(@NotNull JetElement element) {
@@ -150,13 +150,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
}
@Override
public void returnValue(@NotNull JetElement subroutine) {
add(new ReturnValueInstruction(getExitPoint(subroutine)));
public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
add(new ReturnValueInstruction(returnExpression, getExitPoint(subroutine)));
}
@Override
public void returnNoValue(@NotNull JetElement expression, @NotNull JetElement subroutine) {
add(new ReturnNoValueInstruction(expression, getExitPoint(subroutine)));
public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) {
add(new ReturnNoValueInstruction(returnExpression, getExitPoint(subroutine)));
}
@Override
@@ -6,15 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
/**
* @author abreslav
*/
public abstract class JetElementInstruction extends Instruction {
protected final JetElement element;
public JetElementInstruction(@NotNull JetElement element) {
this.element = element;
}
public interface JetElementInstruction {
@NotNull
public JetElement getElement() {
return element;
}
JetElement getElement();
}
@@ -0,0 +1,21 @@
package org.jetbrains.jet.lang.cfg.pseudocode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetElement;
/**
* @author abreslav
*/
public abstract class JetElementInstructionImpl extends Instruction implements JetElementInstruction {
protected final JetElement element;
public JetElementInstructionImpl(@NotNull JetElement element) {
this.element = element;
}
@NotNull
@Override
public JetElement getElement() {
return element;
}
}
@@ -7,7 +7,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
/**
* @author abreslav
*/
public class ReturnNoValueInstruction extends AbstractJumpInstruction {
public class ReturnNoValueInstruction extends AbstractJumpInstruction implements JetElementInstruction {
private final JetElement element;
@@ -16,6 +16,8 @@ public class ReturnNoValueInstruction extends AbstractJumpInstruction {
this.element = element;
}
@NotNull
@Override
public JetElement getElement() {
return element;
}
@@ -1,14 +1,20 @@
package org.jetbrains.jet.lang.cfg.pseudocode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.Label;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
/**
* @author abreslav
*/
public class ReturnValueInstruction extends AbstractJumpInstruction {
public class ReturnValueInstruction extends AbstractJumpInstruction implements JetElementInstruction {
public ReturnValueInstruction(Label targetLabel) {
private final JetElement element;
public ReturnValueInstruction(@NotNull JetExpression returnExpression, @NotNull Label targetLabel) {
super(targetLabel);
this.element = returnExpression;
}
@Override
@@ -20,4 +26,10 @@ public class ReturnValueInstruction extends AbstractJumpInstruction {
public String toString() {
return "ret(*) " + getTargetLabel();
}
@NotNull
@Override
public JetElement getElement() {
return element;
}
}
@@ -286,8 +286,12 @@ public class TopDownAnalyzer {
List<JetElement> unreachableElements = new ArrayList<JetElement>();
flowInformationProvider.collectUnreachableExpressions(function, unreachableElements);
for (JetElement unreachableElement : unreachableElements) {
semanticServices.getErrorHandler().genericError(unreachableElement.getNode(), "Unreachable code");
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
Set<JetElement> rootElements = findRootExpressions(unreachableElements);
for (JetElement element : rootElements) {
semanticServices.getErrorHandler().genericError(element.getNode(), "Unreachable code");
}
}
else {
@@ -310,6 +314,28 @@ public class TopDownAnalyzer {
}
}
private Set<JetElement> findRootExpressions(List<JetElement> unreachableElements) {
Set<JetElement> rootElements = new HashSet<JetElement>();
final Set<JetElement> shadowedElements = new HashSet<JetElement>();
JetVisitor shadowAllChildren = new JetVisitor() {
@Override
public void visitJetElement(JetElement elem) {
if (shadowedElements.add(elem)) {
elem.acceptChildren(this);
}
}
};
for (JetElement element : unreachableElements) {
if (shadowedElements.contains(element)) continue;
element.acceptChildren(shadowAllChildren);
rootElements.removeAll(shadowedElements);
rootElements.add(element);
}
return rootElements;
}
private JetFlowInformationProvider computeFlowData(@NotNull JetDeclaration declaration, @NotNull JetExpression bodyExpression) {
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
@@ -415,8 +441,8 @@ public class TopDownAnalyzer {
@Override
public void visitInstruction(Instruction instruction) {
if (instruction instanceof JetElementInstruction) {
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
if (instruction instanceof JetElementInstructionImpl) {
JetElementInstructionImpl elementInstruction = (JetElementInstructionImpl) instruction;
semanticServices.getErrorHandler().genericError(elementInstruction.getElement().getNode(), "Unsupported by control-flow builder " + elementInstruction.getElement());
}
else {
+103 -10
View File
@@ -3,6 +3,24 @@ fun t1() {
<error>1</error>
}
fun t1a() {
return
<error>return</error>
<error>1</error>
}
fun t1b() {
return
<error>return 1</error>
<error>1</error>
}
fun t1c() {
return 1
<error>return</error>
<error>1</error>
}
fun t2() {
if (1 > 2)
return
@@ -10,6 +28,16 @@ fun t2() {
<error>1</error>
}
fun t2a() {
if (1 > 2) {
return
<error>1</error>
} else { return
<error>2</error>
}
<error>1</error>
}
fun t3() {
if (1 > 2)
return 2
@@ -25,14 +53,79 @@ fun t4(a : Boolean) {
<error>1</error>
}
//fun t5() {
// do {
// return
// }
// while (1 > 2)
// 1
//}
fun t4break(a : Boolean) {
do {
break
}
while (<error>a</error>)
1
}
//fun blockAndAndMismatch() : Boolean {
// (return true) || (return false)
//}
fun t5() {
do {
return
<error>2</error>
}
while (<error>1 > 2</error>)
<error>1</error>
}
fun t6() {
while (1 > 2) {
return
<error>2</error>
}
1
}
fun t6break() {
while (1 > 2) {
break
<error>2</error>
}
1
}
fun t7(b : Int) {
for (i in 1..b) {
return
<error>2</error>
}
1
}
fun t7break(b : Int) {
for (i in 1..b) {
return
<error>2</error>
}
1
}
fun t7() {
try {
return
<error>2</error>
}
catch (e : Any) {
2
}
1 // this is OK, like in Java
}
fun t8() {
try {
return
<error>2</error>
}
catch (e : Any) {
return
<error>2</error>
}
<error>1</error>
}
fun blockAndAndMismatch() : Boolean {
<error>(return true) || (return false)</error>
<error>1</error>
}