mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
GuessManagerImpl DFA: CoW myStates; onlyForPlace
For normal completion we don't need to track expression types for expressions other than myForPlace Also changes in myState are much more rare than memory state copying, thus using copy-on-write strategy on myState seems rewarding Fixes IDEA-183497 Slow completion in somehow long method with workflow
This commit is contained in:
+22
-3
@@ -53,7 +53,8 @@ public class ExpressionTypeMemoryState extends DfaMemoryStateImpl {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
private final MultiMap<PsiExpression, PsiType> myStates = MultiMap.createSet(EXPRESSION_HASHING_STRATEGY);
|
||||
// may be shared between memory state instances
|
||||
private MultiMap<PsiExpression, PsiType> myStates = MultiMap.createSet(EXPRESSION_HASHING_STRATEGY);
|
||||
|
||||
public ExpressionTypeMemoryState(final DfaValueFactory factory) {
|
||||
super(factory);
|
||||
@@ -67,7 +68,7 @@ public class ExpressionTypeMemoryState extends DfaMemoryStateImpl {
|
||||
@Override
|
||||
public DfaMemoryStateImpl createCopy() {
|
||||
final ExpressionTypeMemoryState copy = new ExpressionTypeMemoryState(this);
|
||||
copy.myStates.putAllValues(myStates);
|
||||
copy.myStates = myStates;
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -77,6 +78,7 @@ public class ExpressionTypeMemoryState extends DfaMemoryStateImpl {
|
||||
return false;
|
||||
}
|
||||
MultiMap<PsiExpression, PsiType> thatStates = ((ExpressionTypeMemoryState)that).myStates;
|
||||
if (thatStates == myStates) return true;
|
||||
for (Map.Entry<PsiExpression, Collection<PsiType>> entry : myStates.entrySet()) {
|
||||
Collection<PsiType> thisTypes = entry.getValue();
|
||||
Collection<PsiType> thatTypes = thatStates.get(entry.getKey());
|
||||
@@ -126,7 +128,24 @@ public class ExpressionTypeMemoryState extends DfaMemoryStateImpl {
|
||||
return super.toString() + " states=[" + myStates + "]";
|
||||
}
|
||||
|
||||
void removeExpressionType(@NotNull PsiExpression expression) {
|
||||
if (myStates.containsKey(expression)) {
|
||||
MultiMap<PsiExpression, PsiType> oldStates = myStates;
|
||||
myStates = MultiMap.createSet(EXPRESSION_HASHING_STRATEGY);
|
||||
for (Map.Entry<PsiExpression, Collection<PsiType>> entry : oldStates.entrySet()) {
|
||||
if(!EXPRESSION_HASHING_STRATEGY.equals(entry.getKey(), expression)) {
|
||||
myStates.putValues(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setExpressionType(@NotNull PsiExpression expression, @NotNull PsiType type) {
|
||||
myStates.putValue(expression, type);
|
||||
if (!myStates.get(expression).contains(type)) {
|
||||
MultiMap<PsiExpression, PsiType> oldStates = myStates;
|
||||
myStates = MultiMap.createSet(EXPRESSION_HASHING_STRATEGY);
|
||||
myStates.putAllValues(oldStates);
|
||||
myStates.putValue(expression, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-16
@@ -36,6 +36,7 @@ import com.intellij.util.BitUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -130,12 +131,12 @@ public class GuessManagerImpl extends GuessManager {
|
||||
@NotNull
|
||||
@Override
|
||||
public MultiMap<PsiExpression, PsiType> getControlFlowExpressionTypes(@NotNull final PsiExpression forPlace) {
|
||||
MultiMap<PsiExpression, PsiType> typeMap = buildDataflowTypeMap(forPlace);
|
||||
MultiMap<PsiExpression, PsiType> typeMap = buildDataflowTypeMap(forPlace, false);
|
||||
return typeMap != null ? typeMap : MultiMap.empty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static MultiMap<PsiExpression, PsiType> buildDataflowTypeMap(PsiExpression forPlace) {
|
||||
private static MultiMap<PsiExpression, PsiType> buildDataflowTypeMap(PsiExpression forPlace, boolean place) {
|
||||
PsiElement scope = DfaPsiUtil.getTopmostBlockInSameClass(forPlace);
|
||||
if (scope == null) {
|
||||
PsiFile file = forPlace.getContainingFile();
|
||||
@@ -154,7 +155,7 @@ public class GuessManagerImpl extends GuessManager {
|
||||
}
|
||||
};
|
||||
|
||||
final ExpressionTypeInstructionVisitor visitor = new ExpressionTypeInstructionVisitor(forPlace);
|
||||
final ExpressionTypeInstructionVisitor visitor = new ExpressionTypeInstructionVisitor(forPlace, place);
|
||||
if (runner.analyzeMethodWithInlining(scope, visitor) == RunnerResult.OK) {
|
||||
return visitor.getResult();
|
||||
}
|
||||
@@ -406,7 +407,7 @@ public class GuessManagerImpl extends GuessManager {
|
||||
return Collections.emptyList(); //optimization
|
||||
}
|
||||
|
||||
MultiMap<PsiExpression, PsiType> fromDfa = buildDataflowTypeMap(expr);
|
||||
MultiMap<PsiExpression, PsiType> fromDfa = buildDataflowTypeMap(expr, true);
|
||||
if (fromDfa != null) {
|
||||
Collection<PsiType> conjuncts = fromDfa.get(expr);
|
||||
if (!conjuncts.isEmpty()) {
|
||||
@@ -437,14 +438,11 @@ public class GuessManagerImpl extends GuessManager {
|
||||
private MultiMap<PsiExpression, PsiType> myResult;
|
||||
private final PsiElement myForPlace;
|
||||
private TypeConstraint myConstraint = null;
|
||||
private final boolean myOnlyForPlace;
|
||||
|
||||
private ExpressionTypeInstructionVisitor(@NotNull PsiElement forPlace) {
|
||||
PsiElement parent = PsiUtil.skipParenthesizedExprUp(forPlace.getParent());
|
||||
if (forPlace instanceof PsiThisExpression && parent instanceof PsiReferenceExpression) {
|
||||
myForPlace = parent.getParent() instanceof PsiMethodCallExpression ? parent.getParent() : parent;
|
||||
} else {
|
||||
myForPlace = forPlace;
|
||||
}
|
||||
private ExpressionTypeInstructionVisitor(@NotNull PsiElement forPlace, boolean onlyForPlace) {
|
||||
myOnlyForPlace = onlyForPlace;
|
||||
myForPlace = PsiUtil.skipParenthesizedExprUp(forPlace);
|
||||
}
|
||||
|
||||
MultiMap<PsiExpression, PsiType> getResult() {
|
||||
@@ -460,21 +458,33 @@ public class GuessManagerImpl extends GuessManager {
|
||||
return myResult;
|
||||
}
|
||||
|
||||
@Contract("null -> false")
|
||||
private boolean isInteresting(PsiExpression expression) {
|
||||
if (expression == null) return false;
|
||||
return !myOnlyForPlace ||
|
||||
(myForPlace instanceof PsiExpression &&
|
||||
ExpressionTypeMemoryState.EXPRESSION_HASHING_STRATEGY.equals((PsiExpression)myForPlace, expression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaInstructionState[] visitInstanceof(InstanceofInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
|
||||
if (instruction.getLeft() == null) {
|
||||
PsiExpression psiOperand = instruction.getLeft();
|
||||
if (!isInteresting(psiOperand)) {
|
||||
return super.visitInstanceof(instruction, runner, memState);
|
||||
}
|
||||
DfaValue type = memState.pop();
|
||||
DfaValue operand = memState.pop();
|
||||
DfaValue relation = runner.getFactory().createCondition(operand, DfaRelationValue.RelationType.IS, type);
|
||||
memState.push(new DfaInstanceofValue(runner.getFactory(), instruction.getLeft(), instruction.getCastType(), relation, false));
|
||||
memState.push(new DfaInstanceofValue(runner.getFactory(), psiOperand, instruction.getCastType(), relation, false));
|
||||
return new DfaInstructionState[]{new DfaInstructionState(runner.getInstruction(instruction.getIndex() + 1), memState)};
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaInstructionState[] visitTypeCast(TypeCastInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
|
||||
((ExpressionTypeMemoryState) memState).setExpressionType(instruction.getCasted(), instruction.getCastTo());
|
||||
PsiExpression psiOperand = instruction.getCasted();
|
||||
if (isInteresting(psiOperand)) {
|
||||
((ExpressionTypeMemoryState)memState).setExpressionType(psiOperand, instruction.getCastTo());
|
||||
}
|
||||
return super.visitTypeCast(instruction, runner, memState);
|
||||
}
|
||||
|
||||
@@ -483,8 +493,7 @@ public class GuessManagerImpl extends GuessManager {
|
||||
PsiExpression left = instruction.getLExpression();
|
||||
PsiExpression right = instruction.getRExpression();
|
||||
if (left != null && right != null) {
|
||||
MultiMap<PsiExpression, PsiType> states = ((ExpressionTypeMemoryState)memState).getStates();
|
||||
states.remove(left);
|
||||
((ExpressionTypeMemoryState)memState).removeExpressionType(left);
|
||||
}
|
||||
return super.visitAssign(instruction, runner, memState);
|
||||
}
|
||||
|
||||
+2
-2
@@ -1759,7 +1759,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
|
||||
@Override public void visitSuperExpression(PsiSuperExpression expression) {
|
||||
startElement(expression);
|
||||
addInstruction(new PushInstruction(myFactory.createTypeValue(expression.getType(), Nullness.NOT_NULL), null));
|
||||
addInstruction(new PushInstruction(myFactory.createTypeValue(expression.getType(), Nullness.NOT_NULL), expression));
|
||||
finishElement(expression);
|
||||
}
|
||||
|
||||
@@ -1769,7 +1769,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
if (myThisReadOnly) {
|
||||
value = myFactory.withFact(value, DfaFactType.MUTABLE, false);
|
||||
}
|
||||
addInstruction(new PushInstruction(value, null));
|
||||
addInstruction(new PushInstruction(value, expression));
|
||||
finishElement(expression);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user