diff --git a/java/codeserver/core/intellij.java.codeserver.core.iml b/java/codeserver/core/intellij.java.codeserver.core.iml
index ddd48c7f6b9f..d0873c34122e 100644
--- a/java/codeserver/core/intellij.java.codeserver.core.iml
+++ b/java/codeserver/core/intellij.java.codeserver.core.iml
@@ -3,6 +3,7 @@
+
@@ -17,5 +18,6 @@
+
\ No newline at end of file
diff --git a/java/codeserver/core/resources/META-INF/JavaCodeServerCore.xml b/java/codeserver/core/resources/META-INF/JavaCodeServerCore.xml
new file mode 100644
index 000000000000..ec47d70f0457
--- /dev/null
+++ b/java/codeserver/core/resources/META-INF/JavaCodeServerCore.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiModuleUtil.java b/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiModuleUtil.java
index bd6a4d00dea4..b1852a3ce926 100644
--- a/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiModuleUtil.java
+++ b/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiModuleUtil.java
@@ -18,22 +18,27 @@ import com.intellij.psi.impl.light.LightJavaModule;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
+import com.intellij.psi.search.searches.JavaModuleSearch;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.JavaMultiReleaseUtil;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.MultiMap;
+import com.intellij.util.graph.Graph;
+import com.intellij.util.graph.GraphGenerator;
+import com.intellij.util.indexing.DumbModeAccessType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.java.JavaResourceRootType;
import org.jetbrains.jps.model.java.JavaSourceRootType;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
+import java.util.function.BiFunction;
import java.util.jar.JarFile;
+import static com.intellij.psi.PsiJavaModule.JAVA_BASE;
+
/**
* Utilities related to JPMS modules
*/
@@ -212,4 +217,245 @@ public final class JavaPsiModuleUtil {
return null;
}
+
+ /**
+ * @param source source module
+ * @param destination target module
+ * @return true if the source module reads the target module
+ */
+ public static boolean reads(@NotNull PsiJavaModule source, @NotNull PsiJavaModule destination) {
+ return getRequiresGraph(source).reads(source, destination);
+ }
+
+ /**
+ * @param source source module
+ * @return set of all direct (non-transitive) dependencies of the source module
+ */
+ public static @NotNull Set getAllDependencies(@NotNull PsiJavaModule source) {
+ return getRequiresGraph(source).getAllDependencies(source, false);
+ }
+
+ /**
+ * @param source source module
+ * @return set of all direct and indirect (transitive) dependencies of the source module
+ */
+ public static @NotNull Set getAllTransitiveDependencies(@NotNull PsiJavaModule source) {
+ return getRequiresGraph(source).getAllDependencies(source, true);
+ }
+
+ /**
+ * Represents a dependency conflict when a single package is imported from two modules
+ * @param packageName package name
+ * @param module1 first module from which this package is being read
+ * @param module2 second module from which this package is being read
+ */
+ public record ModulePackageConflict(@NotNull String packageName, @NotNull PsiJavaModule module1, @NotNull PsiJavaModule module2) { }
+
+ /**
+ * @param module module to check
+ * @return a {@link ModulePackageConflict} representing a package name conflict among module dependencies; null if no conflict found.
+ * If there are several conflicts, only the first one is returned.
+ */
+ public static @Nullable ModulePackageConflict findConflict(@NotNull PsiJavaModule module) {
+ return getRequiresGraph(module).findConflict(module);
+ }
+
+ /**
+ * @param module module that accesses a package
+ * @param packageName the name of the accessed package
+ * @return the module where the package is declared; null if not found
+ */
+ public static @Nullable PsiJavaModule findOrigin(@NotNull PsiJavaModule module, @NotNull String packageName) {
+ return getRequiresGraph(module).findOrigin(module, packageName);
+ }
+
+ private static RequiresGraph getRequiresGraph(@NotNull PsiJavaModule module) {
+ final Project project = module.getProject();
+ if (DumbService.getInstance(project).isAlternativeResolveEnabled()) {
+ return DumbModeAccessType.RELIABLE_DATA_ONLY.ignoreDumbMode(() -> buildRequiresGraph(project));
+ }
+ return CachedValuesManager.getManager(project).getCachedValue(project, () ->
+ CachedValueProvider.Result.create(buildRequiresGraph(project),
+ PsiJavaModuleModificationTracker.getInstance(project),
+ ProjectRootModificationTracker.getInstance(project)));
+ }
+
+ /*
+ * Collects all module dependencies in the project.
+ * The resulting graph is used for tracing readability and checking package conflicts.
+ */
+ private static @NotNull RequiresGraph buildRequiresGraph(@NotNull Project project) {
+ MultiMap relations = MultiMap.create();
+ Set transitiveEdges = new HashSet<>();
+
+ GlobalSearchScope scope = ProjectScope.getAllScope(project);
+ JavaModuleSearch.allModules(project, scope).forEach(module -> {
+ visit(module, relations, transitiveEdges);
+ return true;
+ });
+
+ Graph graph = GraphGenerator.generate(new ChameleonGraph<>(relations, true));
+ return new RequiresGraph(graph, transitiveEdges);
+ }
+
+ private static void visit(@NotNull PsiJavaModule module, @NotNull MultiMap relations, @NotNull Set transitiveEdges) {
+ if (!(module instanceof LightJavaModule) && !relations.containsKey(module)) {
+ relations.putValues(module, Collections.emptyList());
+ boolean explicitJavaBase = false;
+ for (PsiRequiresStatement statement : module.getRequires()) {
+ PsiJavaModuleReference ref = statement.getModuleReference();
+ if (ref != null) {
+ if (JAVA_BASE.equals(ref.getCanonicalText())) explicitJavaBase = true;
+ for (ResolveResult result : ref.multiResolve(false)) {
+ PsiJavaModule dependency = (PsiJavaModule)result.getElement();
+ assert dependency != null : result;
+ relations.putValue(module, dependency);
+ if (statement.hasModifierProperty(PsiModifier.TRANSITIVE)) transitiveEdges.add(RequiresGraph.key(dependency, module));
+ visit(dependency, relations, transitiveEdges);
+ }
+ }
+ }
+ if (!explicitJavaBase) {
+ PsiJavaModule javaBase = JavaPsiFacade.getInstance(module.getProject()).findModule(JAVA_BASE, module.getResolveScope());
+ if (javaBase != null) relations.putValue(module, javaBase);
+ }
+ }
+ }
+
+ private static final class ChameleonGraph implements Graph {
+ private final Set myNodes;
+ private final MultiMap myEdges;
+ private final boolean myInbound;
+
+ private ChameleonGraph(MultiMap edges, boolean inbound) {
+ myNodes = new HashSet<>();
+ edges.entrySet().forEach(e -> {
+ myNodes.add(e.getKey());
+ myNodes.addAll(e.getValue());
+ });
+ myEdges = edges;
+ myInbound = inbound;
+ }
+
+ @Override
+ public @NotNull Collection getNodes() {
+ return myNodes;
+ }
+
+ @Override
+ public @NotNull Iterator getIn(N n) {
+ return myInbound ? myEdges.get(n).iterator() : Collections.emptyIterator();
+ }
+
+ @Override
+ public @NotNull Iterator getOut(N n) {
+ return myInbound ? Collections.emptyIterator() : myEdges.get(n).iterator();
+ }
+ }
+
+ private static final class RequiresGraph {
+ private final @NotNull Graph myGraph;
+ private final @NotNull Set myTransitiveEdges;
+
+ private RequiresGraph(@NotNull Graph graph, @NotNull Set transitiveEdges) {
+ myGraph = graph;
+ myTransitiveEdges = transitiveEdges;
+ }
+
+ public boolean reads(PsiJavaModule source, PsiJavaModule destination) {
+ Collection nodes = myGraph.getNodes();
+ if (nodes.contains(destination) && nodes.contains(source)) {
+ Iterator directReaders = myGraph.getOut(destination);
+ while (directReaders.hasNext()) {
+ PsiJavaModule next = directReaders.next();
+ if (source.equals(next) || myTransitiveEdges.contains(key(destination, next)) && reads(source, next)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private @Nullable ModulePackageConflict findConflict(@NotNull PsiJavaModule source) {
+ Map exports = new HashMap<>();
+ return processExports(source, (pkg, m) -> {
+ PsiJavaModule found = exports.put(pkg, m);
+ return found == null ||
+ found instanceof LightJavaModule && m instanceof LightJavaModule ||
+ found.getName().equals(m.getName())
+ ? null : new ModulePackageConflict(pkg, found, m);
+ });
+ }
+
+ private @Nullable PsiJavaModule findOrigin(@NotNull PsiJavaModule module, @NotNull String packageName) {
+ return processExports(module, (pkg, m) -> packageName.equals(pkg) ? m : null);
+ }
+
+ private @Nullable T processExports(@NotNull PsiJavaModule start, @NotNull BiFunction super String, ? super PsiJavaModule, ? extends T> processor) {
+ return myGraph.getNodes().contains(start) ? processExports(start.getName(), start, true, new HashSet<>(), processor) : null;
+ }
+
+ private @Nullable T processExports(@Nullable String name,
+ @NotNull PsiJavaModule module,
+ boolean direct,
+ @NotNull Set super PsiJavaModule> visited,
+ @NotNull BiFunction super String, ? super PsiJavaModule, ? extends T> processor) {
+ if (visited.add(module)) {
+ if (!direct) {
+ for (PsiPackageAccessibilityStatement statement : module.getExports()) {
+ List exportTargets = statement.getModuleNames();
+ if (exportTargets.isEmpty() || exportTargets.contains(name)) {
+ T result = processor.apply(statement.getPackageName(), module);
+ if (result != null) return result;
+ }
+ }
+ }
+ for (Iterator iterator = myGraph.getIn(module); iterator.hasNext();) {
+ PsiJavaModule dependency = iterator.next();
+ if (direct || myTransitiveEdges.contains(key(dependency, module))) {
+ T result = processExports(name, dependency, false, visited, processor);
+ if (result != null) return result;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public static @NotNull String key(@NotNull PsiJavaModule module, @NotNull PsiJavaModule exporter) {
+ return module.getName() + '/' + exporter.getName();
+ }
+
+ public @NotNull Set getAllDependencies(@NotNull PsiJavaModule module, boolean transitive) {
+ Set requires = new HashSet<>();
+ collectDependencies(module, requires, transitive);
+ return requires;
+ }
+
+ private void collectDependencies(@NotNull PsiJavaModule module, @NotNull Set dependencies, boolean transitive) {
+ for (Iterator iterator = myGraph.getIn(module); iterator.hasNext();) {
+ PsiJavaModule dependency = iterator.next();
+ if (!dependencies.contains(dependency) && (!transitive || myTransitiveEdges.contains(key(dependency, module)))) {
+ dependencies.add(dependency);
+ collectDependencies(dependency, dependencies, transitive);
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper service to support resolve in java-psi-impl
+ */
+ public static class Helper extends JavaModuleGraphHelper {
+ @Contract("null->null")
+ @Override
+ public @Nullable PsiJavaModule findDescriptorByElement(@Nullable PsiElement element) {
+ return JavaPsiModuleUtil.findDescriptorByElement(element);
+ }
+
+ @Override
+ public @NotNull Set getAllTransitiveDependencies(@NotNull PsiJavaModule psiJavaModule) {
+ return JavaPsiModuleUtil.getAllTransitiveDependencies(psiJavaModule);
+ }
+ }
}
diff --git a/java/execution/impl/intellij.java.execution.impl.iml b/java/execution/impl/intellij.java.execution.impl.iml
index 8b54aa8c3482..7ae1cc54ce79 100644
--- a/java/execution/impl/intellij.java.execution.impl.iml
+++ b/java/execution/impl/intellij.java.execution.impl.iml
@@ -53,6 +53,7 @@
+
diff --git a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java
index 9885ff8cee12..a00fadca640b 100644
--- a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java
+++ b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java
@@ -1,12 +1,12 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.execution.util;
-import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil;
import com.intellij.execution.CantRunException;
import com.intellij.execution.CommonJavaRunConfigurationParameters;
import com.intellij.execution.ExecutionBundle;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.*;
+import com.intellij.java.codeserver.core.JavaPsiModuleUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
@@ -225,7 +225,7 @@ public final class JavaParametersUtil {
Set forModulePath = new HashSet<>(explicitModules);
for (PsiJavaModule explicitModule : explicitModules) {
- forModulePath.addAll(JavaModuleGraphUtil.getAllDependencies(explicitModule));
+ forModulePath.addAll(JavaPsiModuleUtil.getAllDependencies(explicitModule));
}
if (!includeTests) {
@@ -296,7 +296,7 @@ public final class JavaParametersUtil {
PsiClassType provideInterfaceType = provide.getInterfaceType();
if (provideInterfaceType != null && interfaces.contains(provideInterfaceType.getCanonicalText())) {
registerProviders.accept(aModule);
- JavaModuleGraphUtil.getAllDependencies(aModule).forEach(registerProviders);
+ JavaPsiModuleUtil.getAllDependencies(aModule).forEach(registerProviders);
continue nextModule;
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphHelperImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphHelperImpl.java
deleted file mode 100644
index 10001182bf70..000000000000
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphHelperImpl.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package com.intellij.codeInsight.daemon.impl.analysis;
-
-import com.intellij.java.codeserver.core.JavaPsiModuleUtil;
-import com.intellij.psi.JavaModuleGraphHelper;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiJavaModule;
-import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Set;
-
-public class JavaModuleGraphHelperImpl extends JavaModuleGraphHelper {
- @Contract("null->null")
- @Override
- public @Nullable PsiJavaModule findDescriptorByElement(@Nullable PsiElement element) {
- return JavaPsiModuleUtil.findDescriptorByElement(element);
- }
-
- @Override
- public @NotNull Set getAllTransitiveDependencies(@NotNull PsiJavaModule psiJavaModule) {
- return JavaModuleGraphUtil.getAllTransitiveDependencies(psiJavaModule);
- }
-}
\ No newline at end of file
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java
index 2819199f8da6..38f4fd48242e 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaModuleGraphUtil.java
@@ -13,11 +13,9 @@ import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtilCore;
-import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
-import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
@@ -25,8 +23,6 @@ import com.intellij.psi.impl.PsiJavaModuleModificationTracker;
import com.intellij.psi.impl.light.LightJavaModule;
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.search.ProjectScope;
-import com.intellij.psi.search.searches.JavaModuleSearch;
import com.intellij.psi.util.CachedValueProvider.Result;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiUtil;
@@ -36,15 +32,12 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.graph.DFSTBuilder;
import com.intellij.util.graph.Graph;
-import com.intellij.util.graph.GraphGenerator;
-import com.intellij.util.indexing.DumbModeAccessType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.*;
-import java.util.function.BiFunction;
import static com.intellij.openapi.roots.DependencyScope.PROVIDED;
import static com.intellij.psi.PsiJavaModule.JAVA_BASE;
@@ -95,26 +88,6 @@ public final class JavaModuleGraphUtil {
return targets != null && (targets.isEmpty() || target != null && targets.contains(target.getName()));
}
- public static boolean reads(@NotNull PsiJavaModule source, @NotNull PsiJavaModule destination) {
- return getRequiresGraph(source).reads(source, destination);
- }
-
- public static @NotNull Set getAllDependencies(PsiJavaModule source) {
- return getRequiresGraph(source).getAllDependencies(source, false);
- }
-
- public static @NotNull Set getAllTransitiveDependencies(PsiJavaModule source) {
- return getRequiresGraph(source).getAllDependencies(source, true);
- }
-
- public static @Nullable Trinity findConflict(@NotNull PsiJavaModule module) {
- return getRequiresGraph(module).findConflict(module);
- }
-
- public static @Nullable PsiJavaModule findOrigin(@NotNull PsiJavaModule module, @NotNull String packageName) {
- return getRequiresGraph(module).findOrigin(module, packageName);
- }
-
/**
* Determines if a specified module is readable from a given context
*
@@ -179,7 +152,7 @@ public final class JavaModuleGraphUtil {
if (from == to) return false;
if (!PsiNameHelper.isValidModuleName(to.getName(), to)) return false;
if (contains(from.getRequires(), to.getName())) return false;
- if (reads(from, to)) return false;
+ if (JavaPsiModuleUtil.reads(from, to)) return false;
PsiUtil.addModuleStatement(from, PsiKeyword.REQUIRES + " " +
(isStaticModule(to.getName(), scope) ? PsiKeyword.STATIC + " " : "") +
(isExported(from, to) ? PsiKeyword.TRANSITIVE + " " : "") +
@@ -194,33 +167,6 @@ public final class JavaModuleGraphUtil {
return false;
}
- /**
- * Optimizes the dependencies of a current module file by removing redundant 'requires' statements
- * that contain (transitive) in the selected dependency.
- *
- * @param currentModule The Java module for which to optimize the dependencies.
- * @param selectedDependency The Java module that is the selected dependency.
- */
- public static void optimizeDependencies(@NotNull PsiJavaModule currentModule, @NotNull PsiJavaModule selectedDependency) {
- Map requires = new HashMap<>();
- for (PsiRequiresStatement require : currentModule.getRequires()) {
- PsiJavaModule resolvedModule = require.resolve();
- if (resolvedModule != null) {
- requires.put(resolvedModule, require);
- }
- }
-
- Set redundant = new HashSet<>();
- for (PsiJavaModule module : requires.keySet()) {
- if (module.getName().equals(selectedDependency.getName())) continue;
- if (reads(selectedDependency, module)) redundant.add(module);
- }
-
- for (PsiJavaModule module : redundant) {
- requires.get(module).delete();
- }
- }
-
private static boolean isExported(@NotNull PsiJavaModule from, @NotNull PsiJavaModule to) {
VirtualFile toFile = getVirtualFile(to);
if (toFile == null) return false;
@@ -326,149 +272,6 @@ public final class JavaModuleGraphUtil {
return map;
}
- private static RequiresGraph getRequiresGraph(@NotNull PsiJavaModule module) {
- final Project project = module.getProject();
- if (DumbService.getInstance(project).isAlternativeResolveEnabled()) {
- return DumbModeAccessType.RELIABLE_DATA_ONLY.ignoreDumbMode(() -> buildRequiresGraph(project));
- }
- return CachedValuesManager.getManager(project).getCachedValue(project, () ->
- Result.create(buildRequiresGraph(project),
- PsiJavaModuleModificationTracker.getInstance(project),
- ProjectRootModificationTracker.getInstance(project)));
- }
-
- /*
- * Collects all module dependencies in the project.
- * The resulting graph is used for tracing readability and checking package conflicts.
- */
- private static @NotNull RequiresGraph buildRequiresGraph(@NotNull Project project) {
- MultiMap relations = MultiMap.create();
- Set transitiveEdges = new HashSet<>();
-
- GlobalSearchScope scope = ProjectScope.getAllScope(project);
- JavaModuleSearch.allModules(project, scope).forEach(module -> {
- visit(module, relations, transitiveEdges);
- return true;
- });
-
- Graph graph = GraphGenerator.generate(new ChameleonGraph<>(relations, true));
- return new RequiresGraph(graph, transitiveEdges);
- }
-
- private static void visit(@NotNull PsiJavaModule module, @NotNull MultiMap relations, @NotNull Set transitiveEdges) {
- if (!(module instanceof LightJavaModule) && !relations.containsKey(module)) {
- relations.putValues(module, Collections.emptyList());
- boolean explicitJavaBase = false;
- for (PsiRequiresStatement statement : module.getRequires()) {
- PsiJavaModuleReference ref = statement.getModuleReference();
- if (ref != null) {
- if (JAVA_BASE.equals(ref.getCanonicalText())) explicitJavaBase = true;
- for (ResolveResult result : ref.multiResolve(false)) {
- PsiJavaModule dependency = (PsiJavaModule)result.getElement();
- assert dependency != null : result;
- relations.putValue(module, dependency);
- if (statement.hasModifierProperty(PsiModifier.TRANSITIVE)) transitiveEdges.add(RequiresGraph.key(dependency, module));
- visit(dependency, relations, transitiveEdges);
- }
- }
- }
- if (!explicitJavaBase) {
- PsiJavaModule javaBase = JavaPsiFacade.getInstance(module.getProject()).findModule(JAVA_BASE, module.getResolveScope());
- if (javaBase != null) relations.putValue(module, javaBase);
- }
- }
- }
-
- private static final class RequiresGraph {
- private final @NotNull Graph myGraph;
- private final @NotNull Set myTransitiveEdges;
-
- private RequiresGraph(@NotNull Graph graph, @NotNull Set transitiveEdges) {
- myGraph = graph;
- myTransitiveEdges = transitiveEdges;
- }
-
- public boolean reads(PsiJavaModule source, PsiJavaModule destination) {
- Collection nodes = myGraph.getNodes();
- if (nodes.contains(destination) && nodes.contains(source)) {
- Iterator directReaders = myGraph.getOut(destination);
- while (directReaders.hasNext()) {
- PsiJavaModule next = directReaders.next();
- if (source.equals(next) || myTransitiveEdges.contains(key(destination, next)) && reads(source, next)) {
- return true;
- }
- }
- }
- return false;
- }
-
- public @Nullable Trinity findConflict(@NotNull PsiJavaModule source) {
- Map exports = new HashMap<>();
- return processExports(source, (pkg, m) -> {
- PsiJavaModule found = exports.put(pkg, m);
- return found == null ||
- found instanceof LightJavaModule && m instanceof LightJavaModule ||
- found.getName().equals(m.getName())
- ? null : new Trinity<>(pkg, found, m);
- });
- }
-
- public @Nullable PsiJavaModule findOrigin(@NotNull PsiJavaModule module, @NotNull String packageName) {
- return processExports(module, (pkg, m) -> packageName.equals(pkg) ? m : null);
- }
-
- private @Nullable T processExports(@NotNull PsiJavaModule start, @NotNull BiFunction super String, ? super PsiJavaModule, ? extends T> processor) {
- return myGraph.getNodes().contains(start) ? processExports(start.getName(), start, true, new HashSet<>(), processor) : null;
- }
-
- private @Nullable T processExports(@Nullable String name,
- @NotNull PsiJavaModule module,
- boolean direct,
- @NotNull Set super PsiJavaModule> visited,
- @NotNull BiFunction super String, ? super PsiJavaModule, ? extends T> processor) {
- if (visited.add(module)) {
- if (!direct) {
- for (PsiPackageAccessibilityStatement statement : module.getExports()) {
- List exportTargets = statement.getModuleNames();
- if (exportTargets.isEmpty() || exportTargets.contains(name)) {
- T result = processor.apply(statement.getPackageName(), module);
- if (result != null) return result;
- }
- }
- }
- for (Iterator iterator = myGraph.getIn(module); iterator.hasNext();) {
- PsiJavaModule dependency = iterator.next();
- if (direct || myTransitiveEdges.contains(key(dependency, module))) {
- T result = processExports(name, dependency, false, visited, processor);
- if (result != null) return result;
- }
- }
- }
-
- return null;
- }
-
- public static @NotNull String key(@NotNull PsiJavaModule module, @NotNull PsiJavaModule exporter) {
- return module.getName() + '/' + exporter.getName();
- }
-
- public @NotNull Set getAllDependencies(@NotNull PsiJavaModule module, boolean transitive) {
- Set requires = new HashSet<>();
- collectDependencies(module, requires, transitive);
- return requires;
- }
-
- private void collectDependencies(@NotNull PsiJavaModule module, @NotNull Set dependencies, boolean transitive) {
- for (Iterator iterator = myGraph.getIn(module); iterator.hasNext();) {
- PsiJavaModule dependency = iterator.next();
- if (!dependencies.contains(dependency) && (!transitive || myTransitiveEdges.contains(key(dependency, module)))) {
- dependencies.add(dependency);
- collectDependencies(dependency, dependencies, transitive);
- }
- }
- }
- }
-
private static final class ChameleonGraph implements Graph {
private final Set myNodes;
private final MultiMap myEdges;
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java
index 8fefeef8fbc2..7476a0d5c281 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java
@@ -11,6 +11,7 @@ import com.intellij.codeInsight.daemon.impl.quickfix.*;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.java.codeserver.core.JavaPsiModuleUtil;
+import com.intellij.java.codeserver.core.JavaPsiModuleUtil.ModulePackageConflict;
import com.intellij.modcommand.ModCommandAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
@@ -19,7 +20,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.JavaFeature;
@@ -60,7 +60,7 @@ final class ModuleHighlightUtil {
if (javaModule != null) {
String packageName = statement.getPackageName();
if (packageName != null) {
- PsiJavaModule origin = JavaModuleGraphUtil.findOrigin(javaModule, packageName);
+ PsiJavaModule origin = JavaPsiModuleUtil.findOrigin(javaModule, packageName);
if (origin != null) {
PsiJavaCodeReferenceElement reference = statement.getPackageReference();
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
@@ -485,10 +485,10 @@ final class ModuleHighlightUtil {
}
static HighlightInfo.Builder checkClashingReads(@NotNull PsiJavaModule module) {
- Trinity conflict = JavaModuleGraphUtil.findConflict(module);
+ ModulePackageConflict conflict = JavaPsiModuleUtil.findConflict(module);
if (conflict != null) {
String message = JavaErrorBundle.message(
- "module.conflicting.reads", module.getName(), conflict.first, conflict.second.getName(), conflict.third.getName());
+ "module.conflicting.reads", module.getName(), conflict.packageName(), conflict.module1(), conflict.module2());
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range(module)).descriptionAndTooltip(message);
}
diff --git a/java/java-impl-inspections/src/com/intellij/codeInspection/reflectiveAccess/Java9ReflectionClassVisibilityInspection.java b/java/java-impl-inspections/src/com/intellij/codeInspection/reflectiveAccess/Java9ReflectionClassVisibilityInspection.java
index fa21b74090b3..d3f11306c17f 100644
--- a/java/java-impl-inspections/src/com/intellij/codeInspection/reflectiveAccess/Java9ReflectionClassVisibilityInspection.java
+++ b/java/java-impl-inspections/src/com/intellij/codeInspection/reflectiveAccess/Java9ReflectionClassVisibilityInspection.java
@@ -1,7 +1,6 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection.reflectiveAccess;
-import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil;
import com.intellij.codeInsight.daemon.impl.quickfix.AddExportsDirectiveFix;
import com.intellij.codeInsight.daemon.impl.quickfix.AddOpensDirectiveFix;
import com.intellij.codeInsight.daemon.impl.quickfix.AddRequiresDirectiveFix;
@@ -62,7 +61,7 @@ public final class Java9ReflectionClassVisibilityInspection extends AbstractBase
if (psiClass != null) {
final PsiJavaModule otherModule = JavaPsiModuleUtil.findDescriptorByElement(psiClass);
if (otherModule != null && otherModule != javaModule) {
- if (!JavaModuleGraphUtil.reads(javaModule, otherModule)) {
+ if (!JavaPsiModuleUtil.reads(javaModule, otherModule)) {
String message = JavaBundle.message("module.not.in.requirements", javaModule.getName(), otherModule.getName());
holder.problem(classNameArgument, message).fix(new AddRequiresDirectiveFix(javaModule, otherModule.getName())).register();
return;
diff --git a/java/java-impl/resources/META-INF/JavaPlugin.xml b/java/java-impl/resources/META-INF/JavaPlugin.xml
index e2a2914b1a4e..97bc7de232fb 100644
--- a/java/java-impl/resources/META-INF/JavaPlugin.xml
+++ b/java/java-impl/resources/META-INF/JavaPlugin.xml
@@ -11,6 +11,7 @@
+
@@ -395,8 +396,6 @@
serviceImplementation="com.intellij.psi.impl.file.PsiPackageImplementationHelperImpl"/>
-
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java
index e05263a702a9..2a85f890f2e4 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java
@@ -7,7 +7,6 @@ import com.intellij.codeInsight.completion.scope.CompletionElement;
import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor;
import com.intellij.codeInsight.completion.util.CompletionStyleUtil;
import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
-import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil;
import com.intellij.codeInsight.editorActions.TabOutScopesTracker;
import com.intellij.codeInsight.guess.GuessManager;
import com.intellij.codeInsight.lookup.*;
@@ -520,11 +519,11 @@ public final class JavaCompletionUtil {
}
if (PsiUtil.isAvailable(JavaFeature.MODULES, myPlace)) {
final PsiJavaModule currentModule =
- ReadAction.compute(() -> JavaModuleGraphUtil.findDescriptorByFile(myOriginalFile, myPlace.getProject()));
+ ReadAction.compute(() -> JavaPsiModuleUtil.findDescriptorByFile(myOriginalFile, myPlace.getProject()));
if (currentModule != null) {
final PsiJavaModule targetModule = ReadAction.compute(() -> JavaPsiModuleUtil.findDescriptorByElement(psiClass));
if (targetModule != null && targetModule != currentModule &&
- !JavaModuleGraphUtil.reads(currentModule, targetModule)) {
+ !JavaPsiModuleUtil.reads(currentModule, targetModule)) {
LookupElementDecorator element = generator.apply(presentation -> presentation.setItemTextForeground(JBColor.RED));
return PrioritizedLookupElement.withExplicitProximity(element, -1);
}
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 836f5f82840e..a48eb4033da4 100644
--- a/java/java-impl/src/com/intellij/psi/impl/JavaPlatformModuleSystem.kt
+++ b/java/java-impl/src/com/intellij/psi/impl/JavaPlatformModuleSystem.kt
@@ -12,6 +12,7 @@ import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.QuickFixFactory
import com.intellij.codeInspection.util.IntentionName
import com.intellij.java.JavaBundle
+import com.intellij.java.codeserver.core.JavaPsiModuleUtil
import com.intellij.java.codeserver.core.JavaPsiModuleUtil.findDescriptorByElement
import com.intellij.modcommand.ActionContext
import com.intellij.modcommand.ModCommand
@@ -50,21 +51,21 @@ internal class JavaPlatformModuleSystem : JavaModuleSystemEx {
return getProblem(targetPackageName, targetFile, place, false) { (current, target) ->
val currentModule = current.module ?: return@getProblem false
val targetModule = target.module ?: return@getProblem false
- return@getProblem JavaModuleGraphUtil.reads(currentModule, targetModule)
+ return@getProblem JavaPsiModuleUtil.reads(currentModule, targetModule)
}
}
override fun isAccessible(targetModule: PsiJavaModule, place: PsiElement): Boolean {
return getProblem(targetModule, place, true) { (current, target) ->
if (current.module == null || target.module == null) return@getProblem false
- return@getProblem JavaModuleGraphUtil.reads(current.module, target.module!!)
+ return@getProblem JavaPsiModuleUtil.reads(current.module, target.module!!)
} == null
}
override fun checkAccess(targetModule: PsiJavaModule, place: PsiElement): ErrorWithFixes? {
return getProblem(targetModule, place, false) { (current, target) ->
if (current.module == null || target.module == null) return@getProblem false
- return@getProblem JavaModuleGraphUtil.reads(current.module, target.module!!)
+ return@getProblem JavaPsiModuleUtil.reads(current.module, target.module!!)
}
}
diff --git a/java/java-impl/src/com/intellij/psi/util/proximity/ExplicitlyImportedWeigher.java b/java/java-impl/src/com/intellij/psi/util/proximity/ExplicitlyImportedWeigher.java
index 12a8c1002015..6c115d470f22 100644
--- a/java/java-impl/src/com/intellij/psi/util/proximity/ExplicitlyImportedWeigher.java
+++ b/java/java-impl/src/com/intellij/psi/util/proximity/ExplicitlyImportedWeigher.java
@@ -1,7 +1,6 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi.util.proximity;
-import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil;
import com.intellij.java.codeserver.core.JavaPsiModuleUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
@@ -33,7 +32,7 @@ public final class ExplicitlyImportedWeigher extends ProximityWeigher {
BiConsumer, PsiJavaModule> append = (list, module) -> {
if (module != null) {
list.add(module);
- list.addAll(JavaModuleGraphUtil.getAllTransitiveDependencies(module));
+ list.addAll(JavaPsiModuleUtil.getAllTransitiveDependencies(module));
}
};
diff --git a/plugins/kotlin/core/kotlin.core.iml b/plugins/kotlin/core/kotlin.core.iml
index f9055a0dd223..71cdffeb4151 100644
--- a/plugins/kotlin/core/kotlin.core.iml
+++ b/plugins/kotlin/core/kotlin.core.iml
@@ -61,5 +61,6 @@
+
\ No newline at end of file
diff --git a/plugins/kotlin/core/src/org/jetbrains/kotlin/idea/modules/IdeJavaModuleResolver.kt b/plugins/kotlin/core/src/org/jetbrains/kotlin/idea/modules/IdeJavaModuleResolver.kt
index 0c801fbc5a37..ea58ebf00ea7 100644
--- a/plugins/kotlin/core/src/org/jetbrains/kotlin/idea/modules/IdeJavaModuleResolver.kt
+++ b/plugins/kotlin/core/src/org/jetbrains/kotlin/idea/modules/IdeJavaModuleResolver.kt
@@ -3,6 +3,7 @@
package org.jetbrains.kotlin.idea.modules
import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil
+import com.intellij.java.codeserver.core.JavaPsiModuleUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.openapi.vfs.VirtualFile
@@ -64,7 +65,7 @@ class IdeJavaModuleResolver(private val project: Project) : JavaModuleResolver {
return JavaModuleResolver.AccessError.ModuleDoesNotReadUnnamedModule
}
- if (ourModule != null && !JavaModuleGraphUtil.reads(ourModule, theirModule)) {
+ if (ourModule != null && !JavaPsiModuleUtil.reads(ourModule, theirModule)) {
return JavaModuleResolver.AccessError.ModuleDoesNotReadModule(theirModule.name)
}