diff --git a/java/java-psi-api/java-psi-api.iml b/java/java-psi-api/java-psi-api.iml
index caff682b4a06..56cc8cf0ef77 100644
--- a/java/java-psi-api/java-psi-api.iml
+++ b/java/java-psi-api/java-psi-api.iml
@@ -8,6 +8,6 @@
+
-
-
+
\ No newline at end of file
diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiClassUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiClassUtil.java
index 1f2d47996384..bdc71934dc59 100644
--- a/java/java-psi-api/src/com/intellij/psi/util/PsiClassUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/util/PsiClassUtil.java
@@ -16,9 +16,24 @@
package com.intellij.psi.util;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.OrderEntry;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiAnonymousClass;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiModifier;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
/**
* @author mike
@@ -42,4 +57,31 @@ public class PsiClassUtil {
if (mustNotBeAbstract && aClass.hasModifierProperty(PsiModifier.ABSTRACT)) return false;
return aClass.getContainingClass() == null || aClass.hasModifierProperty(PsiModifier.STATIC);
}
+
+ /**
+ * Searches the project for modules that contain the class with the specified full-qualified name within
+ * the module dependencies or libraries.
+ *
+ * @param qualifiedName the full-qualified name of the class to find.
+ * @return the modules that contain the given class in dependencies or libraries.
+ */
+ @NotNull
+ public static Collection findModulesWithClass(@NotNull Project project, @NonNls @NotNull String qualifiedName) {
+ GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
+ JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
+ PsiClass[] possibleClasses = facade.findClasses(qualifiedName, allScope);
+ if (possibleClasses.length == 0) {
+ return Collections.emptyList();
+ }
+ Set relevantModules = ContainerUtil.newLinkedHashSet();
+ ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
+ for (PsiClass aClass : possibleClasses) {
+ VirtualFile classFile = aClass.getContainingFile().getVirtualFile();
+ for (OrderEntry orderEntry : fileIndex.getOrderEntriesForFile(classFile)) {
+ relevantModules.add(orderEntry.getOwnerModule());
+ }
+ }
+ return relevantModules;
+ }
+
}
diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/FindClassTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/FindClassTest.java
index 988017df992f..c3825da78195 100644
--- a/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/FindClassTest.java
+++ b/java/java-tests/testSrc/com/intellij/psi/impl/cache/impl/FindClassTest.java
@@ -16,9 +16,14 @@
package com.intellij.psi.impl.cache.impl;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.module.ModifiableModuleModel;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.module.StdModuleTypes;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
@@ -29,11 +34,15 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiClassUtil;
import com.intellij.testFramework.PsiTestCase;
import com.intellij.testFramework.PsiTestUtil;
+import com.intellij.util.containers.ContainerUtil;
import java.io.File;
import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
/**
* @author max
@@ -139,4 +148,64 @@ public class FindClassTest extends PsiTestCase {
}
});
}
+
+ public void testMultipleModules() throws Exception {
+ List otherModules = configureTwoMoreModules();
+ assertSize(2, otherModules);
+ PsiClass psiClass = myJavaFacade.findClass("p.A", getModule().getModuleWithDependenciesAndLibrariesScope(true));
+ assertNotNull(psiClass);
+ assertEquals("p.A", psiClass.getQualifiedName());
+
+ PsiClass packClass1 = myJavaFacade.findClass("pack.MyClass", getModule().getModuleWithDependenciesAndLibrariesScope(true));
+ assertNull(packClass1);
+
+ PsiClass psiClass2 = myJavaFacade.findClass("p.A", otherModules.get(0).getModuleWithDependenciesAndLibrariesScope(true));
+ assertNotNull(psiClass2);
+ assertEquals("p.A", psiClass2.getQualifiedName());
+
+ PsiClass packClass2 = myJavaFacade.findClass("pack.MyClass", otherModules.get(0).getModuleWithDependenciesAndLibrariesScope(true));
+ assertNotNull(packClass2);
+ assertEquals("pack.MyClass", packClass2.getQualifiedName());
+
+ PsiClass psiClass3 = myJavaFacade.findClass("p.A", otherModules.get(1).getModuleWithDependenciesAndLibrariesScope(true));
+ assertNull(psiClass3);
+
+ PsiClass packClass3 = myJavaFacade.findClass("pack.MyClass", otherModules.get(1).getModuleWithDependenciesAndLibrariesScope(true));
+ assertNull(packClass3);
+ }
+
+ public void testFindModulesWithClass() throws Exception {
+ List otherModules = configureTwoMoreModules();
+ assertSize(2, otherModules);
+
+ PsiClass psiClass = myJavaFacade.findClass("p.A", getModule().getModuleWithDependenciesAndLibrariesScope(true));
+ assertNotNull(psiClass);
+ PsiClass psiClass2 = myJavaFacade.findClass("p.A", otherModules.get(0).getModuleWithDependenciesAndLibrariesScope(true));
+ assertNotNull(psiClass2);
+ Collection modules = PsiClassUtil.findModulesWithClass(myProject, "p.A");
+ assertSameElements(modules, getModule(), otherModules.get(0));
+
+ PsiClass packClass = myJavaFacade.findClass("pack.MyClass", otherModules.get(0).getModuleWithDependenciesAndLibrariesScope(true));
+ assertNotNull(packClass);
+ Collection packModules = PsiClassUtil.findModulesWithClass(myProject, "pack.MyClass");
+ assertSameElements(packModules, otherModules.get(0));
+ }
+
+ private List configureTwoMoreModules() {
+ final List newModules = ContainerUtil.newArrayList();
+ ApplicationManager.getApplication().runWriteAction(() -> {
+ ModifiableModuleModel modifiableModel = ModuleManager.getInstance(getProject()).getModifiableModel();
+ Module module2 = modifiableModel.newModule("a.iml", StdModuleTypes.JAVA.getId());
+ newModules.add(module2);
+ ModuleRootModificationUtil.addDependency(module2, getModule());
+ File repoLib = new File(PathManagerEx.getTestDataPath(), "/psi/cls/repo/");
+ VirtualFile repoRoot = LocalFileSystem.getInstance().findFileByIoFile(repoLib);
+ assertNotNull(repoRoot);
+ ModuleRootModificationUtil.addModuleLibrary(module2, repoRoot.getUrl());
+ newModules.add(modifiableModel.newModule("b.iml", StdModuleTypes.JAVA.getId()));
+ modifiableModel.commit();
+ });
+ return newModules;
+ }
+
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.java
index a9f11d162698..6b3b42cd0fb0 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/GroovyConsoleUtil.java
@@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.console;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.JavaPsiFacade;
@@ -32,6 +33,8 @@ import org.jetbrains.plugins.groovy.config.GroovyFacetUtil;
import org.jetbrains.plugins.groovy.util.LibrariesUtil;
import org.jetbrains.plugins.groovy.util.ModuleChooserUtil;
+import java.util.Arrays;
+
public class GroovyConsoleUtil {
public static final Condition APPLICABLE_MODULE = new Condition() {
@@ -64,13 +67,17 @@ public class GroovyConsoleUtil {
facade.findClass("groovy.ui.GroovyMain", scope) != null;
}
-
public static void selectModuleAndRun(Project project, Consumer consumer) {
- ModuleChooserUtil.selectModule(project, APPLICABLE_MODULE, MODULE_VERSION, consumer);
+ ModuleChooserUtil.selectModule(project,
+ ModuleChooserUtil.filterGroovyCompatibleModules(
+ Arrays.asList(ModuleManager.getInstance(project).getModules()), APPLICABLE_MODULE),
+ MODULE_VERSION, consumer);
}
public static void selectModuleAndRun(Project project, Consumer consumer, DataContext context) {
- ModuleChooserUtil.selectModule(project, APPLICABLE_MODULE, MODULE_VERSION, consumer, context);
+ ModuleChooserUtil.selectModule(project, ModuleChooserUtil.filterGroovyCompatibleModules(
+ Arrays.asList(ModuleManager.getInstance(project).getModules()), APPLICABLE_MODULE),
+ MODULE_VERSION, consumer, context);
}
@Contract("null -> null; !null -> !null")
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrNewConsoleAction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrNewConsoleAction.java
index 677d95a359fc..65257a4afa8d 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrNewConsoleAction.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/console/actions/GrNewConsoleAction.java
@@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
@@ -30,6 +31,7 @@ import org.jetbrains.plugins.groovy.console.GroovyConsole;
import org.jetbrains.plugins.groovy.console.GroovyConsoleRootType;
import org.jetbrains.plugins.groovy.util.ModuleChooserUtil;
+import java.util.Arrays;
import java.util.List;
import static org.jetbrains.plugins.groovy.console.GroovyConsoleUtil.APPLICABLE_MODULE;
@@ -68,7 +70,8 @@ public class GrNewConsoleAction extends AnAction {
if (moduleForFile != null) return moduleForFile;
}
- final List modules = ModuleChooserUtil.getGroovyCompatibleModules(project, APPLICABLE_MODULE);
+ final List modules = ModuleChooserUtil.filterGroovyCompatibleModules(
+ Arrays.asList(ModuleManager.getInstance(project).getModules()), APPLICABLE_MODULE);
return modules.isEmpty() ? null : modules.get(0);
}
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/DefaultGroovyShellRunner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/DefaultGroovyShellRunner.java
index 9654e6dc3b6a..7657f3b4a675 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/DefaultGroovyShellRunner.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/DefaultGroovyShellRunner.java
@@ -18,10 +18,13 @@ package org.jetbrains.plugins.groovy.shell;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.JavaParameters;
import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiClassUtil;
+import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.config.AbstractConfigUtils;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
@@ -29,6 +32,9 @@ import org.jetbrains.plugins.groovy.runner.DefaultGroovyScriptRunner;
import org.jetbrains.plugins.groovy.runner.GroovyScriptRunConfiguration;
import org.jetbrains.plugins.groovy.util.LibrariesUtil;
+import java.util.Collection;
+import java.util.Set;
+
/**
* @author Sergey Evdokimov
*/
@@ -66,12 +72,20 @@ public class DefaultGroovyShellRunner extends GroovyShellConfig {
return version == AbstractConfigUtils.UNDEFINED_VERSION ? "" : "Groovy " + version;
}
+ private final static String[] REQUIRED_GROOVY_CLASSES = {
+ "org.apache.commons.cli.CommandLineParser",
+ "org.codehaus.groovy.tools.shell.Main",
+ "org.fusesource.jansi.AnsiConsole"};
+
public static boolean hasGroovyWithNeededJars(Module module) {
GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module);
JavaPsiFacade facade = JavaPsiFacade.getInstance(module.getProject());
- return facade.findClass("org.apache.commons.cli.CommandLineParser", scope) != null &&
- facade.findClass("org.codehaus.groovy.tools.shell.Main", scope) != null &&
- facade.findClass("org.fusesource.jansi.AnsiConsole", scope) != null;
+ for (String className : REQUIRED_GROOVY_CLASSES) {
+ if (facade.findClass(className, scope) == null) {
+ return false;
+ }
+ }
+ return true;
}
@Override
@@ -79,6 +93,23 @@ public class DefaultGroovyShellRunner extends GroovyShellConfig {
return super.isSuitableModule(module) && hasGroovyWithNeededJars(module);
}
+ @Override
+ public Collection getPossiblySuitableModules(Project project) {
+ Set results = null;
+ for (String className : REQUIRED_GROOVY_CLASSES) {
+ Collection someModules = PsiClassUtil.findModulesWithClass(project, className);
+ if (results == null) {
+ results = ContainerUtil.newLinkedHashSet(someModules);
+ } else {
+ results.retainAll(someModules);
+ }
+ if (results.isEmpty()) {
+ return ContainerUtil.emptyList();
+ }
+ }
+ return results;
+ }
+
@Override
public String getTitle() {
return "Groovy Shell";
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellActionBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellActionBase.java
index 6567050466d6..663b35834f67 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellActionBase.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellActionBase.java
@@ -31,6 +31,8 @@ import com.intellij.util.Function;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.util.ModuleChooserUtil;
+import java.util.Collection;
+
public abstract class GroovyShellActionBase extends AnAction {
private final GroovyShellConfig myConfig;
@@ -77,7 +79,8 @@ public abstract class GroovyShellActionBase extends AnAction {
@Nullable
@Override
public Result compute() {
- return Result.create(ModuleChooserUtil.hasGroovyCompatibleModules(project, APPLICABLE_MODULE),
+ Collection possibleModules = myConfig.getPossiblySuitableModules(project);
+ return Result.create(ModuleChooserUtil.hasGroovyCompatibleModules(possibleModules, APPLICABLE_MODULE),
ProjectRootModificationTracker.getInstance(project));
}
}, false);
@@ -87,6 +90,9 @@ public abstract class GroovyShellActionBase extends AnAction {
public void actionPerformed(AnActionEvent e) {
final Project project = e.getData(CommonDataKeys.PROJECT);
assert project != null;
- ModuleChooserUtil.selectModule(project, APPLICABLE_MODULE, VERSION_PROVIDER, RUNNER);
+ Collection suitableModules = ModuleChooserUtil.filterGroovyCompatibleModules(myConfig.getPossiblySuitableModules(project),
+ APPLICABLE_MODULE);
+ ModuleChooserUtil.selectModule(project, suitableModules, VERSION_PROVIDER, RUNNER);
}
+
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellConfig.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellConfig.java
index a4946c23cb77..a32a53d8185c 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellConfig.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/shell/GroovyShellConfig.java
@@ -18,11 +18,14 @@ package org.jetbrains.plugins.groovy.shell;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.JavaParameters;
import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.config.GroovyFacetUtil;
+import java.util.Collection;
+
public abstract class GroovyShellConfig {
@NotNull
@@ -46,5 +49,7 @@ public abstract class GroovyShellConfig {
return GroovyFacetUtil.isSuitableModule(module);
}
+ public abstract Collection getPossiblySuitableModules(Project project);
+
public abstract String getTitle();
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/ModuleChooserUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/ModuleChooserUtil.java
index ef537637136a..a9ed8458fb08 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/ModuleChooserUtil.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/ModuleChooserUtil.java
@@ -18,7 +18,6 @@ package org.jetbrains.plugins.groovy.util;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.Sdk;
@@ -43,21 +42,21 @@ public class ModuleChooserUtil {
private static final String GROOVY_LAST_MODULE = "Groovy.Last.Module.Chosen";
public static void selectModule(@NotNull Project project,
- final Condition check,
+ final Collection suitableModules,
final Function versionProvider,
final Consumer callback) {
- selectModule(project, check, versionProvider, callback, null);
+ selectModule(project, suitableModules, versionProvider, callback, null);
}
public static void selectModule(@NotNull Project project,
- final Condition check,
+ final Collection suitableModules,
final Function versionProvider,
final Consumer callback,
@Nullable DataContext context) {
final List modules = new ArrayList();
final Map versions = new HashMap();
- for (Module module : getGroovyCompatibleModules(project, check)) {
+ for (Module module : suitableModules) {
modules.add(module);
versions.put(module, versionProvider.fun(module));
}
@@ -132,11 +131,11 @@ public class ModuleChooserUtil {
};
}
- public static List getGroovyCompatibleModules(Project project, final Condition condition) {
- return ContainerUtil.filter(ModuleManager.getInstance(project).getModules(), isGroovyCompatibleModule(condition));
+ public static List filterGroovyCompatibleModules(Collection modules, final Condition condition) {
+ return ContainerUtil.filter(modules, isGroovyCompatibleModule(condition));
}
- public static boolean hasGroovyCompatibleModules(Project project, final Condition condition) {
- return ContainerUtil.or(ModuleManager.getInstance(project).getModules(), isGroovyCompatibleModule(condition));
+ public static boolean hasGroovyCompatibleModules(Collection modules, final Condition condition) {
+ return ContainerUtil.or(modules, isGroovyCompatibleModule(condition));
}
}