Bug 546945 - append module path to Javadoc URL for Java 11+

Copy of the fix for bug 539684 for the Javadoc browser in JDT UI.

Change-Id: Ibc5dd1e4ce1d95c313b1a09f6c15932632931879
Signed-off-by: Mikael Sterner <mikaels@comsol.se>
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AttachedJavadocTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AttachedJavadocTests.java
index a15c877..a3db75e 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AttachedJavadocTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AttachedJavadocTests.java
@@ -1361,5 +1361,20 @@
 			assertTrue("Should not happen", false);
 		}
 	}
+	public void testBug546945() throws JavaModelException {
+		IClasspathAttribute attribute =
+				JavaCore.newClasspathAttribute(
+						IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME,
+						"jar:platform:/resource/AttachedJavadocProject/bug546945_doc.zip!/");
+		IClasspathEntry newEntry = JavaCore.newLibraryEntry(new Path("/AttachedJavadocProject/bug546945.jar"), null, null, null, new IClasspathAttribute[] {attribute}, true);
+		this.project.setRawClasspath(new IClasspathEntry[]{newEntry}, null);
+		this.project.getResolvedClasspath(false);
+		this.project.setOption(JavaCore.COMPILER_COMPLIANCE, "11");
+
+		IPackageFragmentRoot jarRoot = this.project.getPackageFragmentRoot(getFile("/AttachedJavadocProject/bug546945.jar"));
+		IOrdinaryClassFile classFile = jarRoot.getPackageFragment("org.eclipse.pub").getOrdinaryClassFile("API.class");
+		String javadoc = classFile.getAttachedJavadoc(new NullProgressMonitor());
+		assertNotNull("Should have a javadoc", javadoc); //$NON-NLS-1$
+	}
 }
 
diff --git a/org.eclipse.jdt.core.tests.model/workspace/AttachedJavadocProject/bug546945.jar b/org.eclipse.jdt.core.tests.model/workspace/AttachedJavadocProject/bug546945.jar
new file mode 100644
index 0000000..b3cd3c6
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/AttachedJavadocProject/bug546945.jar
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/workspace/AttachedJavadocProject/bug546945_doc.zip b/org.eclipse.jdt.core.tests.model/workspace/AttachedJavadocProject/bug546945_doc.zip
new file mode 100644
index 0000000..dd78759
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/AttachedJavadocProject/bug546945_doc.zip
Binary files differ
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
index f7ccbe0..c8a50c9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
@@ -29,6 +29,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
@@ -1083,6 +1084,7 @@
 		typeQualifiedName = getElementName();
 	}
 
+	appendModulePath(pack, pathBuffer);
 	pathBuffer.append(pack.getElementName().replace('.', '/')).append('/').append(typeQualifiedName).append(JavadocConstants.HTML_EXTENSION);
 	if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
 	final String contents = getURLContents(baseLocation, String.valueOf(pathBuffer));
@@ -1096,4 +1098,49 @@
 public boolean isLambda() {
 	return false;
 }
+
+private static void appendModulePath(IPackageFragment pack, StringBuffer buf) {
+	IModuleDescription moduleDescription= getModuleDescription(pack);
+	if (moduleDescription != null) {
+		String moduleName= moduleDescription.getElementName();
+		if (moduleName != null && moduleName.length() > 0) {
+			buf.append(moduleName);
+			buf.append('/');
+		}
+	}
+}
+
+private static IModuleDescription getModuleDescription(IPackageFragment pack) {
+	if (pack == null) {
+		return null;
+	}
+	IModuleDescription moduleDescription= null;
+	/*
+	 * The Javadoc tool for Java SE 11 uses module name in the created URL.
+	 * We can't know what format is required, so we just guess by the project's compiler compliance.
+	 */
+	IJavaProject javaProject= pack.getJavaProject();
+	if (javaProject != null && isComplianceJava11OrHigher(javaProject)) {
+		if (pack.isReadOnly()) {
+			IPackageFragmentRoot root= (IPackageFragmentRoot) pack.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+			if (root != null) {
+				moduleDescription= root.getModuleDescription();
+			}
+		} else {
+			try {
+				moduleDescription= javaProject.getModuleDescription();
+			} catch (JavaModelException e) {
+				// do nothing
+			}
+		}
+	}
+	return moduleDescription;
+}
+
+private static boolean isComplianceJava11OrHigher(IJavaProject javaProject) {
+	if (javaProject == null) {
+		return false;
+	}
+	return CompilerOptions.versionToJdkLevel(javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true)) >= ClassFileConstants.JDK11;
+}
 }