More tests for dead code detection
This commit is contained in:
@@ -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) {
|
||||
|
||||
+4
-4
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user