KT-776 Wrong detection of unreachable code
KT-1001 Argument 2 for @NotNull parameter of JetFlowInformationProvider.checkIsInitialized must not be null
This commit is contained in:
@@ -19,6 +19,7 @@ public interface JetControlFlowBuilder {
|
||||
|
||||
void bindLabel(@NotNull Label label);
|
||||
void allowDead();
|
||||
void stopAllowDead();
|
||||
|
||||
// Jumps
|
||||
void jump(@NotNull Label label);
|
||||
|
||||
@@ -43,6 +43,12 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
||||
builder.allowDead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopAllowDead() {
|
||||
assert builder != null;
|
||||
builder.stopAllowDead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jump(@NotNull Label label) {
|
||||
assert builder != null;
|
||||
|
||||
@@ -8,10 +8,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author svtk
|
||||
@@ -140,7 +137,6 @@ public class JetControlFlowGraphTraverser<D> {
|
||||
Collections.reverse(instructions);
|
||||
}
|
||||
for (Instruction instruction : instructions) {
|
||||
if (instruction.isDead()) continue;
|
||||
if (lookInside && instruction instanceof LocalDeclarationInstruction) {
|
||||
traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), instructionDataAnalyzeStrategy);
|
||||
}
|
||||
|
||||
@@ -408,6 +408,7 @@ public class JetControlFlowProcessor {
|
||||
builder.exitTryFinally();
|
||||
value(finallyBlock.getFinalExpression(), inCondition);
|
||||
}
|
||||
builder.stopAllowDead();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -252,7 +252,10 @@ public class JetFlowInformationProvider {
|
||||
analyzeLocalDeclarations(processLocalDeclaration, pseudocode);
|
||||
}
|
||||
|
||||
private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, @NotNull JetElement element, @NotNull VariableInitializers variableInitializers, @NotNull Collection<VariableDescriptor> varWithUninitializedErrorGenerated) {
|
||||
private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor,
|
||||
@NotNull JetElement element,
|
||||
@NotNull VariableInitializers variableInitializers,
|
||||
@NotNull Collection<VariableDescriptor> varWithUninitializedErrorGenerated) {
|
||||
if (!(element instanceof JetSimpleNameExpression)) return;
|
||||
|
||||
boolean isInitialized = variableInitializers.isInitialized();
|
||||
@@ -272,7 +275,10 @@ public class JetFlowInformationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull Collection<VariableDescriptor> varWithValReassignErrorGenerated) {
|
||||
private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor,
|
||||
@NotNull JetExpression expression,
|
||||
@NotNull VariableInitializers enterInitializers,
|
||||
@NotNull Collection<VariableDescriptor> varWithValReassignErrorGenerated) {
|
||||
boolean isInitializedNotHere = enterInitializers.isInitialized();
|
||||
Set<JetElement> possibleLocalInitializers = enterInitializers.getPossibleLocalInitializers();
|
||||
if (possibleLocalInitializers.size() == 1) {
|
||||
|
||||
@@ -20,6 +20,4 @@ public interface Instruction {
|
||||
Collection<Instruction> getNextInstructions();
|
||||
|
||||
void accept(InstructionVisitor visitor);
|
||||
|
||||
boolean isDead();
|
||||
}
|
||||
|
||||
+8
-1
@@ -190,7 +190,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
bindLabel(getExitPoint(subroutine));
|
||||
pseudocode.addExitInstruction(new SubroutineExitInstruction(subroutine, "<END>"));
|
||||
bindLabel(error);
|
||||
add(new SubroutineExitInstruction(subroutine, "<ERROR>"));
|
||||
pseudocode.addErrorInstruction(new SubroutineExitInstruction(subroutine, "<ERROR>"));
|
||||
bindLabel(sink);
|
||||
pseudocode.addSinkInstruction(new SubroutineSinkInstruction(subroutine, "<SINK>"));
|
||||
elementToBlockInfo.remove(subroutine);
|
||||
@@ -266,6 +266,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
pseudocode.allowDead(allowedDeadLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopAllowDead() {
|
||||
Label allowedDeadLabel = createUnboundLabel();
|
||||
bindLabel(allowedDeadLabel);
|
||||
pseudocode.stopAllowDead(allowedDeadLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nondeterministicJump(Label label) {
|
||||
handleJumpInsideTryFinally(label);
|
||||
|
||||
@@ -56,12 +56,16 @@ public class Pseudocode {
|
||||
|
||||
private final List<Instruction> mutableInstructionList = new ArrayList<Instruction>();
|
||||
private final List<Instruction> instructions = new ArrayList<Instruction>();
|
||||
private List<Instruction> deadInstructions;
|
||||
|
||||
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
|
||||
private final List<PseudocodeLabel> allowedDeadLabels = new ArrayList<PseudocodeLabel>();
|
||||
private final List<PseudocodeLabel> stopAllowDeadLabels = new ArrayList<PseudocodeLabel>();
|
||||
|
||||
private final JetElement correspondingElement;
|
||||
private SubroutineExitInstruction exitInstruction;
|
||||
private SubroutineSinkInstruction sinkInstruction;
|
||||
private SubroutineExitInstruction errorInstruction;
|
||||
private boolean postPrecessed = false;
|
||||
|
||||
public Pseudocode(JetElement correspondingElement) {
|
||||
@@ -81,6 +85,10 @@ public class Pseudocode {
|
||||
public void allowDead(Label label) {
|
||||
allowedDeadLabels.add((PseudocodeLabel) label);
|
||||
}
|
||||
|
||||
public void stopAllowDead(Label label) {
|
||||
stopAllowDeadLabels.add((PseudocodeLabel) label);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Instruction> getInstructions() {
|
||||
@@ -95,10 +103,17 @@ public class Pseudocode {
|
||||
|
||||
@NotNull
|
||||
public List<Instruction> getDeadInstructions() {
|
||||
List<Instruction> deadInstructions = Lists.newArrayList();
|
||||
for (Instruction instruction : instructions) {
|
||||
if (instruction.isDead()) {
|
||||
deadInstructions.add(instruction);
|
||||
if (deadInstructions != null) {
|
||||
return deadInstructions;
|
||||
}
|
||||
deadInstructions = Lists.newArrayList();
|
||||
Collection<Instruction> allowedDeadInstructions = collectAllowedDeadInstructions();
|
||||
|
||||
for (Instruction instruction : mutableInstructionList) {
|
||||
if (((InstructionImpl)instruction).isDead()) {
|
||||
if (!allowedDeadInstructions.contains(instruction)) {
|
||||
deadInstructions.add(instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
return deadInstructions;
|
||||
@@ -122,6 +137,12 @@ public class Pseudocode {
|
||||
this.sinkInstruction = sinkInstruction;
|
||||
}
|
||||
|
||||
public void addErrorInstruction(SubroutineExitInstruction errorInstruction) {
|
||||
addInstruction(errorInstruction);
|
||||
assert this.errorInstruction == null;
|
||||
this.errorInstruction = errorInstruction;
|
||||
}
|
||||
|
||||
public void addInstruction(Instruction instruction) {
|
||||
mutableInstructionList.add(instruction);
|
||||
instruction.setOwner(this);
|
||||
@@ -151,88 +172,107 @@ public class Pseudocode {
|
||||
if (postPrecessed) return;
|
||||
postPrecessed = true;
|
||||
for (int i = 0, instructionsSize = mutableInstructionList.size(); i < instructionsSize; i++) {
|
||||
Instruction instruction = mutableInstructionList.get(i);
|
||||
final int currentPosition = i;
|
||||
instruction.accept(new InstructionVisitor() {
|
||||
@Override
|
||||
public void visitInstructionWithNext(InstructionWithNext instruction) {
|
||||
instruction.setNext(getNextPosition(currentPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
instruction.setResolvedTarget(getJumpTarget(instruction.getTargetLabel()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
instruction.setNext(getNextPosition(currentPosition));
|
||||
List<Label> targetLabels = instruction.getTargetLabels();
|
||||
for (Label targetLabel : targetLabels) {
|
||||
instruction.setResolvedTarget(targetLabel, getJumpTarget(targetLabel));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConditionalJump(ConditionalJumpInstruction instruction) {
|
||||
Instruction nextInstruction = getNextPosition(currentPosition);
|
||||
Instruction jumpTarget = getJumpTarget(instruction.getTargetLabel());
|
||||
if (instruction.onTrue()) {
|
||||
instruction.setNextOnFalse(nextInstruction);
|
||||
instruction.setNextOnTrue(jumpTarget);
|
||||
}
|
||||
else {
|
||||
instruction.setNextOnFalse(jumpTarget);
|
||||
instruction.setNextOnTrue(nextInstruction);
|
||||
}
|
||||
visitJump(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalDeclarationInstruction(LocalDeclarationInstruction instruction) {
|
||||
instruction.getBody().postProcess();
|
||||
instruction.setNext(getSinkInstruction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineExit(SubroutineExitInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineSink(SubroutineSinkInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
throw new UnsupportedOperationException(instruction.toString());
|
||||
}
|
||||
});
|
||||
processInstruction(mutableInstructionList.get(i), i);
|
||||
}
|
||||
getExitInstruction().setSink(getSinkInstruction());
|
||||
Set<Instruction> allowedDeadStartInstructions = prepareAllowedDeadInstructions();
|
||||
Set<Instruction> reachableInstructions = collectReachableInstructions();
|
||||
for (Instruction instruction : mutableInstructionList) {
|
||||
if (reachableInstructions.contains(instruction)) {
|
||||
instructions.add(instruction);
|
||||
}
|
||||
}
|
||||
markDeadInstructions();
|
||||
Collection<Instruction> allowedDeadInstructions = collectAllowedDeadInstructions(allowedDeadStartInstructions);
|
||||
instructions.addAll(mutableInstructionList);
|
||||
instructions.removeAll(allowedDeadInstructions);
|
||||
}
|
||||
|
||||
private void processInstruction(Instruction instruction, final int currentPosition) {
|
||||
instruction.accept(new InstructionVisitor() {
|
||||
@Override
|
||||
public void visitInstructionWithNext(InstructionWithNext instruction) {
|
||||
instruction.setNext(getNextPosition(currentPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
instruction.setResolvedTarget(getJumpTarget(instruction.getTargetLabel()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
instruction.setNext(getNextPosition(currentPosition));
|
||||
List<Label> targetLabels = instruction.getTargetLabels();
|
||||
for (Label targetLabel : targetLabels) {
|
||||
instruction.setResolvedTarget(targetLabel, getJumpTarget(targetLabel));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConditionalJump(ConditionalJumpInstruction instruction) {
|
||||
Instruction nextInstruction = getNextPosition(currentPosition);
|
||||
Instruction jumpTarget = getJumpTarget(instruction.getTargetLabel());
|
||||
if (instruction.onTrue()) {
|
||||
instruction.setNextOnFalse(nextInstruction);
|
||||
instruction.setNextOnTrue(jumpTarget);
|
||||
}
|
||||
else {
|
||||
instruction.setNextOnFalse(jumpTarget);
|
||||
instruction.setNextOnTrue(nextInstruction);
|
||||
}
|
||||
visitJump(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalDeclarationInstruction(LocalDeclarationInstruction instruction) {
|
||||
instruction.getBody().postProcess();
|
||||
instruction.setNext(getSinkInstruction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineExit(SubroutineExitInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineSink(SubroutineSinkInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
throw new UnsupportedOperationException(instruction.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Set<Instruction> collectReachableInstructions() {
|
||||
Set<Instruction> visited = Sets.newHashSet();
|
||||
traverseNextInstructions(getEnterInstruction(), visited);
|
||||
if (!visited.contains(getExitInstruction())) {
|
||||
visited.add(getExitInstruction());
|
||||
}
|
||||
if (!visited.contains(errorInstruction)) {
|
||||
visited.add(errorInstruction);
|
||||
}
|
||||
if (!visited.contains(getSinkInstruction())) {
|
||||
visited.add(getSinkInstruction());
|
||||
}
|
||||
return visited;
|
||||
}
|
||||
|
||||
private void traverseNextInstructions(Instruction instruction, Set<Instruction> visited) {
|
||||
if (visited.contains(instruction)) return;
|
||||
visited.add(instruction);
|
||||
for (Instruction nextInstruction : instruction.getNextInstructions()) {
|
||||
traverseNextInstructions(nextInstruction, visited);
|
||||
}
|
||||
}
|
||||
|
||||
private void markDeadInstructions() {
|
||||
boolean hasRemovedInstruction = true;
|
||||
Collection<Instruction> processedInstructions = Sets.newHashSet();
|
||||
while (hasRemovedInstruction) {
|
||||
hasRemovedInstruction = false;
|
||||
for (Instruction instruction : mutableInstructionList) {
|
||||
if (!(instruction instanceof SubroutineEnterInstruction || instruction instanceof SubroutineExitInstruction || instruction instanceof SubroutineSinkInstruction) &&
|
||||
instruction.getPreviousInstructions().isEmpty() && !processedInstructions.contains(instruction)) {
|
||||
hasRemovedInstruction = true;
|
||||
for (Instruction nextInstruction : instruction.getNextInstructions()) {
|
||||
nextInstruction.getPreviousInstructions().remove(instruction);
|
||||
}
|
||||
((InstructionImpl)instruction).die();
|
||||
processedInstructions.add(instruction);
|
||||
Set<Instruction> instructionSet = Sets.newHashSet(instructions);
|
||||
for (Instruction instruction : mutableInstructionList) {
|
||||
if (!instructionSet.contains(instruction)) {
|
||||
((InstructionImpl)instruction).die();
|
||||
for (Instruction nextInstruction : instruction.getNextInstructions()) {
|
||||
nextInstruction.getPreviousInstructions().remove(instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,27 +283,43 @@ public class Pseudocode {
|
||||
Set<Instruction> allowedDeadStartInstructions = Sets.newHashSet();
|
||||
for (PseudocodeLabel allowedDeadLabel : allowedDeadLabels) {
|
||||
Instruction allowedDeadInstruction = getJumpTarget(allowedDeadLabel);
|
||||
if (allowedDeadInstruction.getPreviousInstructions().isEmpty()) {
|
||||
if (((InstructionImpl)allowedDeadInstruction).isDead()) {
|
||||
allowedDeadStartInstructions.add(allowedDeadInstruction);
|
||||
}
|
||||
}
|
||||
return allowedDeadStartInstructions;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<Instruction> prepareStopAllowedDeadInstructions() {
|
||||
Set<Instruction> stopAllowedDeadInstructions = Sets.newHashSet();
|
||||
for (PseudocodeLabel stopAllowedDeadLabel : stopAllowDeadLabels) {
|
||||
Instruction stopAllowDeadInsruction = getJumpTarget(stopAllowedDeadLabel);
|
||||
if (((InstructionImpl)stopAllowDeadInsruction).isDead()) {
|
||||
stopAllowedDeadInstructions.add(stopAllowDeadInsruction);
|
||||
}
|
||||
}
|
||||
return stopAllowedDeadInstructions;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<Instruction> collectAllowedDeadInstructions(@NotNull Set<Instruction> allowedDeadStartInstructions) {
|
||||
private Collection<Instruction> collectAllowedDeadInstructions() {
|
||||
Set<Instruction> allowedDeadStartInstructions = prepareAllowedDeadInstructions();
|
||||
Set<Instruction> stopAllowDeadInstructions = prepareStopAllowedDeadInstructions();
|
||||
Set<Instruction> allowedDeadInstructions = Sets.newHashSet();
|
||||
|
||||
for (Instruction allowedDeadStartInstruction : allowedDeadStartInstructions) {
|
||||
collectAllowedDeadInstructions(allowedDeadStartInstruction, allowedDeadInstructions);
|
||||
collectAllowedDeadInstructions(allowedDeadStartInstruction, allowedDeadInstructions, stopAllowDeadInstructions);
|
||||
}
|
||||
return allowedDeadInstructions;
|
||||
}
|
||||
|
||||
private void collectAllowedDeadInstructions(Instruction allowedDeadInstruction, Set<Instruction> instructionSet) {
|
||||
if (allowedDeadInstruction.isDead()) {
|
||||
private void collectAllowedDeadInstructions(Instruction allowedDeadInstruction, Set<Instruction> instructionSet, Set<Instruction> stopAllowDeadInstructions) {
|
||||
if (stopAllowDeadInstructions.contains(allowedDeadInstruction)) return;
|
||||
if (((InstructionImpl)allowedDeadInstruction).isDead()) {
|
||||
instructionSet.add(allowedDeadInstruction);
|
||||
for (Instruction instruction : allowedDeadInstruction.getNextInstructions()) {
|
||||
collectAllowedDeadInstructions(instruction, instructionSet);
|
||||
collectAllowedDeadInstructions(instruction, instructionSet, stopAllowDeadInstructions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ l0:
|
||||
l2:
|
||||
r(2) NEXT:[<END>] PREV:[r(1)]
|
||||
l1:
|
||||
l3:
|
||||
<END> NEXT:[<SINK>] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -41,13 +42,14 @@ l0:
|
||||
jf(l2) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[ret l1] PREV:[jf(l2)]
|
||||
ret l1 NEXT:[<END>] PREV:[r(2)]
|
||||
* jmp(l3) NEXT:[r(2)] PREV:[]
|
||||
- jmp(l3) NEXT:[r(2)] PREV:[]
|
||||
l2:
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l2)]
|
||||
l3:
|
||||
l4:
|
||||
r(2) NEXT:[<END>] PREV:[read (Unit)]
|
||||
l1:
|
||||
l5:
|
||||
<END> NEXT:[<SINK>] PREV:[ret l1, r(2)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -69,7 +71,7 @@ l3:
|
||||
r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)]
|
||||
jf(l5) NEXT:[read (Unit), ret l4] PREV:[r(2 > 3)]
|
||||
ret l4 NEXT:[<END>] PREV:[jf(l5)]
|
||||
* jmp(l6) NEXT:[<END>] PREV:[]
|
||||
- jmp(l6) NEXT:[<END>] PREV:[]
|
||||
l5:
|
||||
read (Unit) NEXT:[<END>] PREV:[jf(l5)]
|
||||
l4:
|
||||
@@ -112,6 +114,7 @@ l2:
|
||||
l7:
|
||||
r(2) NEXT:[<END>] PREV:[r({ () => if (2 > 3) { retur..)]
|
||||
l1:
|
||||
l8:
|
||||
<END> NEXT:[<SINK>] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -125,7 +128,7 @@ l3:
|
||||
r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)]
|
||||
jf(l5) NEXT:[read (Unit), ret l4] PREV:[r(2 > 3)]
|
||||
ret l4 NEXT:[<END>] PREV:[jf(l5)]
|
||||
* jmp(l6) NEXT:[<END>] PREV:[]
|
||||
- jmp(l6) NEXT:[<END>] PREV:[]
|
||||
l5:
|
||||
read (Unit) NEXT:[<END>] PREV:[jf(l5)]
|
||||
l4:
|
||||
@@ -158,13 +161,14 @@ l3:
|
||||
jf(l5) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[ret l4] PREV:[jf(l5)]
|
||||
ret l4 NEXT:[<END>] PREV:[r(2)]
|
||||
* jmp(l6) NEXT:[r(2)] PREV:[]
|
||||
- jmp(l6) NEXT:[r(2)] PREV:[]
|
||||
l5:
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l5)]
|
||||
l6:
|
||||
l7:
|
||||
r(2) NEXT:[<END>] PREV:[read (Unit)]
|
||||
l4:
|
||||
l8:
|
||||
<END> NEXT:[<SINK>] PREV:[ret l4, r(2)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -225,13 +229,14 @@ l3:
|
||||
jf(l5) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[ret l4] PREV:[jf(l5)]
|
||||
ret l4 NEXT:[<END>] PREV:[r(2)]
|
||||
* jmp(l6) NEXT:[r(2)] PREV:[]
|
||||
- jmp(l6) NEXT:[r(2)] PREV:[]
|
||||
l5:
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l5)]
|
||||
l6:
|
||||
l7:
|
||||
r(2) NEXT:[<END>] PREV:[read (Unit)]
|
||||
l4:
|
||||
l8:
|
||||
<END> NEXT:[<SINK>] PREV:[ret l4, r(2)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -267,12 +272,13 @@ l4:
|
||||
jf(l6) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[jmp(l3)] PREV:[jf(l6)]
|
||||
jmp(l3) NEXT:[read (Unit)] PREV:[r(2)]
|
||||
* jmp(l7) NEXT:[r(2)] PREV:[]
|
||||
- jmp(l7) NEXT:[r(2)] PREV:[]
|
||||
l6:
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l6)]
|
||||
l7:
|
||||
l8:
|
||||
r(2) NEXT:[jmp(l2)] PREV:[read (Unit)]
|
||||
l9:
|
||||
jmp(l2) NEXT:[r(true)] PREV:[r(2)]
|
||||
l3:
|
||||
read (Unit) NEXT:[<END>] PREV:[jf(l3), jmp(l3)]
|
||||
@@ -312,7 +318,7 @@ l4:
|
||||
r(2 > 3) NEXT:[jf(l6)] PREV:[r(>)]
|
||||
jf(l6) NEXT:[read (Unit), jmp(l3)] PREV:[r(2 > 3)]
|
||||
jmp(l3) NEXT:[read (Unit)] PREV:[jf(l6)]
|
||||
* jmp(l7) NEXT:[jmp(l2)] PREV:[]
|
||||
- jmp(l7) NEXT:[jmp(l2)] PREV:[]
|
||||
l6:
|
||||
read (Unit) NEXT:[jmp(l2)] PREV:[jf(l6)]
|
||||
l7:
|
||||
@@ -323,6 +329,7 @@ l3:
|
||||
l8:
|
||||
r(2) NEXT:[<END>] PREV:[r(5)]
|
||||
l1:
|
||||
l9:
|
||||
<END> NEXT:[<SINK>] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -357,7 +364,7 @@ l4:
|
||||
r(2 > 3) NEXT:[jf(l6)] PREV:[r(>)]
|
||||
jf(l6) NEXT:[read (Unit), jmp(l3)] PREV:[r(2 > 3)]
|
||||
jmp(l3) NEXT:[read (Unit)] PREV:[jf(l6)]
|
||||
* jmp(l7) NEXT:[jmp(l2)] PREV:[]
|
||||
- jmp(l7) NEXT:[jmp(l2)] PREV:[]
|
||||
l6:
|
||||
read (Unit) NEXT:[jmp(l2)] PREV:[jf(l6)]
|
||||
l7:
|
||||
@@ -367,6 +374,7 @@ l3:
|
||||
l8:
|
||||
r(2) NEXT:[<END>] PREV:[read (Unit)]
|
||||
l1:
|
||||
l9:
|
||||
<END> NEXT:[<SINK>] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -409,12 +417,13 @@ l5:
|
||||
jf(l6) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[jmp(l4)] PREV:[jf(l6)]
|
||||
jmp(l4) NEXT:[r(1)] PREV:[r(2)]
|
||||
* jmp(l7) NEXT:[r(2)] PREV:[]
|
||||
- jmp(l7) NEXT:[r(2)] PREV:[]
|
||||
l6:
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l6)]
|
||||
l7:
|
||||
l8:
|
||||
r(2) NEXT:[jmp?(l4)] PREV:[read (Unit)]
|
||||
l9:
|
||||
jmp?(l4) NEXT:[r(1), read (Unit)] PREV:[r(2)]
|
||||
l2:
|
||||
read (Unit) NEXT:[<END>] PREV:[jmp?(l2), jmp?(l4)]
|
||||
@@ -461,7 +470,7 @@ l5:
|
||||
r(2 > 3) NEXT:[jf(l6)] PREV:[r(>)]
|
||||
jf(l6) NEXT:[read (Unit), jmp(l4)] PREV:[r(2 > 3)]
|
||||
jmp(l4) NEXT:[r(1)] PREV:[jf(l6)]
|
||||
* jmp(l7) NEXT:[jmp?(l4)] PREV:[]
|
||||
- jmp(l7) NEXT:[jmp?(l4)] PREV:[]
|
||||
l6:
|
||||
read (Unit) NEXT:[jmp?(l4)] PREV:[jf(l6)]
|
||||
l7:
|
||||
@@ -472,6 +481,7 @@ l2:
|
||||
l8:
|
||||
r(2) NEXT:[<END>] PREV:[r(5)]
|
||||
l1:
|
||||
l9:
|
||||
<END> NEXT:[<SINK>] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -513,7 +523,7 @@ l5:
|
||||
r(2 > 3) NEXT:[jf(l6)] PREV:[r(>)]
|
||||
jf(l6) NEXT:[read (Unit), jmp(l4)] PREV:[r(2 > 3)]
|
||||
jmp(l4) NEXT:[r(1)] PREV:[jf(l6)]
|
||||
* jmp(l7) NEXT:[jmp?(l4)] PREV:[]
|
||||
- jmp(l7) NEXT:[jmp?(l4)] PREV:[]
|
||||
l6:
|
||||
read (Unit) NEXT:[jmp?(l4)] PREV:[jf(l6)]
|
||||
l7:
|
||||
@@ -523,6 +533,7 @@ l2:
|
||||
l8:
|
||||
r(2) NEXT:[<END>] PREV:[read (Unit)]
|
||||
l1:
|
||||
l9:
|
||||
<END> NEXT:[<SINK>] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -544,11 +555,12 @@ l0:
|
||||
r(1) NEXT:[r(2)] PREV:[<START>]
|
||||
r(2) NEXT:[ret(*) l1] PREV:[r(1)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(2)]
|
||||
* ret(*) l1 NEXT:[<END>] PREV:[]
|
||||
- ret(*) l1 NEXT:[<END>] PREV:[]
|
||||
l2:
|
||||
R r(2) NEXT:[ret(*) l1] PREV:[]
|
||||
R ret(*) l1 NEXT:[<END>] PREV:[]
|
||||
- r(2) NEXT:[ret(*) l1] PREV:[]
|
||||
- ret(*) l1 NEXT:[<END>] PREV:[]
|
||||
l1:
|
||||
l3:
|
||||
<END> NEXT:[<SINK>] PREV:[ret(*) l1]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -573,10 +585,11 @@ l0:
|
||||
r(doSmth(3)) NEXT:[ret(*) l1] PREV:[r(doSmth)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(doSmth(3))]
|
||||
l2:
|
||||
R r(3) NEXT:[r(doSmth)] PREV:[]
|
||||
R r(doSmth) NEXT:[r(doSmth(3))] PREV:[]
|
||||
R r(doSmth(3)) NEXT:[<END>] PREV:[]
|
||||
- r(3) NEXT:[r(doSmth)] PREV:[]
|
||||
- r(doSmth) NEXT:[r(doSmth(3))] PREV:[]
|
||||
- r(doSmth(3)) NEXT:[<END>] PREV:[]
|
||||
l1:
|
||||
l3:
|
||||
<END> NEXT:[<SINK>] PREV:[ret(*) l1]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -605,7 +618,7 @@ l0:
|
||||
r(doSmth(3)) NEXT:[ret(*) l1] PREV:[r(doSmth)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(doSmth(3))]
|
||||
l3:
|
||||
R jmp(l4) NEXT:[r(3)] PREV:[]
|
||||
- jmp(l4) NEXT:[r(3)] PREV:[]
|
||||
l2:
|
||||
jmp?() NEXT:[v(e: UnsupportedOperationException)] PREV:[jmp?(l2)]
|
||||
v(e: UnsupportedOperationException) NEXT:[w(e)] PREV:[jmp?()]
|
||||
@@ -620,6 +633,7 @@ l4:
|
||||
r(doSmth) NEXT:[r(doSmth(3))] PREV:[r(3)]
|
||||
r(doSmth(3)) NEXT:[<END>] PREV:[r(doSmth)]
|
||||
l1:
|
||||
l6:
|
||||
<END> NEXT:[<SINK>] PREV:[ret(*) l1, r(doSmth(3))]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -642,7 +656,7 @@ l0:
|
||||
r(1) NEXT:[ret(*) l1] PREV:[jmp?(l2)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(1)]
|
||||
l3:
|
||||
R jmp(l4) NEXT:[<END>] PREV:[]
|
||||
- jmp(l4) NEXT:[<END>] PREV:[]
|
||||
l2:
|
||||
jmp?() NEXT:[v(e: UnsupportedOperationException)] PREV:[jmp?(l2)]
|
||||
v(e: UnsupportedOperationException) NEXT:[w(e)] PREV:[jmp?()]
|
||||
@@ -654,6 +668,7 @@ l5:
|
||||
jmp(l4) NEXT:[<END>] PREV:[r(doSmth(2))]
|
||||
l1:
|
||||
l4:
|
||||
l6:
|
||||
<END> NEXT:[<SINK>] PREV:[ret(*) l1, jmp(l4)]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -682,7 +697,7 @@ l0:
|
||||
r(doSmth(3)) NEXT:[ret(*) l1] PREV:[r(doSmth)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(doSmth(3))]
|
||||
l3:
|
||||
R jmp(l4) NEXT:[r(3)] PREV:[]
|
||||
- jmp(l4) NEXT:[r(3)] PREV:[]
|
||||
l2:
|
||||
jmp?() NEXT:[v(e: UnsupportedOperationException)] PREV:[jmp?(l2)]
|
||||
v(e: UnsupportedOperationException) NEXT:[w(e)] PREV:[jmp?()]
|
||||
@@ -693,12 +708,13 @@ l2:
|
||||
r(doSmth(3)) NEXT:[ret(*) l1] PREV:[r(doSmth)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(doSmth(3))]
|
||||
l5:
|
||||
R jmp(l4) NEXT:[r(3)] PREV:[]
|
||||
- jmp(l4) NEXT:[r(3)] PREV:[]
|
||||
l4:
|
||||
R r(3) NEXT:[r(doSmth)] PREV:[]
|
||||
R r(doSmth) NEXT:[r(doSmth(3))] PREV:[]
|
||||
R r(doSmth(3)) NEXT:[<END>] PREV:[]
|
||||
- r(3) NEXT:[r(doSmth)] PREV:[]
|
||||
- r(doSmth) NEXT:[r(doSmth(3))] PREV:[]
|
||||
- r(doSmth(3)) NEXT:[<END>] PREV:[]
|
||||
l1:
|
||||
l6:
|
||||
<END> NEXT:[<SINK>] PREV:[ret(*) l1, ret(*) l1]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
@@ -736,12 +752,13 @@ l2:
|
||||
r(doSmth(3)) NEXT:[ret(*) l1] PREV:[r(doSmth)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(doSmth(3))]
|
||||
l5:
|
||||
R jmp(l4) NEXT:[r(3)] PREV:[]
|
||||
- jmp(l4) NEXT:[r(3)] PREV:[]
|
||||
l4:
|
||||
r(3) NEXT:[r(doSmth)] PREV:[jmp(l4)]
|
||||
r(doSmth) NEXT:[r(doSmth(3))] PREV:[r(3)]
|
||||
r(doSmth(3)) NEXT:[<END>] PREV:[r(doSmth)]
|
||||
l1:
|
||||
l6:
|
||||
<END> NEXT:[<SINK>] PREV:[ret(*) l1, r(doSmth(3))]
|
||||
error:
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
|
||||
@@ -74,7 +74,7 @@ l0:
|
||||
r(b) NEXT:[jf(l2)] PREV:[w(i)]
|
||||
jf(l2) NEXT:[read (Unit), ret l1] PREV:[r(b)]
|
||||
ret l1 NEXT:[<END>] PREV:[jf(l2)]
|
||||
* jmp(l3) NEXT:[r(i)] PREV:[]
|
||||
- jmp(l3) NEXT:[r(i)] PREV:[]
|
||||
l2:
|
||||
read (Unit) NEXT:[r(i)] PREV:[jf(l2)]
|
||||
l3:
|
||||
@@ -85,7 +85,7 @@ l3:
|
||||
r(i is Int) NEXT:[jf(l4)] PREV:[r(i)]
|
||||
jf(l4) NEXT:[read (Unit), ret l1] PREV:[r(i is Int)]
|
||||
ret l1 NEXT:[<END>] PREV:[jf(l4)]
|
||||
* jmp(l5) NEXT:[<END>] PREV:[]
|
||||
- jmp(l5) NEXT:[<END>] PREV:[]
|
||||
l4:
|
||||
read (Unit) NEXT:[<END>] PREV:[jf(l4)]
|
||||
l1:
|
||||
|
||||
@@ -38,13 +38,13 @@ l2:
|
||||
l4:
|
||||
ret l1 NEXT:[<END>] PREV:[<START>]
|
||||
l5:
|
||||
* r(1) NEXT:[r(0)] PREV:[]
|
||||
* r(0) NEXT:[r(>)] PREV:[]
|
||||
* r(>) NEXT:[r(1 > 0)] PREV:[]
|
||||
* r(1 > 0) NEXT:[jt(l2)] PREV:[]
|
||||
* jt(l2) NEXT:[read (Unit), ret l1] PREV:[]
|
||||
- r(1) NEXT:[r(0)] PREV:[]
|
||||
- r(0) NEXT:[r(>)] PREV:[]
|
||||
- r(>) NEXT:[r(1 > 0)] PREV:[]
|
||||
- r(1 > 0) NEXT:[jt(l2)] PREV:[]
|
||||
- jt(l2) NEXT:[read (Unit), ret l1] PREV:[]
|
||||
l3:
|
||||
* read (Unit) NEXT:[<END>] PREV:[]
|
||||
- read (Unit) NEXT:[<END>] PREV:[]
|
||||
l1:
|
||||
<END> NEXT:[<SINK>] PREV:[ret l1]
|
||||
error:
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
//KT-1001 Argument 2 for @NotNull parameter of JetFlowInformationProvider.checkIsInitialized must not be null
|
||||
|
||||
package kt1001
|
||||
//+JDK
|
||||
|
||||
fun foo(<!UNUSED_PARAMETER!>c<!>: Array<Int>) {
|
||||
return
|
||||
|
||||
for (<!UNREACHABLE_CODE!>i<!> in <!UNREACHABLE_CODE!>c<!>) {}
|
||||
for (<!UNREACHABLE_CODE!>i<!> in <!UNREACHABLE_CODE!>c<!>) {}
|
||||
}
|
||||
|
||||
//more tests
|
||||
|
||||
fun t1() : Int {
|
||||
try {
|
||||
return 1
|
||||
}
|
||||
catch (e : Exception) {
|
||||
return 2
|
||||
}
|
||||
<!UNREACHABLE_CODE!>return 3<!>
|
||||
}
|
||||
|
||||
fun t2() : Int {
|
||||
try {
|
||||
return 1
|
||||
}
|
||||
finally {
|
||||
doSmth()
|
||||
}
|
||||
<!UNREACHABLE_CODE!>return 2<!>
|
||||
}
|
||||
|
||||
fun doSmth() {}
|
||||
@@ -0,0 +1,38 @@
|
||||
//KT-776 Wrong detection of unreachable code
|
||||
|
||||
package kt776
|
||||
|
||||
fun test5() : Int {
|
||||
var x = 0
|
||||
while(true) {
|
||||
try {
|
||||
if(x < 10) {
|
||||
x++
|
||||
continue
|
||||
}
|
||||
else {
|
||||
break
|
||||
}
|
||||
}
|
||||
finally {
|
||||
x++
|
||||
}
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
fun test1() : Int {
|
||||
try {
|
||||
if (true) {
|
||||
return 1
|
||||
}
|
||||
else {
|
||||
return 2
|
||||
}
|
||||
}
|
||||
finally {
|
||||
doSmth() //unreachable
|
||||
}
|
||||
}
|
||||
|
||||
fun doSmth() {}
|
||||
@@ -128,7 +128,7 @@ public class JetControlFlowTest extends JetLiteFixture {
|
||||
//check edges directions
|
||||
Collection<Instruction> instructions = pseudocode.getMutableInstructionList();
|
||||
for (Instruction instruction : instructions) {
|
||||
if (!instruction.isDead()) {
|
||||
if (!((InstructionImpl)instruction).isDead()) {
|
||||
for (Instruction nextInstruction : instruction.getNextInstructions()) {
|
||||
assertTrue("instruction '" + instruction + "' has '" + nextInstruction + "' among next instructions list, but not vice versa",
|
||||
nextInstruction.getPreviousInstructions().contains(instruction));
|
||||
@@ -176,7 +176,7 @@ public class JetControlFlowTest extends JetLiteFixture {
|
||||
private static String formatInstruction(Instruction instruction, int maxLength, Set<Instruction> remainedAfterPostProcessInstructions) {
|
||||
String[] parts = instruction.toString().split("\n");
|
||||
boolean isRemovedThroughPostProcess = !remainedAfterPostProcessInstructions.contains(instruction);
|
||||
String prefix = isRemovedThroughPostProcess ? "R " : instruction.isDead() ? "* " : " ";
|
||||
String prefix = isRemovedThroughPostProcess ? "- " : ((InstructionImpl)instruction).isDead() ? "* " : " ";
|
||||
if (parts.length == 1) {
|
||||
return prefix + String.format("%1$-" + maxLength + "s", instruction);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user