mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-08-25 17:07:05 +07:00
DFA instruction visitor refactoring wave#5 fixes
ResultOfInstruction
This commit is contained in:
@@ -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>
|
||||
|
||||
+3
@@ -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) {
|
||||
|
||||
+1
@@ -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) {
|
||||
|
||||
+5
@@ -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)};
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+7
-6
@@ -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 =
|
||||
|
||||
+9
-1
@@ -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) {
|
||||
|
||||
+34
@@ -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(); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user