GuessManagerImpl.getControlFlowExpressionTypeConjuncts: don't traverse all PSI each time

when a method contains many unresolved references, this can easily become a performance hotspot
because after IDEA-185569 the DFA type is checked for every such reference
This commit is contained in:
peter
2018-07-09 11:18:31 +02:00
parent 9cb6e63c34
commit a0780d74f3
@@ -30,6 +30,8 @@ import com.intellij.psi.search.PsiElementProcessorAdapter;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.BitUtil;
@@ -348,9 +350,7 @@ public class GuessManagerImpl extends GuessManager {
List<PsiType> result = null;
if (!ControlFlowAnalyzer.inlinerMayInferPreciseType(place)) {
GuessTypeVisitor visitor = new GuessTypeVisitor(place);
getTopmostBlock(place).accept(visitor);
GuessTypeVisitor visitor = tryGuessingTypeWithoutDfa(place);
if (!visitor.isDfaNeeded()) {
result = visitor.mySpecificType == null ?
Collections.emptyList() : Collections.singletonList(tryGenerify(expr, visitor.mySpecificType));
@@ -365,6 +365,27 @@ public class GuessManagerImpl extends GuessManager {
return result;
}
@NotNull
private static GuessTypeVisitor tryGuessingTypeWithoutDfa(PsiExpression place) {
List<PsiElement> exprsAndVars = getPotentiallyAffectingElements(place);
GuessTypeVisitor visitor = new GuessTypeVisitor(place);
for (PsiElement e : exprsAndVars) {
e.accept(visitor);
if (e == place || visitor.isDfaNeeded()) {
break;
}
}
return visitor;
}
private static List<PsiElement> getPotentiallyAffectingElements(PsiExpression place) {
PsiElement topmostBlock = getTopmostBlock(place);
return CachedValuesManager.getCachedValue(topmostBlock, () -> {
List<PsiElement> list = SyntaxTraverser.psiTraverser(topmostBlock).filter(e -> e instanceof PsiExpression || e instanceof PsiLocalVariable).toList();
return new CachedValueProvider.Result<>(list, topmostBlock);
});
}
@NotNull
private static List<PsiType> getTypesFromDfa(@NotNull PsiExpression expr) {
MultiMap<PsiExpression, PsiType> fromDfa = buildDataflowTypeMap(expr, true);
@@ -393,16 +414,14 @@ public class GuessManagerImpl extends GuessManager {
return GenericsUtil.getExpectedGenericType(expression, psiClass, (PsiClassType)expressionType);
}
static class GuessTypeVisitor extends JavaRecursiveElementWalkingVisitor {
static class GuessTypeVisitor extends JavaElementVisitor {
private final @NotNull PsiExpression myPlace;
PsiType mySpecificType;
private boolean myNeedDfa;
private boolean myDeclared;
private final int myStart;
GuessTypeVisitor(@NotNull PsiExpression place) {
myPlace = place;
myStart = place.getTextRange().getStartOffset();
}
private void handleAssignment(@Nullable PsiExpression expression) {
@@ -418,7 +437,6 @@ public class GuessManagerImpl extends GuessManager {
}
else if (!mySpecificType.equals(rawType)) {
myNeedDfa = true;
stopWalking();
}
}
@@ -443,7 +461,6 @@ public class GuessManagerImpl extends GuessManager {
public void visitTypeCastExpression(PsiTypeCastExpression expression) {
if (ExpressionTypeMemoryState.EXPRESSION_HASHING_STRATEGY.equals(expression.getOperand(), myPlace)) {
myNeedDfa = true;
stopWalking();
}
super.visitTypeCastExpression(expression);
}
@@ -452,19 +469,10 @@ public class GuessManagerImpl extends GuessManager {
public void visitInstanceOfExpression(PsiInstanceOfExpression expression) {
if (ExpressionTypeMemoryState.EXPRESSION_HASHING_STRATEGY.equals(expression.getOperand(), myPlace)) {
myNeedDfa = true;
stopWalking();
}
super.visitInstanceOfExpression(expression);
}
@Override
public void visitElement(PsiElement element) {
if (element.getTextRange().getStartOffset() > myStart) {
stopWalking();
}
super.visitElement(element);
}
public boolean isDfaNeeded() {
if (myNeedDfa) return true;
if (myDeclared || mySpecificType == null) return false;