[maven] IDEA-255308 fix "The service implementation must be defined in the same module" error for multi-release modules

GitOrigin-RevId: ca9fbd1ea7611357844fdf3c77a731e0e911c651
This commit is contained in:
Dmitry Kichinsky
2025-02-01 12:25:30 +00:00
committed by intellij-monorepo-bot
parent 8e8b301fb2
commit e66362d4cc
3 changed files with 46 additions and 34 deletions
@@ -425,7 +425,9 @@ final class ModuleHighlightUtil {
PsiElement implTarget = implRef.resolve();
if (implTarget instanceof PsiClass implClass) {
if (ModuleUtilCore.findModuleForFile(file) != ModuleUtilCore.findModuleForFile(implClass.getContainingFile())) {
Module fileModule = ModuleUtilCore.findModuleForFile(file);
Module implModule = ModuleUtilCore.findModuleForFile(implClass.getContainingFile());
if (fileModule != implModule && !MultiReleaseUtil.inSameMultiReleaseModule(implModule, fileModule)) {
String message = JavaErrorBundle.message("module.service.alien");
HighlightInfo.Builder info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(implRef)).descriptionAndTooltip(message);
@@ -0,0 +1,42 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:JvmName("MultiReleaseUtil")
package com.intellij.codeInsight.daemon.impl.analysis
import com.intellij.openapi.module.Module
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.jps.entities.ModuleId
import com.intellij.platform.workspace.jps.entities.exModuleOptions
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.jps.model.serialization.SerializationConstants.MAVEN_EXTERNAL_SOURCE_ID
import java.util.regex.Pattern
private const val MAIN = "main"
private val javaVersionPattern: Pattern by lazy { Pattern.compile("java\\d+") }
@Internal
fun inSameMultiReleaseModule(mainModule: Module, additionalModule: Module): Boolean {
// Maven
val project = additionalModule.project
val storage = project.workspaceModel.currentSnapshot
val placeModuleName = additionalModule.name
val targetModuleName = mainModule.name
val placeModuleExOptions = storage.resolve(ModuleId(placeModuleName))?.exModuleOptions
val targetModuleExOptions = storage.resolve(ModuleId(targetModuleName))?.exModuleOptions
if (placeModuleExOptions?.externalSystem == MAVEN_EXTERNAL_SOURCE_ID
&& targetModuleExOptions?.externalSystem == MAVEN_EXTERNAL_SOURCE_ID) {
val baseModuleName = targetModuleName.substringBeforeLast('.')
if (placeModuleName.startsWith(baseModuleName)
&& placeModuleExOptions.externalSystemModuleType == "MAIN_ONLY_ADDITIONAL" // StandardMavenModuleType.MAIN_ONLY_ADDITIONAL
&& targetModuleExOptions.externalSystemModuleType == "MAIN_ONLY" // StandardMavenModuleType.MAIN_ONLY
) {
return true
}
}
// Gradle
if (targetModuleName.endsWith(".$MAIN")) {
val baseModuleName = targetModuleName.substringBeforeLast(MAIN)
return javaVersionPattern.matcher(placeModuleName.substringAfter(baseModuleName)).matches()
}
return false
}
@@ -28,10 +28,7 @@ import com.intellij.openapi.roots.JdkOrderEntry
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.eel.provider.utils.EelPathUtils
import com.intellij.platform.workspace.jps.entities.ModuleId
import com.intellij.platform.workspace.jps.entities.exModuleOptions
import com.intellij.pom.java.JavaFeature
import com.intellij.psi.*
import com.intellij.psi.JavaModuleSystem.*
@@ -43,16 +40,11 @@ import com.intellij.util.concurrency.AppExecutorUtil
import com.intellij.util.containers.CollectionFactory
import com.intellij.util.indexing.DumbModeAccessType
import org.jetbrains.annotations.NonNls
import org.jetbrains.jps.model.serialization.SerializationConstants.MAVEN_EXTERNAL_SOURCE_ID
import java.nio.file.Path
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import java.util.regex.Pattern
private const val MAIN = "main"
private val javaVersionPattern: Pattern by lazy { Pattern.compile("java\\d+") }
/**
* Checks package accessibility according to JLS 7 "Packages and Modules".
@@ -309,31 +301,7 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx {
private fun inSameMultiReleaseModule(current: ModuleInfo, target: ModuleInfo): Boolean {
val placeModule = current.jpsModule ?: return false
val targetModule = target.jpsModule ?: return false
// Maven
val project = placeModule.project
val storage = project.workspaceModel.currentSnapshot
val placeModuleName = placeModule.name
val targetModuleName = targetModule.name
val placeModuleExOptions = storage.resolve(ModuleId(placeModuleName))?.exModuleOptions
val targetModuleExOptions = storage.resolve(ModuleId(targetModuleName))?.exModuleOptions
if (placeModuleExOptions?.externalSystem == MAVEN_EXTERNAL_SOURCE_ID
&& targetModuleExOptions?.externalSystem == MAVEN_EXTERNAL_SOURCE_ID) {
val baseModuleName = targetModuleName.substringBeforeLast('.')
if (placeModuleName.startsWith(baseModuleName)
&& placeModuleExOptions.externalSystemModuleType == "MAIN_ONLY_ADDITIONAL" // StandardMavenModuleType.MAIN_ONLY_ADDITIONAL
&& targetModuleExOptions.externalSystemModuleType == "MAIN_ONLY" // StandardMavenModuleType.MAIN_ONLY
) {
return true
}
}
// Gradle
if (targetModuleName.endsWith(".$MAIN")) {
val baseModuleName = targetModuleName.substringBeforeLast(MAIN)
return javaVersionPattern.matcher(placeModuleName.substringAfter(baseModuleName)).matches()
}
return false
return com.intellij.codeInsight.daemon.impl.analysis.inSameMultiReleaseModule(targetModule, placeModule)
}
private fun detectAutomaticModule(current: ModuleInfo): PsiJavaModule? {