diff --git a/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiModuleUtil.java b/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiModuleUtil.java index cb5a7838e759..c8467bbc213b 100644 --- a/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiModuleUtil.java +++ b/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiModuleUtil.java @@ -502,12 +502,20 @@ public final class JavaPsiModuleUtil { source = getPhysicalModule(source); destination = getPhysicalModule(destination); Collection nodes = myGraph.getNodes(); - if (nodes.contains(destination) && nodes.contains(source)) { + if (!nodes.contains(destination) || !nodes.contains(source)) { + return false; + } + + UniqueBuffer buffer = new UniqueBuffer<>(); + buffer.add(destination); + while (!buffer.isEmpty()) { + destination = buffer.poll(); Iterator directReaders = myGraph.getOut(destination); while (directReaders.hasNext()) { PsiJavaModule next = directReaders.next(); - if (source.equals(next) || myTransitiveEdges.contains(key(destination, next)) && !next.equals(destination) && reads(source, next)) { - return true; + if (source.equals(next)) return true; + if (myTransitiveEdges.contains(key(destination, next)) && !next.equals(destination)) { + buffer.add(next); } } } @@ -591,6 +599,29 @@ public final class JavaPsiModuleUtil { if (origin.getModuleDeclaration() instanceof PsiJavaModule result) return result; return from; } + + /** + * FIFO queue that prevents duplicate additions. + * Once added, an element cannot be added again even after being polled. + */ + private static class UniqueBuffer { + private final Set myUnique = new HashSet<>(); + private final Queue myBuffer = new ArrayDeque<>(); + + public void add(T value) { + if (myUnique.add(value)) { + myBuffer.add(value); + } + } + + public T poll() { + return myBuffer.poll(); + } + + public boolean isEmpty() { + return myBuffer.isEmpty(); + } + } } /** diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/caches/resolve/Java9MultiModuleHighlightingTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/caches/resolve/Java9MultiModuleHighlightingTest.kt index f5af5c585f21..81755526ea41 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/caches/resolve/Java9MultiModuleHighlightingTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/caches/resolve/Java9MultiModuleHighlightingTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.kotlin.idea.caches.resolve @@ -74,7 +74,7 @@ class Java9MultiModuleHighlightingTest : AbstractMultiModuleHighlightingTest() { checkHighlightingInProject() } - fun _testCyclicDependency() { + fun testCyclicDependency() { val a = module("moduleA") val b = module("moduleB") val c = module("moduleC")