Bug 553611 - Launch Configuration uses wrong module for main classes
outside the project module

Change-Id: Icaa91b9a21dcf813691c767c5f72fdbc35e1d08c
diff --git a/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
index 757f462..2c97028 100644
--- a/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.debug.ui; singleton:=true
-Bundle-Version: 3.10.500.qualifier
+Bundle-Version: 3.10.600.qualifier
 Bundle-Activator: org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/org.eclipse.jdt.debug.ui/pom.xml b/org.eclipse.jdt.debug.ui/pom.xml
index 26c4720..a9f378a 100644
--- a/org.eclipse.jdt.debug.ui/pom.xml
+++ b/org.eclipse.jdt.debug.ui/pom.xml
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.debug.ui</artifactId>
-  <version>3.10.500-SNAPSHOT</version>
+  <version>3.10.600-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   <properties>
     <code.ignoredWarnings>-warn:+resource,-deprecation,unavoidableGenericProblems</code.ignoredWarnings>
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaApplicationLaunchShortcut.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaApplicationLaunchShortcut.java
index bf3697c..1eea298 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaApplicationLaunchShortcut.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaApplicationLaunchShortcut.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2018 IBM Corporation and others.
+ * Copyright (c) 2007, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -33,6 +33,7 @@
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IModuleDescription;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
@@ -115,6 +116,7 @@
 			wc = configType.newInstance(null, getLaunchManager().generateLaunchConfigurationName(type.getTypeQualifiedName('.')));
 			wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, type.getFullyQualifiedName());
 			wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, type.getJavaProject().getElementName());
+			wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MODULE_NAME, getModuleName(type));
 			if (!isTestCode(type)) {
 				wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_EXCLUDE_TEST_CODE, true);
 			}
@@ -211,4 +213,15 @@
 	protected String getSelectionEmptyMessage() {
 		return LauncherMessages.JavaApplicationLaunchShortcut_2;
 	}
+
+	private String getModuleName(IType type) {
+		IJavaElement javaElement = type.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+		if (javaElement instanceof IPackageFragmentRoot) {
+			IModuleDescription moduleDescription = ((IPackageFragmentRoot) (javaElement)).getModuleDescription();
+			if (moduleDescription != null) {
+				return moduleDescription.getElementName();
+			}
+		}
+		return ""; //$NON-NLS-1$
+	}
 }
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaMainTab.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaMainTab.java
index 76bbf1c..9cb792f 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaMainTab.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaMainTab.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2017 IBM Corporation and others.
+ * Copyright (c) 2005, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -191,6 +191,7 @@
 		if (type != null) {
 			fMainText.setText(type.getFullyQualifiedName());
 			fProjText.setText(type.getJavaProject().getElementName());
+			fModuleName = getModuleName(type);
 		}
 	}
 
@@ -251,6 +252,7 @@
 	public void performApply(ILaunchConfigurationWorkingCopy config) {
 		config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, fProjText.getText().trim());
 		config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, fMainText.getText().trim());
+		config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MODULE_NAME, fModuleName);
 		mapResources(config);
 
 		// attribute added in 2.1, so null must be used instead of false for backwards compatibility
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/AbstractJavaMainTab.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/AbstractJavaMainTab.java
index ffee734..18db3ea 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/AbstractJavaMainTab.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/AbstractJavaMainTab.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2015 IBM Corporation and others.
+ * Copyright (c) 2005, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -85,6 +85,8 @@
 
 	private Button fProjButton;
 
+	protected String fModuleName = EMPTY_STRING;
+
 	private WidgetListener fListener = new WidgetListener();
 
 	/**
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/SharedJavaMainTab.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/SharedJavaMainTab.java
index 8ba8ead..2a8ab68 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/SharedJavaMainTab.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/SharedJavaMainTab.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2017 IBM Corporation and others.
+ * Copyright (c) 2005, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -25,6 +25,8 @@
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IMember;
+import org.eclipse.jdt.core.IModuleDescription;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.search.IJavaSearchScope;
 import org.eclipse.jdt.core.search.SearchEngine;
@@ -104,6 +106,7 @@
 	 */
 	protected void initializeMainTypeAndName(IJavaElement javaElement, ILaunchConfigurationWorkingCopy config) {
 		String name = null;
+		String moduleName = EMPTY_STRING;
 		if (javaElement instanceof IMember) {
 			IMember member = (IMember)javaElement;
 			if (member.isBinary()) {
@@ -119,8 +122,10 @@
 				MainMethodSearchEngine engine = new MainMethodSearchEngine();
 				IType[] types = engine.searchMainMethods(getLaunchConfigurationDialog(), scope, false);
 				if (types != null && (types.length > 0)) {
-					// Simply grab the first main type found in the searched element
+					// Simply grab the first main type found in the searched element and set the module name
 					name = types[0].getFullyQualifiedName();
+					moduleName = getModuleName(types[0]);
+
 				}
 			}
 			catch (InterruptedException ie) {JDIDebugUIPlugin.log(ie);}
@@ -130,6 +135,7 @@
 			name = EMPTY_STRING;
 		}
 		config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, name);
+		config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MODULE_NAME, moduleName);
 		if (name.length() > 0) {
 			int index = name.lastIndexOf('.');
 			if (index > 0) {
@@ -146,18 +152,21 @@
 	 */
 	protected void updateMainTypeFromConfig(ILaunchConfiguration config) {
 		String mainTypeName = EMPTY_STRING;
+		String moduleName = EMPTY_STRING;
 		try {
 			mainTypeName = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, EMPTY_STRING);
+			moduleName = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, EMPTY_STRING);
 		}
 		catch (CoreException ce) {JDIDebugUIPlugin.log(ce);}
 		fMainText.setText(mainTypeName);
+		fModuleName = moduleName;
 	}
 
 	/*
 	 * (non-Javadoc)
 	 *
 	 * @see org.eclipse.jdt.debug.ui.launchConfigurations.JavaLaunchTab#initializeAttributes()
-	 * 
+	 *
 	 * @since 3.9
 	 */
 	@Override
@@ -165,4 +174,15 @@
 		super.initializeAttributes();
 		getAttributesLabelsForPrototype().put(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, LauncherMessages.SharedJavaMainTab_AttributeLabel_MainTypeName);
 	}
+
+	protected String getModuleName(IType type) {
+		IJavaElement javaElement = type.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+		if (javaElement instanceof IPackageFragmentRoot) {
+			IModuleDescription moduleDescription = ((IPackageFragmentRoot) (javaElement)).getModuleDescription();
+			if (moduleDescription != null) {
+				return moduleDescription.getElementName();
+			}
+		}
+		return EMPTY_STRING;
+	}
 }
diff --git a/org.eclipse.jdt.launching/META-INF/MANIFEST.MF b/org.eclipse.jdt.launching/META-INF/MANIFEST.MF
index a61e556..e508f0b 100644
--- a/org.eclipse.jdt.launching/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.launching/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.launching; singleton:=true
-Bundle-Version: 3.16.0.qualifier
+Bundle-Version: 3.17.0.qualifier
 Bundle-Activator: org.eclipse.jdt.internal.launching.LaunchingPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/IJavaLaunchConfigurationConstants.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/IJavaLaunchConfigurationConstants.java
index 48d6b48..c8660ec 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/IJavaLaunchConfigurationConstants.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/IJavaLaunchConfigurationConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -83,6 +83,13 @@
 	public static final String ATTR_MAIN_TYPE_NAME = LaunchingPlugin.getUniqueIdentifier() + ".MAIN_TYPE";	 //$NON-NLS-1$
 
 	/**
+	 * Launch configuration attribute key. The value is the module name for the main type to launch.
+	 * 
+	 * @since 3.17
+	 */
+	public static final String ATTR_MODULE_NAME = LaunchingPlugin.getUniqueIdentifier() + ".MODULE_NAME"; //$NON-NLS-1$
+
+	/**
 	 * Launch configuration attribute key. The value is a boolean specifying
 	 * whether execution should stop when main is entered. The default value
 	 * is <code>false</code>.
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaLaunchDelegate.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaLaunchDelegate.java
index a1feb7e..80e34a6 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaLaunchDelegate.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaLaunchDelegate.java
@@ -101,18 +101,24 @@
 		runConfig.setVMSpecificAttributesMap(vmAttributesMap);
 		runConfig.setPreviewEnabled(supportsPreviewFeatures(configuration));
 		if (supportsModule()) {
-			// current module name, if so
-			try {
-				IJavaProject proj = JavaRuntime.getJavaProject(configuration);
-				if (proj != null) {
-					IModuleDescription module = proj == null ? null : proj.getModuleDescription();
-					String modName = module == null ? null : module.getElementName();
-					if (modName != null) {
-						runConfig.setModuleDescription(modName);
+			// Module name need not be the same as project name
+			String defaultModuleName = null;
+			String moduleName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MODULE_NAME, defaultModuleName);
+			if (moduleName != null) {
+				runConfig.setModuleDescription(moduleName);
+			} else {
+				try {
+					IJavaProject proj = JavaRuntime.getJavaProject(configuration);
+					if (proj != null) {
+						IModuleDescription module = proj == null ? null : proj.getModuleDescription();
+						String modName = module == null ? null : module.getElementName();
+						if (modName != null) {
+							runConfig.setModuleDescription(modName);
+						}
 					}
+				} catch (CoreException e) {
+					// Not a java Project so no need to set module description
 				}
-			} catch (CoreException e) {
-				// Not a java Project so no need to set module description
 			}
 		}
 
diff --git a/org.eclipse.jdt.launching/pom.xml b/org.eclipse.jdt.launching/pom.xml
index 158e3d1..5376a65 100644
--- a/org.eclipse.jdt.launching/pom.xml
+++ b/org.eclipse.jdt.launching/pom.xml
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.launching</artifactId>
-  <version>3.16.0-SNAPSHOT</version>
+  <version>3.17.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   
   <build>