diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/util/jvmClasspathUtil.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/util/jvmClasspathUtil.kt index 0826dbd6131..3a52c561728 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/util/jvmClasspathUtil.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/util/jvmClasspathUtil.kt @@ -43,7 +43,7 @@ internal const val KOTLIN_SCRIPT_RUNTIME_JAR_PROPERTY = "kotlin.script.runtime.j private val validClasspathFilesExtensions = setOf("jar", "zip", "java") fun classpathFromClassloader(classLoader: ClassLoader): List? = - generateSequence(classLoader) { it.parent }.toList().flatMap { + allRelatedClassLoaders(classLoader).toList().flatMap { val urls = (it as? URLClassLoader)?.urLs?.asList() ?: try { // e.g. for IDEA platform UrlClassLoader @@ -89,6 +89,24 @@ fun File.hasParentNamed(baseName: String): Boolean = private const val KOTLIN_COMPILER_EMBEDDABLE_JAR = "$KOTLIN_COMPILER_NAME-embeddable.jar" +private fun allRelatedClassLoaders(clsLoader: ClassLoader, visited: MutableSet = HashSet()): Sequence { + if (!visited.add(clsLoader)) return emptySequence() + + val singleParent = clsLoader.parent + if (singleParent != null) + return sequenceOf(clsLoader) + sequenceOf(singleParent).flatMap { allRelatedClassLoaders(it, visited) } + + return try { + val field = clsLoader.javaClass.getDeclaredField("myParents") // com.intellij.ide.plugins.cl.PluginClassLoader + field.isAccessible = true + val arrayOfClassLoaders = field.get(clsLoader) as Array + sequenceOf(clsLoader) + arrayOfClassLoaders.asSequence().flatMap { allRelatedClassLoaders(it, visited) } + } catch (e: Throwable) { + sequenceOf(clsLoader) + } +} + + internal fun List.takeIfContainsAll(vararg keyNames: String): List? = takeIf { classpath -> keyNames.all { key -> classpath.any { it.matchMaybeVersionedFile(key) } }