diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java index f66a4261916e..e9c854bd7213 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java @@ -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 *
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
index d8c6fa317f63..b648dde79d63 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
@@ -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) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInstructionVisitor.java
index 10322b2db8c3..55a929705418 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInstructionVisitor.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInstructionVisitor.java
@@ -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) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java
index d87af0faa17e..2ea578cb5e4c 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/InstructionVisitor.java
@@ -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)};
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
index 5385d4c24e53..40e2d26b289f 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
@@ -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);
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/OptionalChainInliner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/OptionalChainInliner.java
index 1c0e3e06c80f..9328cae7a859 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/OptionalChainInliner.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/OptionalChainInliner.java
@@ -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