diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java index 1472cd8b3b0c..8f19a63ffa2d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java @@ -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 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 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 getPotentiallyAffectingElements(PsiExpression place) { + PsiElement topmostBlock = getTopmostBlock(place); + return CachedValuesManager.getCachedValue(topmostBlock, () -> { + List list = SyntaxTraverser.psiTraverser(topmostBlock).filter(e -> e instanceof PsiExpression || e instanceof PsiLocalVariable).toList(); + return new CachedValueProvider.Result<>(list, topmostBlock); + }); + } + @NotNull private static List getTypesFromDfa(@NotNull PsiExpression expr) { MultiMap 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;