mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-dfa] Fix pattern in instanceof control flow when operand is not variable
Also, add diagnostics for diverged stack problem GitOrigin-RevId: 36661c8cb0a40c82c483a373fd45cd9aa90f61e1
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b2d4e0fb30
commit
77697dc741
+11
-13
@@ -1074,18 +1074,19 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
|
||||
private void processPatternInSwitch(@NotNull PsiPattern pattern, @NotNull DfaVariableValue expressionValue, @NotNull PsiType checkType) {
|
||||
DeferredOffset endPatternOffset = new DeferredOffset();
|
||||
processPattern(pattern, pattern, expressionValue, checkType, null, endPatternOffset);
|
||||
addInstruction(new JvmPushInstruction(expressionValue, null));
|
||||
processPattern(pattern, pattern, checkType, null, endPatternOffset);
|
||||
endPatternOffset.setOffset(getInstructionCount());
|
||||
}
|
||||
|
||||
private void processPatternInInstanceof(@NotNull PsiPattern pattern, @NotNull PsiInstanceOfExpression expression,
|
||||
@NotNull DfaVariableValue expressionValue, @NotNull PsiType checkType) {
|
||||
@NotNull PsiType checkType) {
|
||||
boolean potentiallyRedundantInstanceOf = pattern instanceof PsiTypeTestPattern ||
|
||||
JavaPsiPatternUtil.skipParenthesizedPatternDown(pattern) instanceof PsiTypeTestPattern ||
|
||||
pattern instanceof PsiDeconstructionPattern dec && JavaPsiPatternUtil.hasTotalComponents(dec);
|
||||
DfaAnchor instanceofAnchor = potentiallyRedundantInstanceOf ? new JavaExpressionAnchor(expression) : null;
|
||||
DeferredOffset endPatternOffset = new DeferredOffset();
|
||||
processPattern(pattern, pattern, expressionValue, checkType, instanceofAnchor, endPatternOffset);
|
||||
processPattern(pattern, pattern, checkType, instanceofAnchor, endPatternOffset);
|
||||
endPatternOffset.setOffset(getInstructionCount());
|
||||
if (!potentiallyRedundantInstanceOf) {
|
||||
addInstruction(new ResultOfInstruction(new JavaExpressionAnchor(expression)));
|
||||
@@ -1093,12 +1094,11 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
}
|
||||
|
||||
private void processPattern(@NotNull PsiPattern sourcePattern, @Nullable PsiPattern innerPattern,
|
||||
@NotNull DfaVariableValue expressionValue, @NotNull PsiType checkType,
|
||||
@Nullable DfaAnchor instanceofAnchor, @NotNull DeferredOffset endPatternOffset) {
|
||||
@NotNull PsiType checkType, @Nullable DfaAnchor instanceofAnchor, @NotNull DeferredOffset endPatternOffset) {
|
||||
if (innerPattern == null) return;
|
||||
if (innerPattern instanceof PsiGuardedPattern guardedPattern) {
|
||||
PsiPrimaryPattern primaryPattern = guardedPattern.getPrimaryPattern();
|
||||
processPattern(sourcePattern, primaryPattern, expressionValue, checkType, instanceofAnchor, endPatternOffset);
|
||||
processPattern(sourcePattern, primaryPattern, checkType, instanceofAnchor, endPatternOffset);
|
||||
PsiExpression expression = guardedPattern.getGuardingExpression();
|
||||
if (expression != null) {
|
||||
expression.accept(this);
|
||||
@@ -1116,7 +1116,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
}
|
||||
else if (innerPattern instanceof PsiParenthesizedPattern) {
|
||||
PsiPattern unwrappedPattern = JavaPsiPatternUtil.skipParenthesizedPatternDown(innerPattern);
|
||||
processPattern(sourcePattern, unwrappedPattern, expressionValue, checkType, instanceofAnchor, endPatternOffset);
|
||||
processPattern(sourcePattern, unwrappedPattern, checkType, instanceofAnchor, endPatternOffset);
|
||||
}
|
||||
else if (innerPattern instanceof PsiDeconstructionPattern deconstructionPattern) {
|
||||
PsiPatternVariable variable = deconstructionPattern.getPatternVariable();
|
||||
@@ -1124,8 +1124,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
DfaVariableValue patternDfaVar = variable == null ? createTempVariable(patternType) :
|
||||
PlainDescriptor.createVariableValue(getFactory(), variable);
|
||||
|
||||
addInstruction(new JvmPushInstruction(expressionValue, null));
|
||||
|
||||
addTypeCheckPattern(sourcePattern, innerPattern, checkType, endPatternOffset, patternDfaVar, instanceofAnchor);
|
||||
|
||||
addInstruction(new PopInstruction());
|
||||
@@ -1142,7 +1140,8 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
if (accessor == null) continue;
|
||||
DfaVariableValue accessorDfaVar =
|
||||
getFactory().getVarFactory().createVariableValue(new GetterDescriptor(accessor), patternDfaVar);
|
||||
processPattern(sourcePattern, patternComponent, accessorDfaVar, recordComponent.getType(), null, endPatternOffset);
|
||||
addInstruction(new JvmPushInstruction(accessorDfaVar, null));
|
||||
processPattern(sourcePattern, patternComponent, recordComponent.getType(), null, endPatternOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1152,8 +1151,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
if (variable == null) return;
|
||||
DfaVariableValue patternDfaVar = PlainDescriptor.createVariableValue(getFactory(), variable);
|
||||
|
||||
addInstruction(new JvmPushInstruction(expressionValue, null));
|
||||
|
||||
addTypeCheckPattern(sourcePattern, innerPattern, checkType, endPatternOffset, patternDfaVar, instanceofAnchor);
|
||||
|
||||
addInstruction(new PopInstruction());
|
||||
@@ -1795,6 +1792,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
DfaValue expr = JavaDfaValueFactory.getExpressionDfaValue(getFactory(), operand);
|
||||
if (expr instanceof DfaVariableValue) {
|
||||
expressionValue = (DfaVariableValue)expr;
|
||||
builder.push(expressionValue);
|
||||
}
|
||||
else {
|
||||
expressionValue = createTempVariable(operand.getType());
|
||||
@@ -1803,7 +1801,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
.pushExpression(operand)
|
||||
.assign();
|
||||
}
|
||||
processPatternInInstanceof(pattern, expression, expressionValue, operandType);
|
||||
processPatternInInstanceof(pattern, expression, operandType);
|
||||
}
|
||||
else {
|
||||
pushUnknown();
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class Aaa {
|
||||
private static void test(String str) {
|
||||
Stream.of(str)
|
||||
.flatMap(Aaa::stream)
|
||||
.forEach(expr -> {
|
||||
if (value(expr) instanceof Integer i) {
|
||||
System.out.println(expr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Object value(String expr) {
|
||||
return expr.trim();
|
||||
}
|
||||
|
||||
private static Stream<String> stream(String str) {
|
||||
return Stream.of(str);
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,10 @@ public class DataFlowInspection17Test extends DataFlowInspectionTestCase {
|
||||
public void testPatterns() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testPatternInStreamNotComplex() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testInstanceof() {
|
||||
doTest();
|
||||
|
||||
+10
@@ -298,6 +298,16 @@ public class StandardDataFlowInterpreter implements DataFlowInterpreter {
|
||||
|
||||
private @NotNull DfaInstructionState mergeBackBranches(DfaInstructionState instructionState, Collection<DfaMemoryState> processed) {
|
||||
DfaMemoryStateImpl curState = (DfaMemoryStateImpl)instructionState.getMemoryState();
|
||||
int curStateStackSize = curState.getStackSize();
|
||||
if (processed.size() > 10 && curStateStackSize > 10) {
|
||||
for (DfaMemoryState state : processed) {
|
||||
int diff = curStateStackSize - state.getStackSize();
|
||||
if (diff > 10) {
|
||||
throw new IllegalStateException("Stack for instruction %d increased by %d; it's likely that IR was built incorrectly"
|
||||
.formatted(instructionState.getInstruction().getIndex(), diff));
|
||||
}
|
||||
}
|
||||
}
|
||||
Object key = curState.getMergeabilityKey();
|
||||
DfaMemoryStateImpl mergedState =
|
||||
StreamEx.of(processed).filterBy(DfaMemoryState::getMergeabilityKey, key)
|
||||
|
||||
+5
@@ -52,6 +52,11 @@ public interface DfaMemoryState {
|
||||
*/
|
||||
@Nullable DfaValue getStackValue(int offset);
|
||||
|
||||
/**
|
||||
* @return number of values on the stack
|
||||
*/
|
||||
int getStackSize();
|
||||
|
||||
/**
|
||||
* @return true if there are no values in the stack
|
||||
*/
|
||||
|
||||
+5
@@ -176,6 +176,11 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
|
||||
return index < 0 ? null : myStack.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackSize() {
|
||||
return myStack.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(@NotNull DfaValue value) {
|
||||
assert value.getFactory() == myFactory : value;
|
||||
|
||||
Reference in New Issue
Block a user