diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/IdeJavaModuleResolver.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/IdeJavaModuleResolver.kt index 18e395e2899..af5b8c58008 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/IdeJavaModuleResolver.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/IdeJavaModuleResolver.kt @@ -46,26 +46,23 @@ class IdeJavaModuleResolver(private val project: Project) : JavaModuleResolver { return JavaModuleResolver.AccessError.ModuleDoesNotReadModule(theirModule.name) } - val fqName = referencedPackage?.asString() ?: return null - if (!exports(theirModule, fqName, ourModule)) { - return JavaModuleResolver.AccessError.ModuleDoesNotExportPackage(theirModule.name) + // In the IDE, we allow unnamed module to access unexported package of the named module. The reason is that the compiler + // will use classpath, not the module path, when compilation of this module is launched from the IDE (because the module has + // no module-info). All of its dependencies will also land on the classpath, and everything is visible in the classpath, + // even non-exported packages of artifacts which would otherwise be loaded as named modules, if they were on the module path. + // So, no error will be reported from the compiler. Moreover, a run configuration of something from this unnamed module will also + // use classpath, not the module path, and in the same way everything will work at runtime as well. + if (ourModule != null) { + val fqName = referencedPackage?.asString() ?: return null + if (!exports(theirModule, fqName, ourModule)) { + return JavaModuleResolver.AccessError.ModuleDoesNotExportPackage(theirModule.name) + } } return null } // Returns whether or not [source] exports [packageName] to [target] - private fun exports(source: PsiJavaModule, packageName: String, target: PsiJavaModule?): Boolean { - if (source is LightJavaModule) { - return true - } - - // TODO: simply call JavaModuleGraphUtil.exports as soon as its 'target' parameter is nullable - if (target != null) { - return JavaModuleGraphUtil.exports(source, packageName, target) - } - return source.exports.any { statement -> - statement.moduleNames.isEmpty() && statement.packageName == packageName - } - } + private fun exports(source: PsiJavaModule, packageName: String, target: PsiJavaModule): Boolean = + source is LightJavaModule || JavaModuleGraphUtil.exports(source, packageName, target) } diff --git a/idea/testData/multiModuleHighlighting/java9/exportsTo/unnamed/unnamedUsage.kt b/idea/testData/multiModuleHighlighting/java9/exportsTo/unnamed/unnamedUsage.kt index a6b343c3ada..f542118d560 100644 --- a/idea/testData/multiModuleHighlighting/java9/exportsTo/unnamed/unnamedUsage.kt +++ b/idea/testData/multiModuleHighlighting/java9/exportsTo/unnamed/unnamedUsage.kt @@ -1,6 +1,6 @@ -import dependency.Foo +import dependency.Foo fun unnamedUsage(): String { - val foo: Foo = Foo() - return foo.toString() + val foo: Foo = Foo() + return foo.toString() } diff --git a/idea/testData/multiModuleHighlighting/java9/unnamedDependsOnNamed/main/usage.kt b/idea/testData/multiModuleHighlighting/java9/unnamedDependsOnNamed/main/usage.kt index d90a85f266f..b16b4ac9272 100644 --- a/idea/testData/multiModuleHighlighting/java9/unnamedDependsOnNamed/main/usage.kt +++ b/idea/testData/multiModuleHighlighting/java9/unnamedDependsOnNamed/main/usage.kt @@ -2,15 +2,15 @@ import dependency.* import dependency.J import dependency.K import dependency.impl.* -import dependency.impl.JImpl -import dependency.impl.KImpl +import dependency.impl.JImpl +import dependency.impl.KImpl fun usage(): String { val j: J = J.getInstance() val k: K = K.getInstance() - val jImpl: JImpl = J.getInstance() - val kImpl: KImpl = K.getInstance() + val jImpl: JImpl = J.getInstance() + val kImpl: KImpl = K.getInstance() return "$j$k$jImpl$kImpl" }