From dd16819fb9960cd7503e041f158bd28293431a6e Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 17 Apr 2018 12:44:35 +0700 Subject: [PATCH] CFGBuilder#assignAndPop, assign --- .../codeInspection/dataFlow/CFGBuilder.java | 48 +++++++++++++++++-- .../inliner/CollectionFactoryInliner.java | 11 ++--- .../dataFlow/inliner/StreamChainInliner.java | 18 ++++--- 3 files changed, 57 insertions(+), 20 deletions(-) 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 986792786fbc..9706e45196b6 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 @@ -235,7 +235,7 @@ public class CFGBuilder { * @param relation relation to use for comparison * @return this builder */ - private CFGBuilder compare(IElementType relation) { + CFGBuilder compare(IElementType relation) { return add(new BinopInstruction(relation, null, PsiType.BOOLEAN)); } @@ -415,6 +415,49 @@ public class CFGBuilder { return add(new AssignInstruction(null, null)); } + /** + * Generate instructions to assign given source value to the given target value. Stack remains unchanged. + * May skip generating instructions if target is not writable (e.g. not a variable) + * + * @param target target to write + * @param source source value + * @return this builder + */ + public CFGBuilder assignAndPop(DfaValue target, DfaValue source) { + if (target instanceof DfaVariableValue) { + if (source == DfaUnknownValue.getInstance()) { + add(new FlushVariableInstruction((DfaVariableValue)target)); + } else { + pushForWrite((DfaVariableValue)target).push(source).assign().pop(); + } + } + return this; + } + + /** + * Generate instructions to assign given source value to the given target value and leave the result on stack. + *

+ * Stack before: ... + *

+ * Stack after: ... target + * + * @param target target to write + * @param source source value + * @return this builder + */ + public CFGBuilder assign(DfaValue target, DfaValue source) { + if (target instanceof DfaVariableValue) { + if (source == DfaUnknownValue.getInstance()) { + add(new FlushVariableInstruction((DfaVariableValue)target)).push(target); + } else { + pushForWrite((DfaVariableValue)target).push(source).assign(); + } + } else { + push(source); + } + return this; + } + /** * Generate instructions to assign top stack value to the specified variable *

@@ -638,8 +681,7 @@ public class CFGBuilder { ConditionalGotoInstruction condGoto = new ConditionalGotoInstruction(null, false, null); condGoto.setOffset(myAnalyzer.getInstructionCount()); myBranches.add(() -> pushUnknown().add(condGoto)); - DfaValue loopElement = factory.createCommonValue(expressions); - pushForWrite(targetVariable).push(loopElement).assign(); + assign(targetVariable, factory.createCommonValue(expressions)); } else { push(factory.getConstFactory().getSentinel()); for (PsiExpression expression : expressions) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/CollectionFactoryInliner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/CollectionFactoryInliner.java index a7bcc2aca5d5..e66bdff26b01 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/CollectionFactoryInliner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/CollectionFactoryInliner.java @@ -104,13 +104,10 @@ public class CollectionFactoryInliner implements CallInliner { builder.push(result); } else { DfaVariableValue variableValue = builder.createTempVariable(call.getType()); - builder.pushForWrite(variableValue) // tmpVar = - .push(result) - .assign() // leave tmpVar on stack: it's result of method call - .push(factoryInfo.mySizeField.createValue(factory, variableValue)) // tmpVar.size = - .push(factory.getInt(factoryInfo.mySize)) - .assign() - .pop(); + // tmpVar = ; leave tmpVar on stack: it's result of method call + builder.assign(variableValue, result); + // tmpVar.size = + builder.assignAndPop(factoryInfo.mySizeField.createValue(factory, variableValue), factory.getInt(factoryInfo.mySize)); } return true; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java index a967ceedc650..86a13bdbea61 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java @@ -16,6 +16,8 @@ package com.intellij.codeInspection.dataFlow.inliner; import com.intellij.codeInspection.dataFlow.*; +import com.intellij.codeInspection.dataFlow.value.DfaConstValue; +import com.intellij.codeInspection.dataFlow.value.DfaUnknownValue; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; import com.intellij.psi.*; @@ -243,7 +245,7 @@ public class StreamChainInliner implements CallInliner { @Override void iteration(CFGBuilder builder) { - builder.pushForWrite(myResult).pushUnknown().assign().splice(2); + builder.pop().assignAndPop(myResult, DfaUnknownValue.getInstance()); } } @@ -262,7 +264,7 @@ public class StreamChainInliner implements CallInliner { if (myFunction != null) { builder.pushUnknown().invokeFunction(2, myFunction); } - builder.pushForWrite(myResult).push(builder.getFactory().getFactValue(DfaFactType.OPTIONAL_PRESENCE, true)).assign().splice(2); + builder.assign(myResult, builder.getFactory().getFactValue(DfaFactType.OPTIONAL_PRESENCE, true)).splice(2); } } @@ -288,7 +290,7 @@ public class StreamChainInliner implements CallInliner { @Override void iteration(CFGBuilder builder) { myComparatorModel.invoke(builder); - builder.pushForWrite(myResult).push(builder.getFactory().getFactValue(DfaFactType.OPTIONAL_PRESENCE, true)).assign().pop(); + builder.assignAndPop(myResult, builder.getFactory().getFactValue(DfaFactType.OPTIONAL_PRESENCE, true)); } @Override @@ -309,12 +311,10 @@ public class StreamChainInliner implements CallInliner { @Override void iteration(CFGBuilder builder) { + DfaConstValue result = builder.getFactory().getBoolean("anyMatch".equals(myCall.getMethodExpression().getReferenceName())); builder.invokeFunction(1, myFunction) .ifConditionIs(!"allMatch".equals(myCall.getMethodExpression().getReferenceName())) - .pushForWrite(myResult) - .push(builder.getFactory().getBoolean("anyMatch".equals(myCall.getMethodExpression().getReferenceName()))) - .assign() - .pop() + .assignAndPop(myResult, result) .end(); } } @@ -731,9 +731,7 @@ public class StreamChainInliner implements CallInliner { private static void makeMainLoop(CFGBuilder builder, Step firstStep, PsiType inType) { builder.doWhileUnknown() - .pushForWrite(builder.createTempVariable(inType)) - .push(builder.getFactory().createTypeValue(inType, DfaPsiUtil.getTypeNullability(inType))) - .assign() + .assign(builder.createTempVariable(inType), builder.getFactory().createTypeValue(inType, DfaPsiUtil.getTypeNullability(inType))) .chain(firstStep::iteration).end(); }