mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-01 19:02:13 +07:00
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:
+25
-17
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user