JVM: fix "module reads" check in JavaModuleGraph

There was a bug in the DFS. Whenever we encountered a "requires
transitive X" directive in some module, we recursively invoked DFS not
on X but on `dependencyName`, which is the target module that we're
trying to find the path to. And that always failed, because no module
requires itself.

 #KT-66275 Fixed
This commit is contained in:
Alexander Udalov
2024-03-13 23:17:44 +01:00
committed by Space Team
parent fecc5ba501
commit 94e5cafb61
11 changed files with 68 additions and 1 deletions
@@ -77,7 +77,7 @@ class JavaModuleGraph(finder: JavaModuleFinder) {
is JavaModule.Explicit -> {
for ((dependencyModuleName, isTransitive) in module.moduleInfo.requires) {
if (dependencyModuleName == dependencyName) return true
if (isTransitive && dfs(dependencyName)) return true
if (isTransitive && dfs(dependencyModuleName)) return true
}
return false
}
@@ -0,0 +1,5 @@
package a;
public class A {
public String ok() { return "OK"; }
}
@@ -0,0 +1,3 @@
module moduleA {
exports a;
}
@@ -0,0 +1,5 @@
package b;
import a.A;
public class B extends A {}
@@ -0,0 +1,4 @@
module moduleB {
requires transitive moduleA;
exports b;
}
@@ -0,0 +1,3 @@
module moduleC {
requires transitive moduleB;
}
@@ -0,0 +1,9 @@
package d;
import b.B;
public class JavaMain {
public static void main(String[] args) {
System.out.println(new B().ok());
}
}
@@ -0,0 +1,7 @@
package d
import b.B
fun main() {
println(B().ok())
}
@@ -0,0 +1,4 @@
module moduleD {
requires kotlin.stdlib;
requires moduleC;
}
@@ -210,6 +210,32 @@ abstract class AbstractJavaModulesIntegrationTest(
module("moduleD", listOf(c, b, a))
}
fun testInheritedDeclarationFromTwiceTransitiveDependency() {
// module A <-t- module B <-t- module C <--- module D
// Java: class A { String ok() { /* ... */ } }
val a = module("moduleA")
// Java: class B extends A
val b = module("moduleB", listOf(a))
val c = module("moduleC", listOf(a, b))
// Java: new B().ok()
// Kotlin: B().ok()
val d = module("moduleD", listOf(a, b, c))
// validate the run-time behavior of Java-compiled code for the sake of comparison
val (javaStdout, javaStderr) = runModule("moduleD/d.JavaMain", listOf(d, c, b, a))
assertEquals("", javaStderr)
assertEquals("OK", javaStdout)
// test the run-time behavior of Kotlin-compiled code
val (kotlinStdout, kotlinStderr) = runModule("moduleD/d.KotlinMainKt", listOf(d, c, b, a))
assertEquals("", kotlinStderr)
assertEquals("OK", kotlinStdout)
}
fun testSpecifyPathToModuleInfoInArguments() {
val a = module("moduleA")