More tests for dead code detection
This commit is contained in:
@@ -47,9 +47,9 @@ public interface JetControlFlowBuilder {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
JetElement getCurrentSubroutine();
|
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);
|
void writeNode(@NotNull JetElement assignment, @NotNull JetElement lValue);
|
||||||
|
|
||||||
|
|||||||
@@ -110,13 +110,13 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void returnValue(@NotNull JetElement subroutine) {
|
public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
|
||||||
builder.returnValue(subroutine);
|
builder.returnValue(returnExpression, subroutine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void returnNoValue(@NotNull JetElement expression, @NotNull JetElement subroutine) {
|
public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) {
|
||||||
builder.returnNoValue(expression, subroutine);
|
builder.returnNoValue(returnExpression, subroutine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -346,7 +346,9 @@ public class JetControlFlowProcessor {
|
|||||||
@Override
|
@Override
|
||||||
public void visitForExpression(JetForExpression expression) {
|
public void visitForExpression(JetForExpression expression) {
|
||||||
value(expression.getLoopRange(), false, false);
|
value(expression.getLoopRange(), false, false);
|
||||||
|
// TODO : primitive cases
|
||||||
Label loopExitPoint = builder.createUnboundLabel();
|
Label loopExitPoint = builder.createUnboundLabel();
|
||||||
|
builder.nondeterministicJump(loopExitPoint);
|
||||||
Label loopEntryPoint = builder.enterLoop(expression, loopExitPoint);
|
Label loopEntryPoint = builder.enterLoop(expression, loopExitPoint);
|
||||||
JetExpression body = expression.getBody();
|
JetExpression body = expression.getBody();
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
@@ -421,7 +423,7 @@ public class JetControlFlowProcessor {
|
|||||||
builder.returnNoValue(expression, subroutine);
|
builder.returnNoValue(expression, subroutine);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
builder.returnValue(subroutine);
|
builder.returnValue(expression, subroutine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.util.Collections;
|
|||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public abstract class InstructionWithNext extends JetElementInstruction {
|
public abstract class InstructionWithNext extends JetElementInstructionImpl {
|
||||||
private Instruction next;
|
private Instruction next;
|
||||||
|
|
||||||
protected InstructionWithNext(@NotNull JetElement element) {
|
protected InstructionWithNext(@NotNull JetElement element) {
|
||||||
|
|||||||
+4
-4
@@ -150,13 +150,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void returnValue(@NotNull JetElement subroutine) {
|
public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
|
||||||
add(new ReturnValueInstruction(getExitPoint(subroutine)));
|
add(new ReturnValueInstruction(returnExpression, getExitPoint(subroutine)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void returnNoValue(@NotNull JetElement expression, @NotNull JetElement subroutine) {
|
public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) {
|
||||||
add(new ReturnNoValueInstruction(expression, getExitPoint(subroutine)));
|
add(new ReturnNoValueInstruction(returnExpression, getExitPoint(subroutine)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -6,15 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
|
|||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public abstract class JetElementInstruction extends Instruction {
|
public interface JetElementInstruction {
|
||||||
protected final JetElement element;
|
|
||||||
|
|
||||||
public JetElementInstruction(@NotNull JetElement element) {
|
|
||||||
this.element = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetElement getElement() {
|
JetElement getElement();
|
||||||
return element;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class ReturnNoValueInstruction extends AbstractJumpInstruction {
|
public class ReturnNoValueInstruction extends AbstractJumpInstruction implements JetElementInstruction {
|
||||||
|
|
||||||
private final JetElement element;
|
private final JetElement element;
|
||||||
|
|
||||||
@@ -16,6 +16,8 @@ public class ReturnNoValueInstruction extends AbstractJumpInstruction {
|
|||||||
this.element = element;
|
this.element = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
public JetElement getElement() {
|
public JetElement getElement() {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.cfg.Label;
|
import org.jetbrains.jet.lang.cfg.Label;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @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);
|
super(targetLabel);
|
||||||
|
this.element = returnExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -20,4 +26,10 @@ public class ReturnValueInstruction extends AbstractJumpInstruction {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "ret(*) " + getTargetLabel();
|
return "ret(*) " + getTargetLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public JetElement getElement() {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,8 +286,12 @@ public class TopDownAnalyzer {
|
|||||||
|
|
||||||
List<JetElement> unreachableElements = new ArrayList<JetElement>();
|
List<JetElement> unreachableElements = new ArrayList<JetElement>();
|
||||||
flowInformationProvider.collectUnreachableExpressions(function, unreachableElements);
|
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 {
|
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) {
|
private JetFlowInformationProvider computeFlowData(@NotNull JetDeclaration declaration, @NotNull JetExpression bodyExpression) {
|
||||||
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
||||||
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
||||||
@@ -415,8 +441,8 @@ public class TopDownAnalyzer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitInstruction(Instruction instruction) {
|
public void visitInstruction(Instruction instruction) {
|
||||||
if (instruction instanceof JetElementInstruction) {
|
if (instruction instanceof JetElementInstructionImpl) {
|
||||||
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
JetElementInstructionImpl elementInstruction = (JetElementInstructionImpl) instruction;
|
||||||
semanticServices.getErrorHandler().genericError(elementInstruction.getElement().getNode(), "Unsupported by control-flow builder " + elementInstruction.getElement());
|
semanticServices.getErrorHandler().genericError(elementInstruction.getElement().getNode(), "Unsupported by control-flow builder " + elementInstruction.getElement());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -3,6 +3,24 @@ fun t1() {
|
|||||||
<error>1</error>
|
<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() {
|
fun t2() {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
return
|
return
|
||||||
@@ -10,6 +28,16 @@ fun t2() {
|
|||||||
<error>1</error>
|
<error>1</error>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun t2a() {
|
||||||
|
if (1 > 2) {
|
||||||
|
return
|
||||||
|
<error>1</error>
|
||||||
|
} else { return
|
||||||
|
<error>2</error>
|
||||||
|
}
|
||||||
|
<error>1</error>
|
||||||
|
}
|
||||||
|
|
||||||
fun t3() {
|
fun t3() {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
return 2
|
return 2
|
||||||
@@ -25,14 +53,79 @@ fun t4(a : Boolean) {
|
|||||||
<error>1</error>
|
<error>1</error>
|
||||||
}
|
}
|
||||||
|
|
||||||
//fun t5() {
|
fun t4break(a : Boolean) {
|
||||||
// do {
|
do {
|
||||||
// return
|
break
|
||||||
// }
|
}
|
||||||
// while (1 > 2)
|
while (<error>a</error>)
|
||||||
// 1
|
1
|
||||||
//}
|
}
|
||||||
|
|
||||||
//fun blockAndAndMismatch() : Boolean {
|
fun t5() {
|
||||||
// (return true) || (return false)
|
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