diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java index 6fe31f4c6c20..99133926e18f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java @@ -29,6 +29,8 @@ import com.intellij.util.containers.MultiMap; import com.intellij.util.graph.DFSTBuilder; import com.intellij.util.graph.Graph; import com.intellij.util.graph.GraphGenerator; +import com.intellij.util.graph.OutboundSemiGraph; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -95,7 +97,7 @@ public class JavaModuleGraphUtil { } if (!relations.isEmpty()) { - Graph graph = new SourceSemiGraph(relations); + Graph graph = new ChameleonGraph<>(relations, false); DFSTBuilder builder = new DFSTBuilder<>(graph); Collection> components = builder.getComponents(); if (!components.isEmpty()) { @@ -130,7 +132,7 @@ public class JavaModuleGraphUtil { .ifPresent(m -> visit(m, relations, publicEdges)); } - GraphGenerator graph = GraphGenerator.create(new RequiresSemiGraph(relations)); + Graph graph = GraphGenerator.generate(new ChameleonGraph<>(relations, true)); return new RequiresGraph(graph, publicEdges); } @@ -149,10 +151,10 @@ public class JavaModuleGraphUtil { } private static class RequiresGraph { - private final Graph myGraph; + private final OutboundSemiGraph myGraph; private final Set myPublicEdges; - public RequiresGraph(Graph graph, Set publicEdges) { + public RequiresGraph(OutboundSemiGraph graph, Set publicEdges) { myGraph = graph; myPublicEdges = publicEdges; } @@ -176,46 +178,34 @@ public class JavaModuleGraphUtil { } } - // - private static class SourceSemiGraph implements Graph { - private final MultiMap myMap; + private static class ChameleonGraph implements Graph { + private final Set myNodes; + private final MultiMap myEdges; + private final boolean myInbound; - public SourceSemiGraph(MultiMap map) { - myMap = map; + public ChameleonGraph(MultiMap edges, boolean inbound) { + myNodes = new THashSet<>(); + edges.entrySet().forEach(e -> { + myNodes.add(e.getKey()); + myNodes.addAll(e.getValue()); + }); + myEdges = edges; + myInbound = inbound; } @Override - public Collection getNodes() { - return myMap.keySet(); + public Collection getNodes() { + return myNodes; } @Override - public Iterator getIn(PsiJavaModule n) { - throw new UnsupportedOperationException(); + public Iterator getIn(N n) { + return myInbound ? myEdges.get(n).iterator() : Collections.emptyIterator(); } @Override - public Iterator getOut(PsiJavaModule n) { - return myMap.get(n).iterator(); + public Iterator getOut(N n) { + return myInbound ? Collections.emptyIterator() : myEdges.get(n).iterator(); } } - - private static class RequiresSemiGraph implements GraphGenerator.SemiGraph { - private final MultiMap myMap; - - public RequiresSemiGraph(MultiMap map) { - myMap = map; - } - - @Override - public Collection getNodes() { - return myMap.keySet(); - } - - @Override - public Iterator getIn(PsiJavaModule n) { - return myMap.get(n).iterator(); - } - } - // } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt index 96665872d40b..6c48b7100ab8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt @@ -167,6 +167,13 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() { """.trimIndent()) } + fun testLinearModuleGraphBug() { + addFile("module-info.java", "module M { requires M6; }") + addFile("module-info.java", "module M6 { requires M7; }", M6) + addFile("module-info.java", "module M7 { }", M7) + highlight("module M { requires M6; }") + } + // private fun highlight(text: String) = highlight("module-info.java", text)