DFA instruction visitor refactoring wave#5 fixes

ResultOfInstruction
This commit is contained in:
Tagir Valeev
2018-06-25 15:48:10 +07:00
parent 3d241e6410
commit a4a84553e4
12 changed files with 92 additions and 9 deletions
@@ -207,6 +207,16 @@ public class CFGBuilder {
return add(new ObjectOfInstruction());
}
/**
* Generate instructions to bind top-of-stack value to the given expression. Stack remains unchanged.
*
* @param expression expression to bind top-of-stack value to
* @return this builder
*/
public CFGBuilder resultOf(PsiExpression expression) {
return add(new ResultOfInstruction(expression));
}
/**
* Generate instructions to perform an Class.isInstance operation
* <p>
@@ -1512,6 +1512,9 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
addInstruction(new GotoInstruction(getEndOffset(operands[operands.length - 1])));
}
}
if (shortCircuit) {
addInstruction(new ResultOfInstruction(expression));
}
}
@Override public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
@@ -243,6 +243,7 @@ final class DataFlowInstructionVisitor extends StandardInstructionVisitor {
}
private static boolean shouldCollectBooleanResult(PsiExpression expression) {
if (expression instanceof PsiLiteralExpression) return false;
PsiType type = expression.getType();
if (type == null || !PsiType.BOOLEAN.isAssignableFrom(type)) return false;
if (expression instanceof PsiPrefixExpression || expression instanceof PsiPolyadicExpression) {
@@ -147,6 +147,11 @@ public abstract class InstructionVisitor {
return nextInstruction(instruction, runner, state);
}
public DfaInstructionState[] visitResultOf(ResultOfInstruction instruction, DataFlowRunner runner, DfaMemoryState state) {
pushExpressionResult(state.pop(), instruction, state);
return nextInstruction(instruction, runner, state);
}
protected static DfaInstructionState[] nextInstruction(Instruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
return new DfaInstructionState[]{new DfaInstructionState(runner.getInstruction(instruction.getIndex() + 1), memState)};
}
@@ -101,7 +101,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
checkNotNullable(memState, dfaSource, kind.problem(rValue));
}
memState.push(dfaDest);
pushExpressionResult(dfaDest, instruction, memState);
flushArrayOnUnknownAssignment(instruction, runner.getFactory(), dfaDest, memState);
return nextInstruction(instruction, runner, memState);
@@ -81,11 +81,10 @@ public class OptionalChainInliner implements CallInliner {
.ifNotNull()
.swap() // stack: .. optValue, elseValue
.end()
.pop();
})
.register(OPTIONAL_OR_NULL, (builder, call) -> {
// no op!
.pop()
.resultOf(call);
})
.register(OPTIONAL_OR_NULL, CFGBuilder::resultOf)
.register(OPTIONAL_OR_ELSE_GET, (builder, call) -> {
PsiExpression fn = call.getArgumentList().getExpressions()[0];
builder
@@ -94,7 +93,8 @@ public class OptionalChainInliner implements CallInliner {
.ifNull()
.pop()
.invokeFunction(0, fn)
.end();
.end()
.resultOf(call);
})
.register(OPTIONAL_IF_PRESENT, (builder, call) -> {
PsiExpression fn = call.getArgumentList().getExpressions()[0];
@@ -106,7 +106,8 @@ public class OptionalChainInliner implements CallInliner {
.elseBranch()
.pop()
.pushUnknown()
.end();
.end()
.resultOf(call);
});
private static final CallMapper<BiConsumer<CFGBuilder, PsiExpression>> INTERMEDIATE_MAPPER =
@@ -24,10 +24,11 @@ import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.psi.PsiAssignmentExpression;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiVariable;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
public class AssignInstruction extends Instruction {
public class AssignInstruction extends Instruction implements ExpressionPushingInstruction {
private final PsiExpression myRExpression;
private final PsiExpression myLExpression;
@Nullable private final DfaValue myAssignedValue;
@@ -70,6 +71,13 @@ public class AssignInstruction extends Instruction {
return "ASSIGN";
}
@Nullable
@Override
public PsiAssignmentExpression getExpression() {
if(myRExpression== null) return null;
return ObjectUtils.tryCast(myRExpression.getParent(), PsiAssignmentExpression.class);
}
@Contract("null -> null")
@Nullable
private static PsiExpression getLeftHandOfAssignment(PsiExpression rExpression) {
@@ -0,0 +1,34 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.dataFlow.instructions;
import com.intellij.codeInspection.dataFlow.DataFlowRunner;
import com.intellij.codeInspection.dataFlow.DfaInstructionState;
import com.intellij.codeInspection.dataFlow.DfaMemoryState;
import com.intellij.codeInspection.dataFlow.InstructionVisitor;
import com.intellij.psi.PsiExpression;
import org.jetbrains.annotations.NotNull;
public class ResultOfInstruction extends Instruction implements ExpressionPushingInstruction {
@NotNull
private final PsiExpression myExpression;
public ResultOfInstruction(@NotNull PsiExpression expression) {
myExpression = expression;
}
@Override
public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState stateBefore, InstructionVisitor visitor) {
return visitor.visitResultOf(this, runner, stateBefore);
}
public String toString() {
return "RESULT_OF "+myExpression.getText();
}
@NotNull
@Override
public PsiExpression getExpression() {
return myExpression;
}
}
@@ -0,0 +1,9 @@
import java.util.List;
class Test {
void test(String type) {
if(type != null && (type.equals("foo") | type.equals("bar"))) {
System.out.println("Who knows");
}
}
}
@@ -41,7 +41,7 @@ class S {
}
public void te5(boolean b){
Boolean c = Boolean.TRUE;
boolean o = <warning descr="Condition 'b||c' is always 'true'">b||<warning descr="Condition 'c' is always 'true' when reached">c</warning></warning>;
boolean o = b||<warning descr="Condition 'c' is always 'true' when reached">c</warning>;
if (<warning descr="Condition 'o' is always 'true'">o</warning>) {
}
}
@@ -0,0 +1,10 @@
import java.util.List;
class Test {
void test(String type) {
boolean uint = false;
if ("int".equals(type) || (uint = "uint".equals(type))) {
System.out.println("possible");
}
}
}
@@ -622,4 +622,6 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
public void testEqualsInLoopNotTooComplex() { doTest(); }
public void testEqualsWithItself() { doTest(); }
public void testBoxingBoolean() { doTest(); }
public void testOrWithAssignment() { doTest(); }
public void testAndAndWithOr() { doTest(); }
}