8178067: support for @uses/@provides tags is broken

Reviewed-by: jjg
This commit is contained in:
Kumar Srinivasan 2017-04-12 11:42:50 -07:00
parent 849cae8710
commit bd727dd23f
5 changed files with 367 additions and 29 deletions

View file

@ -409,7 +409,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
* @param section set of elements * @param section set of elements
* @return true if there are elements to be displayed * @return true if there are elements to be displayed
*/ */
public boolean display(SortedSet<? extends Element> section) { public boolean display(Set<? extends Element> section) {
return section != null && !section.isEmpty(); return section != null && !section.isEmpty();
} }
@ -423,6 +423,25 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
return section != null && !section.isEmpty(); return section != null && !section.isEmpty();
} }
/*
* Returns true, in API mode, if at least one type element in
* the typeElements set is referenced by a javadoc tag in tagsMap.
*/
private boolean displayServices(Set<TypeElement> typeElements,
Map<TypeElement, Content> tagsMap) {
return typeElements != null &&
typeElements.stream().anyMatch((v) -> displayServiceDirective(v, tagsMap));
}
/*
* Returns true, in API mode, if the type element is referenced
* from a javadoc tag in tagsMap.
*/
private boolean displayServiceDirective(TypeElement typeElement,
Map<TypeElement, Content> tagsMap) {
return moduleMode == ModuleMode.ALL || tagsMap.containsKey(typeElement);
}
/** /**
* Add the summary header. * Add the summary header.
* *
@ -768,14 +787,18 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
* {@inheritDoc} * {@inheritDoc}
*/ */
public void addServicesSummary(Content summaryContentTree) { public void addServicesSummary(Content summaryContentTree) {
if (display(uses) || display(provides)) {
boolean haveUses = displayServices(uses, usesTrees);
boolean haveProvides = displayServices(provides.keySet(), providesTrees);
if (haveProvides || haveUses) {
HtmlTree li = new HtmlTree(HtmlTag.LI); HtmlTree li = new HtmlTree(HtmlTag.LI);
li.addStyle(HtmlStyle.blockList); li.addStyle(HtmlStyle.blockList);
addSummaryHeader(HtmlConstants.START_OF_SERVICES_SUMMARY, SectionName.SERVICES, addSummaryHeader(HtmlConstants.START_OF_SERVICES_SUMMARY, SectionName.SERVICES,
contents.navServices, li); contents.navServices, li);
String text; String text;
String tableSummary; String tableSummary;
if (display(provides)) { if (haveProvides) {
text = configuration.getText("doclet.Provides_Summary"); text = configuration.getText("doclet.Provides_Summary");
tableSummary = configuration.getText("doclet.Member_Table_Summary", tableSummary = configuration.getText("doclet.Member_Table_Summary",
configuration.getText("doclet.Provides_Summary"), configuration.getText("doclet.Provides_Summary"),
@ -788,7 +811,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
li.addContent(table); li.addContent(table);
} }
} }
if (display(uses)) { if (haveUses){
text = configuration.getText("doclet.Uses_Summary"); text = configuration.getText("doclet.Uses_Summary");
tableSummary = configuration.getText("doclet.Member_Table_Summary", tableSummary = configuration.getText("doclet.Member_Table_Summary",
configuration.getText("doclet.Uses_Summary"), configuration.getText("doclet.Uses_Summary"),
@ -818,11 +841,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
HtmlTree tdSummary; HtmlTree tdSummary;
Content description; Content description;
for (TypeElement t : uses) { for (TypeElement t : uses) {
// For each uses directive in the module declaration, if we are in the "api" mode and if (!displayServiceDirective(t, usesTrees)) {
// if there are service types listed using @uses javadoc tag, check if the service type in
// the uses directive is specified using the @uses tag. If not, we do not display the
// service type in the "api" mode.
if (moduleMode == ModuleMode.API && display(usesTrees) && !usesTrees.containsKey(t)) {
continue; continue;
} }
typeLinkContent = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, t)); typeLinkContent = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.PACKAGE, t));
@ -851,16 +870,11 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
*/ */
public void addProvidesList(Content tbody) { public void addProvidesList(Content tbody) {
boolean altColor = true; boolean altColor = true;
TypeElement srv;
SortedSet<TypeElement> implSet; SortedSet<TypeElement> implSet;
Content description; Content description;
for (Map.Entry<TypeElement, SortedSet<TypeElement>> entry : provides.entrySet()) { for (Map.Entry<TypeElement, SortedSet<TypeElement>> entry : provides.entrySet()) {
srv = entry.getKey(); TypeElement srv = entry.getKey();
// For each provides directive in the module declaration, if we are in the "api" mode and if (!displayServiceDirective(srv, providesTrees)) {
// if there are service types listed using @provides javadoc tag, check if the service type in
// the provides directive is specified using the @provides tag. If not, we do not display the
// service type in the "api" mode.
if (moduleMode == ModuleMode.API && display(providesTrees) && !providesTrees.containsKey(srv)) {
continue; continue;
} }
implSet = entry.getValue(); implSet = entry.getValue();

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -46,6 +46,7 @@ import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
/** /**
@ -237,12 +238,23 @@ public abstract class JavadocTester {
* @throws Exception if any errors occurred * @throws Exception if any errors occurred
*/ */
public void runTests() throws Exception { public void runTests() throws Exception {
runTests(m -> new Object[0]);
}
/**
* Run all methods annotated with @Test, followed by printSummary.
* Typically called on a tester object in main()
* @param f a function which will be used to provide arguments to each
* invoked method
* @throws Exception if any errors occurred
*/
public void runTests(Function<Method, Object[]> f) throws Exception {
for (Method m: getClass().getDeclaredMethods()) { for (Method m: getClass().getDeclaredMethods()) {
Annotation a = m.getAnnotation(Test.class); Annotation a = m.getAnnotation(Test.class);
if (a != null) { if (a != null) {
try { try {
out.println("Running test " + m.getName()); out.println("Running test " + m.getName());
m.invoke(this, new Object[] { }); m.invoke(this, f.apply(m));
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
Throwable cause = e.getCause(); Throwable cause = e.getCause();
throw (cause instanceof Exception) ? ((Exception) cause) : e; throw (cause instanceof Exception) ? ((Exception) cause) : e;

View file

@ -0,0 +1,314 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8176901
* @summary tests the module's services, such as provides and uses
* @modules jdk.javadoc/jdk.javadoc.internal.api
* jdk.javadoc/jdk.javadoc.internal.tool
* jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* @library ../lib /tools/lib
* @build toolbox.ToolBox toolbox.ModuleBuilder JavadocTester
* @run main TestModuleServices
*/
import java.nio.file.Path;
import java.nio.file.Paths;
import toolbox.*;
public class TestModuleServices extends JavadocTester {
public final ToolBox tb;
public static void main(String... args) throws Exception {
TestModuleServices tester = new TestModuleServices();
tester.runTests(m -> new Object[] { Paths.get(m.getName()) });
}
public TestModuleServices() {
tb = new ToolBox();
}
@Test
public void checkUsesNoApiTagModuleModeDefault(Path base) throws Exception {
ModuleBuilder mb = new ModuleBuilder(tb, "m")
.comment("module m.\n@provides p1.A abc") // bogus tag
.uses("p1.A")
.uses("p1.B")
.exports("p1")
.classes("package p1; public class A {}")
.classes("package p1; public class B {}");
mb.write(base);
javadoc("-d", base.toString() + "/out",
"-quiet",
"--module-source-path", base.toString(),
"--module", "m");
checkExit(Exit.OK);
checkOutput("m-summary.html", false,
"<h3>Services</h3>");
}
@Test
public void checkUsesNoApiTagModuleModeAll(Path base) throws Exception {
ModuleBuilder mb = new ModuleBuilder(tb, "m")
.uses("p1.A")
.uses("p1.B")
.exports("p1")
.classes("package p1; public class A {}")
.classes("package p1; public class B {}");
mb.write(base);
javadoc("-d", base.toString() + "/out",
"-quiet",
"--show-module-contents", "all",
"--module-source-path", base.toString(),
"--module", "m");
checkExit(Exit.OK);
checkOutput("m-summary.html", true,
"<h3>Services</h3>");
checkOutput("m-summary.html", true,
"<table class=\"usesSummary\" summary=\"Uses table, listing types, and an explanation\">\n" +
"<caption><span>Uses</span><span class=\"tabEnd\">&nbsp;</span></caption>\n" +
"<tr>\n" +
"<th class=\"colFirst\" scope=\"col\">Type</th>\n" +
"<th class=\"colLast\" scope=\"col\">Description</th>\n" +
"</tr>\n" +
"<tbody>\n" +
"<tr class=\"altColor\">\n" +
"<th class=\"colFirst\" scope=\"row\"><a href=\"p1/A.html\" title=\"class in p1\">A</a></th>\n" +
"<td class=\"colLast\">&nbsp;</td>\n" +
"</tr>\n" +
"<tr class=\"rowColor\">\n" +
"<th class=\"colFirst\" scope=\"row\"><a href=\"p1/B.html\" title=\"class in p1\">B</a></th>\n" +
"<td class=\"colLast\">&nbsp;</td>\n" +
"</tr>\n" +
"</tbody>\n" +
"</table>\n");
}
@Test
public void checkUsesWithApiTagModuleModeDefault(Path base) throws Exception {
ModuleBuilder mb = new ModuleBuilder(tb, "m")
.comment("module m.\n@uses p1.A")
.uses("p1.A")
.uses("p1.B")
.exports("p1")
.classes("package p1; public class A {}")
.classes("package p1; public class B {}");
mb.write(base);
javadoc("-d", base.toString() + "/out",
"-quiet",
"--module-source-path", base.toString(),
"--module", "m");
checkExit(Exit.OK);
checkOutput("m-summary.html", true,
"<h3>Services</h3>");
checkOutput("m-summary.html", true,
"<table class=\"usesSummary\" summary=\"Uses table, listing types, and an explanation\">\n" +
"<caption><span>Uses</span><span class=\"tabEnd\">&nbsp;</span></caption>\n" +
"<tr>\n" +
"<th class=\"colFirst\" scope=\"col\">Type</th>\n" +
"<th class=\"colLast\" scope=\"col\">Description</th>\n" +
"</tr>\n" +
"<tbody>\n" +
"<tr class=\"altColor\">\n" +
"<th class=\"colFirst\" scope=\"row\"><a href=\"p1/A.html\" title=\"class in p1\">A</a></th>\n" +
"<td class=\"colLast\">&nbsp;</td>\n" +
"</tr>\n" +
"</tbody>\n" +
"</table>\n");
}
@Test
public void checkProvidesNoApiTagModuleModeDefault(Path base) throws Exception {
ModuleBuilder mb = new ModuleBuilder(tb, "m")
.comment("module m.\n@uses p1.A")
.provides("p1.A", "p1.B")
.exports("p1")
.classes("package p1; public interface A {}")
.classes("package p1; public class B implements A {}")
.provides("p2.A", "p2.B")
.exports("p2")
.classes("package p2; public interface A {}")
.classes("package p2; public class B implements A {}");
mb.write(base);
javadoc("-d", base.toString() + "/out",
"-quiet",
"--module-source-path", base.toString(),
"--module", "m");
checkExit(Exit.OK);
checkOutput("m-summary.html", false,
"<h3>Services</h3>");
}
@Test
public void checkProvidesNoApiTagModuleModeAll(Path base) throws Exception {
ModuleBuilder mb = new ModuleBuilder(tb, "m")
.comment("module m.\n@uses p1.A") // bogus uses tag
.provides("p1.A", "p1.B")
.exports("p1")
.classes("package p1; public interface A {}")
.classes("package p1; public class B implements A {}")
.provides("p2.A", "p2.B")
.exports("p2")
.classes("package p2; public interface A {}")
.classes("package p2; public class B implements A {}");
mb.write(base);
javadoc("-d", base.toString() + "/out",
"-quiet",
"--show-module-contents", "all",
"--module-source-path", base.toString(),
"--module", "m");
checkExit(Exit.OK);
checkOutput("m-summary.html", true,
"<h3>Services</h3>");
checkOutput("m-summary.html", true,
"<table class=\"providesSummary\" summary=\"Provides table, listing types, and an explanation\">\n" +
"<caption><span>Provides</span><span class=\"tabEnd\">&nbsp;</span></caption>\n" +
"<tr>\n" +
"<th class=\"colFirst\" scope=\"col\">Type</th>\n" +
"<th class=\"colLast\" scope=\"col\">Description</th>\n" +
"</tr>\n" +
"<tbody>\n" +
"<tr class=\"altColor\">\n" +
"<th class=\"colFirst\" scope=\"row\"><a href=\"p1/A.html\" title=\"interface in p1\">A</a></th>\n" +
"<td class=\"colLast\">&nbsp;<br>(<span class=\"implementationLabel\">Implementation(s):</span>&nbsp;<a href=\"p1/B.html\" title=\"class in p1\">B</a>)</td>\n" +
"</tr>\n" +
"<tr class=\"rowColor\">\n" +
"<th class=\"colFirst\" scope=\"row\"><a href=\"p2/A.html\" title=\"interface in p2\">A</a></th>\n" +
"<td class=\"colLast\">&nbsp;<br>(<span class=\"implementationLabel\">Implementation(s):</span>&nbsp;<a href=\"p2/B.html\" title=\"class in p2\">B</a>)</td>\n" +
"</tr>\n" +
"</tbody>\n");
}
@Test
public void checkProvidesWithApiTagModuleModeDefault(Path base) throws Exception {
ModuleBuilder mb = new ModuleBuilder(tb, "m")
.comment("module m.\n@provides p1.A abc")
.provides("p1.A", "p1.B")
.exports("p1")
.classes("package p1; public interface A {}")
.classes("package p1; public class B implements A {}")
.provides("p2.A", "p2.B")
.exports("p2")
.classes("package p2; public interface A {}")
.classes("package p2; public class B implements A {}");
mb.write(base);
javadoc("-d", base.toString() + "/out",
"-quiet",
"--module-source-path", base.toString(),
"--module", "m");
checkExit(Exit.OK);
checkOutput("m-summary.html", true,
"<h3>Services</h3>");
checkOutput("m-summary.html", true,
"<table class=\"providesSummary\" summary=\"Provides table, listing types, and an explanation\">\n" +
"<caption><span>Provides</span><span class=\"tabEnd\">&nbsp;</span></caption>\n" +
"<tr>\n" +
"<th class=\"colFirst\" scope=\"col\">Type</th>\n" +
"<th class=\"colLast\" scope=\"col\">Description</th>\n" +
"</tr>\n" +
"<tbody>\n" +
"<tr class=\"altColor\">\n" +
"<th class=\"colFirst\" scope=\"row\"><a href=\"p1/A.html\" title=\"interface in p1\">A</a></th>\n" +
"<td class=\"colLast\">abc&nbsp;</td>\n" +
"</tr>\n" +
"</tbody>\n" +
"</table>\n");
}
@Test
public void checkUsesProvidesWithApiTagsModeDefault(Path base) throws Exception {
ModuleBuilder mb = new ModuleBuilder(tb, "m")
.comment("module m.\n@provides p1.A abc\n@uses p2.B def")
.provides("p1.A", "p1.B")
.exports("p1")
.classes("package p1; public interface A {}")
.classes("package p1; public class B implements A {}")
.provides("p2.A", "p2.B")
.uses("p2.B")
.exports("p2")
.classes("package p2; public interface A {}")
.classes("package p2; public class B implements A {}");
mb.write(base);
javadoc("-d", base.toString() + "/out",
"-quiet",
"--module-source-path", base.toString(),
"--module", "m");
checkExit(Exit.OK);
checkOutput("m-summary.html", true,
"<h3>Services</h3>");
checkOutput("m-summary.html", true,
"<table class=\"providesSummary\" summary=\"Provides table, listing types, and an explanation\">\n" +
"<caption><span>Provides</span><span class=\"tabEnd\">&nbsp;</span></caption>\n" +
"<tr>\n" +
"<th class=\"colFirst\" scope=\"col\">Type</th>\n" +
"<th class=\"colLast\" scope=\"col\">Description</th>\n" +
"</tr>\n" +
"<tbody>\n" +
"<tr class=\"altColor\">\n" +
"<th class=\"colFirst\" scope=\"row\"><a href=\"p1/A.html\" title=\"interface in p1\">A</a></th>\n" +
"<td class=\"colLast\">abc&nbsp;</td>\n" +
"</tr>\n" +
"</tbody>\n" +
"</table>",
"<table class=\"usesSummary\" summary=\"Uses table, listing types, and an explanation\">\n" +
"<caption><span>Uses</span><span class=\"tabEnd\">&nbsp;</span></caption>\n" +
"<tr>\n" +
"<th class=\"colFirst\" scope=\"col\">Type</th>\n" +
"<th class=\"colLast\" scope=\"col\">Description</th>\n" +
"</tr>\n" +
"<tbody>\n" +
"<tr class=\"altColor\">\n" +
"<th class=\"colFirst\" scope=\"row\"><a href=\"p2/B.html\" title=\"class in p2\">B</a></th>\n" +
"<td class=\"colLast\">def&nbsp;</td>\n" +
"</tr>\n" +
"</tbody>\n" +
"</table>\n");
}
}

View file

@ -591,10 +591,6 @@ public class TestModules extends JavadocTester {
+ "<th class=\"colFirst\" scope=\"row\"><a href=\"testpkgmdlB/TestClassInModuleB.html\" title=\"class in testpkgmdlB\">TestClassInModuleB</a></th>\n" + "<th class=\"colFirst\" scope=\"row\"><a href=\"testpkgmdlB/TestClassInModuleB.html\" title=\"class in testpkgmdlB\">TestClassInModuleB</a></th>\n"
+ "<td class=\"colLast\">With a test description for uses.&nbsp;</td>\n" + "<td class=\"colLast\">With a test description for uses.&nbsp;</td>\n"
+ "</tr>", + "</tr>",
"<tr class=\"altColor\">\n"
+ "<th class=\"colFirst\" scope=\"row\"><a href=\"testpkg2mdlB/TestInterface2InModuleB.html\" title=\"interface in testpkg2mdlB\">TestInterface2InModuleB</a></th>\n"
+ "<td class=\"colLast\">&nbsp;</td>\n"
+ "</tr>",
"<caption><span>Opens</span><span class=\"tabEnd\">&nbsp;</span></caption>\n" "<caption><span>Opens</span><span class=\"tabEnd\">&nbsp;</span></caption>\n"
+ "<tr>\n" + "<tr>\n"
+ "<th class=\"colFirst\" scope=\"col\">Package</th>\n" + "<th class=\"colFirst\" scope=\"col\">Package</th>\n"

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -247,7 +247,9 @@ public class ModuleBuilder {
List<String> sources = new ArrayList<>(); List<String> sources = new ArrayList<>();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (!comment.isEmpty()) { if (!comment.isEmpty()) {
sb.append("/**\n").append(comment.replace("\n", " *")).append(" */\n"); sb.append("/**\n * ")
.append(comment.replace("\n", "\n * "))
.append("\n */\n");
} }
sb.append("module ").append(name).append(" {\n"); sb.append("module ").append(name).append(" {\n");
requires.forEach(r -> sb.append(" " + r + "\n")); requires.forEach(r -> sb.append(" " + r + "\n"));