diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java index 43553988d0a4..a7c0218b8a6d 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java @@ -15,6 +15,7 @@ */ package com.intellij.execution.application; +import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil; import com.intellij.diagnostic.logging.LogConfigurationPanel; import com.intellij.execution.*; import com.intellij.execution.configuration.EnvironmentVariablesComponent; @@ -29,13 +30,19 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.options.SettingsEditorGroup; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.OrderEnumerator; +import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiJavaModule; +import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.util.PsiMethodUtil; import com.intellij.refactoring.listeners.RefactoringElementListener; +import com.intellij.util.PathsList; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,6 +50,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Stream; public class ApplicationConfiguration extends ModuleBasedConfiguration implements CommonJavaRunConfigurationParameters, SingleClassConfiguration, RefactoringListenerProvider { @@ -206,24 +214,24 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration getValidModules() { @@ -258,9 +266,9 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration classRoots(f, index)) + .forEach(f -> { + modulePath.add(f); + classPath.remove(f); + }); + } + } + } + + private static Stream classRoots(VirtualFile file, ProjectFileIndex index) { + if (index.isInSourceContent(file)) { + Module module = index.getModuleForFile(file); + if (module != null) { + return Stream.of(OrderEnumerator.orderEntries(module).runtimeOnly().withoutSdk().withoutLibraries().withoutDepModules().getClassesRoots()); + } + } + else { + VirtualFile root = index.getClassRootForFile(file); + if (root != null) { + return Stream.of(root); + } + } + return Stream.empty(); + } } -} +} \ No newline at end of file diff --git a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java index 4b20e2189202..cdacd3acc456 100644 --- a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java +++ b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,42 +20,46 @@ import com.intellij.execution.configurations.JavaCommandLine; import com.intellij.execution.configurations.JavaParameters; import com.intellij.execution.configurations.ParametersList; import com.intellij.execution.process.ProcessHandler; -import com.intellij.openapi.projectRoots.ex.JavaSdkUtil; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.projectRoots.ex.JavaSdkUtil; import com.intellij.openapi.util.SystemInfo; -import org.jetbrains.annotations.NonNls; import java.io.File; public class ProcessProxyFactoryImpl extends ProcessProxyFactory { - public ProcessProxy createCommandLineProxy(final JavaCommandLine javaCmdLine) throws ExecutionException { - ProcessProxyImpl proxy = null; - final JavaParameters javaParameters = javaCmdLine.getJavaParameters(); - String mainClass = javaParameters.getMainClass(); - if (ProcessProxyImpl.useLauncher() && mainClass != null) { - try { - proxy = new ProcessProxyImpl(); - JavaSdkUtil.addRtJar(javaParameters.getClassPath()); - final ParametersList vmParametersList = javaParameters.getVMParametersList(); - vmParametersList.defineProperty(ProcessProxyImpl.PROPERTY_PORT_NUMBER, String.valueOf(proxy.getPortNumber())); - vmParametersList.defineProperty(ProcessProxyImpl.PROPERTY_BINPATH, PathManager.getBinPath()); - javaParameters.getProgramParametersList().prepend(mainClass); - javaParameters.setMainClass(ProcessProxyImpl.LAUNCH_MAIN_CLASS); - } - catch (ProcessProxyImpl.NoMoreSocketsException e) { - proxy = null; + private static final String DONT_USE_LAUNCHER_PROPERTY = "idea.no.launcher"; + + @Override + public ProcessProxy createCommandLineProxy(JavaCommandLine javaCmdLine) throws ExecutionException { + JavaParameters javaParameters = javaCmdLine.getJavaParameters(); + if (useLauncher(javaParameters)) { + String mainClass = javaParameters.getMainClass(); + if (mainClass != null) { + try { + ProcessProxyImpl proxy = new ProcessProxyImpl(); + JavaSdkUtil.addRtJar(javaParameters.getClassPath()); + ParametersList vmParametersList = javaParameters.getVMParametersList(); + vmParametersList.defineProperty(ProcessProxyImpl.PROPERTY_PORT_NUMBER, String.valueOf(proxy.getPortNumber())); + vmParametersList.defineProperty(ProcessProxyImpl.PROPERTY_BIN_PATH, PathManager.getBinPath()); + javaParameters.getProgramParametersList().prepend(mainClass); + javaParameters.setMainClass(ProcessProxyImpl.LAUNCH_MAIN_CLASS); + return proxy; + } + catch (ProcessProxyImpl.NoMoreSocketsException ignored) { } } } - return proxy; + + return null; } - public ProcessProxy getAttachedProxy(final ProcessHandler processHandler) { + @Override + public ProcessProxy getAttachedProxy(ProcessHandler processHandler) { return processHandler != null ? processHandler.getUserData(ProcessProxyImpl.KEY) : null; } @Override public boolean isBreakGenLibraryAvailable() { - @NonNls final String libName; + String libName; if (SystemInfo.isWindows) { libName = "breakgen.dll"; } @@ -65,6 +69,10 @@ public class ProcessProxyFactoryImpl extends ProcessProxyFactory { else { libName = "libbreakgen.so"; } - return new File(PathManager.getBinPath() + File.separator + libName).exists(); + return new File(PathManager.getBinPath(), libName).exists(); + } + + private static boolean useLauncher(JavaParameters parameters) { + return !Boolean.getBoolean(DONT_USE_LAUNCHER_PROPERTY) && parameters.getModuleName() == null; } } \ No newline at end of file diff --git a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyImpl.java b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyImpl.java index f09d7b553639..66877b118e45 100644 --- a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyImpl.java +++ b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyImpl.java @@ -17,7 +17,6 @@ package com.intellij.execution.runners; import com.intellij.execution.process.ProcessHandler; import com.intellij.openapi.util.Key; -import org.jetbrains.annotations.NonNls; import java.io.BufferedWriter; import java.io.IOException; @@ -33,11 +32,10 @@ import java.net.Socket; class ProcessProxyImpl implements ProcessProxy { public static final Key KEY = Key.create("ProcessProxyImpl"); - @NonNls public static final String PROPERTY_BINPATH = "idea.launcher.bin.path"; - @NonNls public static final String PROPERTY_PORT_NUMBER = "idea.launcher.port"; - @NonNls public static final String LAUNCH_MAIN_CLASS = "com.intellij.rt.execution.application.AppMain"; + public static final String PROPERTY_BIN_PATH = "idea.launcher.bin.path"; + public static final String PROPERTY_PORT_NUMBER = "idea.launcher.port"; + public static final String LAUNCH_MAIN_CLASS = "com.intellij.rt.execution.application.AppMain"; - @NonNls private static final String DONT_USE_LAUNCHER_PROPERTY = "idea.no.launcher"; private static final int SOCKET_NUMBER_START = 7532; private static final int SOCKET_NUMBER = 100; private static final boolean[] ourUsedSockets = new boolean[SOCKET_NUMBER]; @@ -46,8 +44,7 @@ class ProcessProxyImpl implements ProcessProxy { private PrintWriter myWriter; private Socket mySocket; - public static class NoMoreSocketsException extends Exception { - } + public static class NoMoreSocketsException extends Exception { } public ProcessProxyImpl() throws NoMoreSocketsException { myPortNumber = findFreePort(); @@ -91,7 +88,7 @@ class ProcessProxyImpl implements ProcessProxy { } @SuppressWarnings({"SocketOpenedButNotSafelyClosed", "IOResourceOpenedButNotSafelyClosed"}) - private synchronized void writeLine(@NonNls final String s) { + private synchronized void writeLine(String s) { if (myWriter == null) { try { if (mySocket == null) { @@ -116,8 +113,4 @@ class ProcessProxyImpl implements ProcessProxy { public void sendStop() { writeLine("STOP"); } - - public static boolean useLauncher() { - return !Boolean.valueOf(System.getProperty(DONT_USE_LAUNCHER_PROPERTY)); - } -} +} \ 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 170e6a8e5d2d..65bec99cd7ff 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 @@ -41,6 +41,12 @@ import static com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MOD public class JavaModuleGraphUtil { private JavaModuleGraphUtil() { } + @Nullable + public static PsiJavaModule findDescriptorByElement(@NotNull PsiElement element) { + PsiFileSystemItem fsItem = element instanceof PsiFileSystemItem ? (PsiFileSystemItem)element : element.getContainingFile(); + return fsItem != null ? ModuleHighlightUtil.getModuleDescriptor(fsItem) : null; + } + @Nullable public static Collection findCycle(@NotNull PsiJavaModule module) { Project project = module.getProject(); @@ -57,10 +63,14 @@ public class JavaModuleGraphUtil { } public static boolean reads(@NotNull PsiJavaModule source, @NotNull PsiJavaModule destination) { - Project project = source.getProject(); - RequiresGraph graph = CachedValuesManager.getManager(project).getCachedValue(project, () -> - Result.create(buildRequiresGraph(project), OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)); - return graph.reads(source, destination); + return getRequiresGraph(source).reads(source, destination); + } + + @NotNull + public static Collection moduleDependencies(@NotNull PsiJavaModule start) { + Set result = ContainerUtil.newHashSet(); + visit(getRequiresGraph(start), start, result); + return result; } // Looks for cycles between Java modules in the project sources. @@ -111,6 +121,12 @@ public class JavaModuleGraphUtil { return map; } + private static RequiresGraph getRequiresGraph(@NotNull PsiJavaModule source) { + Project project = source.getProject(); + return CachedValuesManager.getManager(project).getCachedValue(project, () -> + Result.create(buildRequiresGraph(project), OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)); + } + // Starting from source modules, collects all module dependencies in the project. // The resulting graph is used for tracing readability. private static RequiresGraph buildRequiresGraph(Project project) { @@ -142,6 +158,12 @@ public class JavaModuleGraphUtil { } } + private static void visit(RequiresGraph graph, PsiJavaModule module, Set result) { + if (result.add(module)) { + graph.dependencies(module).forEach(dependency -> visit(graph, dependency, result)); + } + } + private static class RequiresGraph { private final Graph myGraph; private final Set myPublicEdges; @@ -165,6 +187,10 @@ public class JavaModuleGraphUtil { return false; } + public Iterable dependencies(PsiJavaModule node) { + return myGraph.getNodes().contains(node) ? () -> myGraph.getIn(node) : Collections.emptyList(); + } + public static String key(PsiJavaModule module, PsiJavaModule exporter) { return module.getModuleName() + '/' + exporter.getModuleName(); } diff --git a/platform/core-api/src/com/intellij/util/PathsList.java b/platform/core-api/src/com/intellij/util/PathsList.java index b93dc9938032..af0385de832e 100644 --- a/platform/core-api/src/com/intellij/util/PathsList.java +++ b/platform/core-api/src/com/intellij/util/PathsList.java @@ -63,6 +63,10 @@ public class PathsList { } }; + public boolean isEmpty() { + return myPathSet.isEmpty(); + } + public void add(String path) { addAllLast(chooseFirstTimeItems(path), myPath); } @@ -77,6 +81,13 @@ public class PathsList { add(LOCAL_PATH.fun(file)); } + public void remove(VirtualFile file) { + String path = LOCAL_PATH.fun(file); + if (path != null) { + remove(path); + } + } + public void addFirst(String path) { int index = 0; for (String element : chooseFirstTimeItems(path)) { diff --git a/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java b/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java index 022e64f8dc55..1676640b62d3 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java @@ -38,6 +38,8 @@ public class SimpleJavaParameters extends SimpleProgramParameters { private Sdk myJdk; private String myMainClass; private final PathsList myClassPath = new PathsList(); + private String myModuleName; + private final PathsList myModulePath = new PathsList(); private final ParametersList myVmParameters = new ParametersList(); private Charset myCharset = CharsetToolkit.getDefaultSystemCharset(); private boolean myUseDynamicClasspath; @@ -67,6 +69,18 @@ public class SimpleJavaParameters extends SimpleProgramParameters { return myClassPath; } + public String getModuleName() { + return myModuleName; + } + + public void setModuleName(String moduleName) { + myModuleName = moduleName; + } + + public PathsList getModulePath() { + return myModulePath; + } + public ParametersList getVMParametersList() { return myVmParameters; } diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java index 57a3ce3f405f..c32284360fda 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java @@ -33,6 +33,7 @@ import com.intellij.openapi.util.text.StringUtilRt; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.util.PathUtil; +import com.intellij.util.PathsList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.execution.ParametersListUtil; import com.intellij.util.lang.ClassPath; @@ -167,33 +168,36 @@ public class JdkUtil { final boolean forceDynamicClasspath) { final GeneralCommandLine commandLine = new GeneralCommandLine(exePath); - final ParametersList vmParametersList = javaParameters.getVMParametersList(); + final ParametersList vmParameters = javaParameters.getVMParametersList(); commandLine.withEnvironment(javaParameters.getEnv()); commandLine.withParentEnvironmentType(javaParameters.isPassParentEnvs() ? ParentEnvironmentType.CONSOLE : ParentEnvironmentType.NONE); final Class commandLineWrapper; boolean passProgramParametersViaClassPathJar = false; - if ((commandLineWrapper = getCommandLineWrapperClass()) != null) { - if (forceDynamicClasspath && !vmParametersList.hasParameter("-classpath") && !vmParametersList.hasParameter("-cp")) { - if (isClassPathJarEnabled(javaParameters, PathUtil.getJarPathForClass(ClassPath.class))) { - passProgramParametersViaClassPathJar = javaParameters.isPassProgramParametersViaClasspathJar(); - appendJarClasspathParams(javaParameters, commandLine, vmParametersList, commandLineWrapper, passProgramParametersViaClassPathJar); - } - else { - appendOldCommandLineWrapper(javaParameters, commandLine, vmParametersList, commandLineWrapper); - } + if (forceDynamicClasspath && + !explicitClassPath(vmParameters) && + javaParameters.getModulePath().isEmpty() && + (commandLineWrapper = getCommandLineWrapperClass()) != null) { + if (isClassPathJarEnabled(javaParameters, PathUtil.getJarPathForClass(ClassPath.class))) { + passProgramParametersViaClassPathJar = javaParameters.isPassProgramParametersViaClasspathJar(); + appendJarClasspathParams(javaParameters, commandLine, vmParameters, commandLineWrapper, passProgramParametersViaClassPathJar); } else { - appendParamsEncodingClasspath(javaParameters, commandLine, vmParametersList); + appendOldCommandLineWrapper(javaParameters, commandLine, vmParameters, commandLineWrapper); } } else { - appendParamsEncodingClasspath(javaParameters, commandLine, vmParametersList); + appendParamsEncodingClasspath(javaParameters, commandLine, vmParameters); } final String mainClass = javaParameters.getMainClass(); + final String moduleName = javaParameters.getModuleName(); final String jarPath = javaParameters.getJarPath(); - if (mainClass != null) { + if (moduleName != null && mainClass != null) { + commandLine.addParameter("-m"); + commandLine.addParameter(moduleName + '/' + mainClass); + } + else if (mainClass != null) { commandLine.addParameter(mainClass); } else if (jarPath != null) { @@ -210,6 +214,14 @@ public class JdkUtil { return commandLine; } + private static boolean explicitClassPath(ParametersList vmParameters) { + return vmParameters.hasParameter("-cp") || vmParameters.hasParameter("-classpath") || vmParameters.hasParameter("--class-path"); + } + + private static boolean explicitModulePath(ParametersList vmParameters) { + return vmParameters.hasParameter("-p") || vmParameters.hasParameter("--module-path"); + } + private static void appendOldCommandLineWrapper(SimpleJavaParameters javaParameters, GeneralCommandLine commandLine, ParametersList vmParametersList, Class commandLineWrapper) { @@ -374,12 +386,21 @@ public class JdkUtil { private static void appendParamsEncodingClasspath(SimpleJavaParameters javaParameters, GeneralCommandLine commandLine, - ParametersList parametersList) { - commandLine.addParameters(parametersList.getList()); - appendEncoding(javaParameters, commandLine, parametersList); - if (!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp") && !javaParameters.getClassPath().getPathList().isEmpty()){ + ParametersList vmParameters) { + commandLine.addParameters(vmParameters.getList()); + + appendEncoding(javaParameters, commandLine, vmParameters); + + PathsList classPath = javaParameters.getClassPath(); + if (!classPath.isEmpty() && !explicitClassPath(vmParameters)) { commandLine.addParameter("-classpath"); - commandLine.addParameter(javaParameters.getClassPath().getPathsString()); + commandLine.addParameter(classPath.getPathsString()); + } + + PathsList modulePath = javaParameters.getModulePath(); + if (!modulePath.isEmpty() && !explicitModulePath(vmParameters)) { + commandLine.addParameter("-p"); + commandLine.addParameter(modulePath.getPathsString()); } }