diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CommonDataflow.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CommonDataflow.java index 297c1045f2c3..d5cb1051c809 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CommonDataflow.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CommonDataflow.java @@ -82,7 +82,7 @@ public class CommonDataflow { return states; } }; - RunnerResult result = runner.analyzeMethod(block, visitor); + RunnerResult result = runner.analyzeMethodRecursively(block, visitor); return result == RunnerResult.OK ? dfr : null; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java index effa2f4551ce..d389ec6352fd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java @@ -23,6 +23,7 @@ import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; @@ -245,6 +246,28 @@ public class DataFlowRunner { } } + public RunnerResult analyzeMethodRecursively(PsiElement block, StandardInstructionVisitor visitor) { + Collection states = createInitialStates(block, visitor); + if (states == null) return RunnerResult.NOT_APPLICABLE; + return analyzeBlockRecursively(block, states, visitor); + } + + private RunnerResult analyzeBlockRecursively(PsiElement block, + Collection states, + StandardInstructionVisitor visitor) { + RunnerResult result = analyzeMethod(block, visitor, false, states); + if (result != RunnerResult.OK) return result; + + Ref ref = Ref.create(RunnerResult.OK); + forNestedClosures((closure, nestedStates) -> { + RunnerResult res = analyzeBlockRecursively(closure, nestedStates, visitor); + if (res != RunnerResult.OK) { + ref.set(res); + } + }); + return ref.get(); + } + @Nullable private static DfaValue makeInitialValue(DfaVariableValue var, PsiElement block) { if(var.getQualifier() != null) return null; @@ -375,14 +398,16 @@ public class DataFlowRunner { } public void forNestedClosures(BiConsumer> consumer) { - for (PsiElement closure : myNestedClosures.keySet()) { + // Copy to avoid concurrent modifications + MultiMap closures = new MultiMap<>(myNestedClosures); + for (PsiElement closure : closures.keySet()) { List unusedVars = StreamEx.of(getFactory().getValues()) .select(DfaVariableValue.class) .filter(var -> var.getQualifier() == null) .filter(var -> var.getPsiVariable() instanceof PsiVariable && !VariableAccessUtils.variableIsUsed((PsiVariable)var.getPsiVariable(), closure)) .toList(); - Collection states = myNestedClosures.get(closure); + Collection states = closures.get(closure); if (!unusedVars.isEmpty()) { List stateList = StreamEx.of(states) .peek(state -> unusedVars.forEach(state::flushVariable))