[java] split TargetModuleInfo based on creation place

- there are 2 cases: one when only PsiJavaModule might appear and another one where we detect the module by PsiFile.

- let's separate them in API, moving from PsiFile to VirtualFile to avoid slow (in kotlin) navigationElement resolution

^KTIJ-34700 fixed

GitOrigin-RevId: df96f36a4aa15f1cd41b1665ff4da208fd0d0ea4
This commit is contained in:
Anna Kozlova
2025-07-01 17:09:03 +00:00
committed by intellij-monorepo-bot
parent 9c2d0c504f
commit 53e8197345
4 changed files with 29 additions and 17 deletions
@@ -633,7 +633,7 @@ public final class JavaPsiModuleUtil {
public boolean isAccessible(@NotNull PsiJavaModule targetModule, @NotNull PsiElement place) {
PsiFile useFile = place.getContainingFile() != null ? place.getContainingFile().getOriginalFile() : null;
if (useFile == null) return true;
return new JpmsModuleInfo.TargetModuleInfo(targetModule, "").accessAt(useFile).checkModuleAccess(place) == null;
return new JpmsModuleInfo.TargetModuleInfoByJavaModule(targetModule, "").accessAt(useFile).checkModuleAccess(place) == null;
}
}
}
@@ -95,7 +95,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v
}
}
else if (current.module != null) {
val autoModule = JpmsModuleInfo.TargetModuleInfo(detectAutomaticModule(target), target.packageName)
val autoModule = JpmsModuleInfo.TargetModuleInfoByJavaModule(detectAutomaticModule(target), target.packageName)
if (autoModule.module == null) {
return JpmsModuleAccessProblem.TO_UNNAMED
}
@@ -154,7 +154,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v
}
}
else if (current.module != null) {
val autoModule = JpmsModuleInfo.TargetModuleInfo(detectAutomaticModule(target), target.packageName)
val autoModule = JpmsModuleInfo.TargetModuleInfoByJavaModule(detectAutomaticModule(target), target.packageName)
if (autoModule.module != null &&
!JpmsModuleAccessInfo(current, autoModule).isAccessible() &&
!inAddedReads(current.module, null) &&
@@ -3,7 +3,9 @@ package com.intellij.java.codeserver.core
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.pom.java.JavaFeature
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightJavaModule
@@ -37,15 +39,8 @@ sealed interface JpmsModuleInfo {
/**
* Represents the details of a target module
*/
class TargetModuleInfo(element: PsiElement?, val packageName: String) : JpmsModuleInfo {
override val jpsModule: Module? by lazy {
if (element == null) return@lazy null
ModuleUtilCore.findModuleForPsiElement(element)
}
override val module: PsiJavaModule? by lazy {
JavaPsiModuleUtil.findDescriptorByElement(element)
}
interface TargetModuleInfo: JpmsModuleInfo {
val packageName: String
/**
* @return access information when the specified target module is accessed at a given place
*/
@@ -56,6 +51,23 @@ sealed interface JpmsModuleInfo {
}
}
class TargetModuleInfoByJavaModule(override val module: PsiJavaModule?, override val packageName: String) : TargetModuleInfo {
override val jpsModule: Module? by lazy {
if (module == null) return@lazy null
ModuleUtilCore.findModuleForPsiElement(module)
}
}
class TargetModuleInfoByFile(virtualFile: VirtualFile, project: Project, override val packageName: String) : TargetModuleInfo {
override val jpsModule: Module? by lazy {
ModuleUtilCore.findModuleForFile(virtualFile, project)
}
override val module: PsiJavaModule? by lazy {
JavaPsiModuleUtil.findDescriptorByFile(virtualFile, project)
}
}
companion object {
/**
* Find module info structures when accessing a given location.
@@ -70,15 +82,15 @@ sealed interface JpmsModuleInfo {
*/
@JvmStatic
fun findTargetModuleInfos(targetPackageName: String, targetFile: PsiFile?, place: PsiFile): List<TargetModuleInfo>? {
val originalTargetFile = targetFile?.navigationElement
if (!PsiUtil.isAvailable(JavaFeature.MODULES, place)) return null
val useVFile = place.virtualFile
val project = place.project
val index = ProjectFileIndex.getInstance(project)
if (useVFile != null && index.isInLibrarySource(useVFile)) return null
if (originalTargetFile != null && originalTargetFile.isPhysical) {
return listOf(TargetModuleInfo(originalTargetFile, targetPackageName))
val targetVirtualFile = targetFile?.virtualFile
if (targetVirtualFile != null && index.isInProject(targetVirtualFile)) {
return listOf(TargetModuleInfoByFile(targetVirtualFile, project, targetPackageName))
}
if (useVFile == null) return null
@@ -97,7 +109,7 @@ sealed interface JpmsModuleInfo {
}
}
return dirs.map { dir -> TargetModuleInfo(dir, packageName) }
return dirs.map { dir -> TargetModuleInfoByFile(dir.virtualFile, project, packageName) }
}
}
}
@@ -327,7 +327,7 @@ final class ModuleChecker {
reportUnresolvedJavaModule(refElement);
return;
}
JpmsModuleAccessInfo moduleAccess = new JpmsModuleInfo.TargetModuleInfo(target, "").accessAt(myVisitor.file().getOriginalFile());
JpmsModuleAccessInfo moduleAccess = new JpmsModuleInfo.TargetModuleInfoByJavaModule(target, "").accessAt(myVisitor.file().getOriginalFile());
JpmsModuleAccessProblem problem = moduleAccess.checkModuleAccess(statement);
if (problem != null) {
myVisitor.report(accessError(problem).create(statement, moduleAccess));