diff --git a/java/codeserver/core/src/com/intellij/java/codeserver/core/JpmsModuleAccessInfo.kt b/java/codeserver/core/src/com/intellij/java/codeserver/core/JpmsModuleAccessInfo.kt index b2c3a3f35d88..5487e4dc968b 100644 --- a/java/codeserver/core/src/com/intellij/java/codeserver/core/JpmsModuleAccessInfo.kt +++ b/java/codeserver/core/src/com/intellij/java/codeserver/core/JpmsModuleAccessInfo.kt @@ -34,9 +34,24 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v JPS_DEPENDENCY_PROBLEM } + /** + * Access mode to determine whether the target is accessible + */ + enum class JpmsModuleAccessMode { + /** + * Consider the target as accessible if the source actually reads the target + */ + READ, + + /** + * Consider the target as accessible if it's exported to the source (even if the source doesn't read it) + */ + EXPORT + } + fun checkAccess( place: PsiFileSystemItem, - isAccessible: (JpmsModuleAccessInfo) -> Boolean, + accessMode: JpmsModuleAccessMode, ): JpmsModuleAccessProblem? { val targetModule = target.module if (targetModule != null) { @@ -53,7 +68,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v return null // a target is not on the mandatory module path } - if (!accessibleFromJdkModules(place, isAccessible) && + if (!accessibleFromJdkModules(place, accessMode) && !inAddedModules(currentJpsModule, targetModule.name) && !hasUpgrade(currentJpsModule, targetModule.name, target.packageName, place)) { return JpmsModuleAccessProblem.PACKAGE_NOT_IN_GRAPH @@ -69,7 +84,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v if (current.module != null && targetModule.name != PsiJavaModule.JAVA_BASE && - !isAccessible(this) && + !this.isAccessible(accessMode) && !inAddedReads(current.module, targetModule)) { return when { PsiNameHelper.isValidModuleName(targetModule.name, current.module) -> JpmsModuleAccessProblem.PACKAGE_DOES_NOT_READ @@ -82,7 +97,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v if (autoModule.module == null) { return JpmsModuleAccessProblem.TO_UNNAMED } - else if (!isAccessible(JpmsModuleAccessInfo(current, autoModule)) && + else if (!JpmsModuleAccessInfo(current, autoModule).isAccessible(accessMode) && !inAddedReads(current.module, null) && !inSameMultiReleaseModule(current, target)) { return JpmsModuleAccessProblem.TO_UNNAMED @@ -92,6 +107,13 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v return null } + private fun isAccessible(accessMode: JpmsModuleAccessMode): Boolean { + return when (accessMode) { + JpmsModuleAccessMode.READ -> isAccessible() + JpmsModuleAccessMode.EXPORT -> isExported() + } + } + /** * @param place place where the target module is accessed * @return access problem, or null if the target module is accessible without any problem @@ -115,7 +137,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v return JpmsModuleAccessProblem.JPS_DEPENDENCY_PROBLEM } - if (!accessibleFromJdkModules(place, { it.isAccessible() }) && + if (!accessibleFromJdkModules(place, JpmsModuleAccessMode.READ) && !inAddedModules(currentJpsModule, targetModule.name)) { return JpmsModuleAccessProblem.NOT_IN_GRAPH } @@ -157,7 +179,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v private fun accessibleFromJdkModules( place: PsiElement, - isAccessible: (JpmsModuleAccessInfo) -> Boolean, + accessMode: JpmsModuleAccessMode, ): Boolean { val jpsModule = current.jpsModule ?: return false val targetModule = target.module ?: return false @@ -176,7 +198,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v if (javaSE != null) { { module -> (!module.name.startsWith("java.") && module.exports.any { e -> e.moduleNames.isEmpty() }) || - isAccessible(JpmsModuleAccessInfo(JpmsModuleInfo.CurrentModuleInfo(javaSE, current.name) { jpsModule }, target)) + JpmsModuleAccessInfo(JpmsModuleInfo.CurrentModuleInfo(javaSE, current.name) { jpsModule }, target).isAccessible(accessMode) } } else { diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaPlatformModuleSystem.kt b/java/java-impl/src/com/intellij/psi/impl/JavaPlatformModuleSystem.kt index 6ed9ec107d65..c8ffb2d45a84 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaPlatformModuleSystem.kt +++ b/java/java-impl/src/com/intellij/psi/impl/JavaPlatformModuleSystem.kt @@ -30,11 +30,11 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx { override fun getName(): String = JavaBundle.message("java.platform.module.system.name") override fun isAccessible(targetPackageName: String, targetFile: PsiFile?, place: PsiElement): Boolean { - return getProblem(targetPackageName, targetFile, place, true) { it.isExported() } == null + return getProblem(targetPackageName, targetFile, place, true, JpmsModuleAccessInfo.JpmsModuleAccessMode.EXPORT) == null } override fun checkAccess(targetPackageName: String, targetFile: PsiFile?, place: PsiElement): ErrorWithFixes? { - return getProblem(targetPackageName, targetFile, place, false) { it.isAccessible() } + return getProblem(targetPackageName, targetFile, place, false, JpmsModuleAccessInfo.JpmsModuleAccessMode.READ) } override fun isAccessible(targetModule: PsiJavaModule, place: PsiElement): Boolean { @@ -43,7 +43,7 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx { } private fun getProblem(targetPackageName: String, targetFile: PsiFile?, place: PsiElement, quick: Boolean, - isAccessible: (JpmsModuleAccessInfo) -> Boolean): ErrorWithFixes? { + accessMode: JpmsModuleAccessInfo.JpmsModuleAccessMode): ErrorWithFixes? { val originalTargetFile = targetFile?.originalFile val useFile = place.containingFile?.originalFile ?: return null if (!PsiUtil.isAvailable(JavaFeature.MODULES, useFile)) return null @@ -53,7 +53,7 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx { if (useVFile != null && index.isInLibrarySource(useVFile)) return null if (originalTargetFile != null && originalTargetFile.isPhysical) { val target = TargetModuleInfo(originalTargetFile, targetPackageName) - return checkAccess(target, useFile, quick, isAccessible) + return checkAccess(target, useFile, quick, accessMode) } if (useVFile == null) return null @@ -71,11 +71,11 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx { } } - val error = checkAccess(TargetModuleInfo(dirs[0], target.qualifiedName), useFile, quick, isAccessible) ?: return null + val error = checkAccess(TargetModuleInfo(dirs[0], target.qualifiedName), useFile, quick, accessMode) ?: return null return when { dirs.size == 1 -> error dirs.asSequence().drop(1).any { TargetModuleInfo(it, target.qualifiedName) - .accessAt(useFile).checkAccess(useFile, isAccessible) == null } -> null + .accessAt(useFile).checkAccess(useFile, accessMode) == null } -> null else -> error } } @@ -83,10 +83,10 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx { private val ERR = ErrorWithFixes("-") private fun checkAccess(target: TargetModuleInfo, place: PsiFileSystemItem, quick: Boolean, - isAccessible: (JpmsModuleAccessInfo) -> Boolean): ErrorWithFixes? { + accessMode: JpmsModuleAccessInfo.JpmsModuleAccessMode): ErrorWithFixes? { val moduleAccess = target.accessAt(place) - val access = moduleAccess.checkAccess(place, isAccessible) + val access = moduleAccess.checkAccess(place, accessMode) return when { access == null -> null quick -> ERR