Skip to content

Commit 7e57531

Browse files
author
duke
committedJun 9, 2020
Automatic merge of jdk:master into master
2 parents b0a95a3 + ac2828d commit 7e57531

File tree

9 files changed

+649
-123
lines changed

9 files changed

+649
-123
lines changed
 

‎src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java

+40-13
Original file line numberDiff line numberDiff line change
@@ -464,31 +464,50 @@ public java.util.List<DocTree> getFirstSentence(java.util.List<? extends DocTree
464464
private Symbol attributeDocReference(TreePath path, DCReference ref) {
465465
Env<AttrContext> env = getAttrContext(path);
466466
if (env == null) return null;
467-
467+
if (ref.moduleName != null && ref.qualifierExpression == null && ref.memberName != null) {
468+
// module name and member name without type
469+
return null;
470+
}
468471
Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
469472
new Log.DeferredDiagnosticHandler(log);
470473
try {
471474
final TypeSymbol tsym;
472475
final Name memberName;
476+
final ModuleSymbol mdlsym;
477+
478+
if (ref.moduleName != null) {
479+
mdlsym = modules.modulesInitialized() ?
480+
modules.getObservableModule(names.fromString(ref.moduleName.toString()))
481+
: null;
482+
if (mdlsym == null) {
483+
return null;
484+
} else if (ref.qualifierExpression == null) {
485+
return mdlsym;
486+
}
487+
} else {
488+
mdlsym = modules.getDefaultModule();
489+
}
490+
473491
if (ref.qualifierExpression == null) {
474492
tsym = env.enclClass.sym;
475493
memberName = (Name) ref.memberName;
476494
} else {
477-
// newSeeTree if the qualifierExpression is a type or package name.
478-
// javac does not provide the exact method required, so
479-
// we first check if qualifierExpression identifies a type,
480-
// and if not, then we check to see if it identifies a package.
481-
Type t = attr.attribType(ref.qualifierExpression, env);
482-
if (t.isErroneous()) {
495+
// Check if qualifierExpression is a type or package, using the methods javac provides.
496+
// If no module name is given we check if qualifierExpression identifies a type.
497+
// If that fails or we have a module name, use that to resolve qualifierExpression to
498+
// a package or type.
499+
Type t = ref.moduleName == null ? attr.attribType(ref.qualifierExpression, env) : null;
500+
501+
if (t == null || t.isErroneous()) {
483502
JCCompilationUnit toplevel =
484503
treeMaker.TopLevel(List.nil());
485-
final ModuleSymbol msym = modules.getDefaultModule();
486-
toplevel.modle = msym;
487-
toplevel.packge = msym.unnamedPackage;
504+
toplevel.modle = mdlsym;
505+
toplevel.packge = mdlsym.unnamedPackage;
488506
Symbol sym = attr.attribIdent(ref.qualifierExpression, toplevel);
489507

490-
if (sym == null)
508+
if (sym == null) {
491509
return null;
510+
}
492511

493512
sym.complete();
494513

@@ -500,7 +519,15 @@ private Symbol attributeDocReference(TreePath path, DCReference ref) {
500519
return null;
501520
}
502521
} else {
503-
if (ref.qualifierExpression.hasTag(JCTree.Tag.IDENT)) {
522+
if (modules.modulesInitialized() && ref.moduleName == null && ref.memberName == null) {
523+
// package/type does not exist, check if there is a matching module
524+
ModuleSymbol moduleSymbol = modules.getObservableModule(names.fromString(ref.signature));
525+
if (moduleSymbol != null) {
526+
return moduleSymbol;
527+
}
528+
}
529+
if (ref.qualifierExpression.hasTag(JCTree.Tag.IDENT) && ref.moduleName == null
530+
&& ref.memberName == null) {
504531
// fixup: allow "identifier" instead of "#identifier"
505532
// for compatibility with javadoc
506533
tsym = env.enclClass.sym;
@@ -513,7 +540,7 @@ private Symbol attributeDocReference(TreePath path, DCReference ref) {
513540
Type e = t;
514541
// If this is an array type convert to element type
515542
while (e instanceof ArrayType)
516-
e = ((ArrayType)e).elemtype;
543+
e = ((ArrayType) e).elemtype;
517544
tsym = e.tsym;
518545
memberName = (Name) ref.memberName;
519546
}

‎src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java

+8-82
Original file line numberDiff line numberDiff line change
@@ -428,9 +428,9 @@ private DCTree inlineText(WhitespaceRetentionPolicy whitespacePolicy) throws Par
428428
* Matching pairs of {@literal < >} are skipped. The text is terminated by the first
429429
* unmatched }. It is an error if the beginning of the next tag is detected.
430430
*/
431+
// TODO: allowMember is currently ignored
431432
// TODO: boolean allowMember should be enum FORBID, ALLOW, REQUIRE
432433
// TODO: improve quality of parse to forbid bad constructions.
433-
// TODO: update to use ReferenceParser
434434
@SuppressWarnings("fallthrough")
435435
protected DCReference reference(boolean allowMember) throws ParseException {
436436
int pos = bp;
@@ -485,91 +485,17 @@ protected DCReference reference(boolean allowMember) throws ParseException {
485485

486486
String sig = newString(pos, bp);
487487

488-
// Break sig apart into qualifiedExpr member paramTypes.
489-
JCTree qualExpr;
490-
Name member;
491-
List<JCTree> paramTypes;
492-
493-
Log.DeferredDiagnosticHandler deferredDiagnosticHandler
494-
= new Log.DeferredDiagnosticHandler(fac.log);
495488

496489
try {
497-
int hash = sig.indexOf("#");
498-
int lparen = sig.indexOf("(", hash + 1);
499-
if (hash == -1) {
500-
if (lparen == -1) {
501-
qualExpr = parseType(sig);
502-
member = null;
503-
} else {
504-
qualExpr = null;
505-
member = parseMember(sig.substring(0, lparen));
506-
}
507-
} else {
508-
qualExpr = (hash == 0) ? null : parseType(sig.substring(0, hash));
509-
if (lparen == -1)
510-
member = parseMember(sig.substring(hash + 1));
511-
else
512-
member = parseMember(sig.substring(hash + 1, lparen));
513-
}
514-
515-
if (lparen < 0) {
516-
paramTypes = null;
517-
} else {
518-
int rparen = sig.indexOf(")", lparen);
519-
if (rparen != sig.length() - 1)
520-
throw new ParseException("dc.ref.bad.parens");
521-
paramTypes = parseParams(sig.substring(lparen + 1, rparen));
522-
}
523-
524-
if (!deferredDiagnosticHandler.getDiagnostics().isEmpty())
525-
throw new ParseException("dc.ref.syntax.error");
526-
527-
} finally {
528-
fac.log.popDiagnosticHandler(deferredDiagnosticHandler);
529-
}
530-
531-
return m.at(pos).newReferenceTree(sig, qualExpr, member, paramTypes).setEndPos(bp);
532-
}
533-
534-
JCTree parseType(String s) throws ParseException {
535-
JavacParser p = fac.newParser(s, false, false, false);
536-
JCTree tree = p.parseType();
537-
if (p.token().kind != TokenKind.EOF)
538-
throw new ParseException("dc.ref.unexpected.input");
539-
return tree;
540-
}
541-
542-
Name parseMember(String s) throws ParseException {
543-
JavacParser p = fac.newParser(s, false, false, false);
544-
Name name = p.ident();
545-
if (p.token().kind != TokenKind.EOF)
546-
throw new ParseException("dc.ref.unexpected.input");
547-
return name;
548-
}
549-
550-
List<JCTree> parseParams(String s) throws ParseException {
551-
if (s.trim().isEmpty())
552-
return List.nil();
553-
554-
JavacParser p = fac.newParser(s.replace("...", "[]"), false, false, false);
555-
ListBuffer<JCTree> paramTypes = new ListBuffer<>();
556-
paramTypes.add(p.parseType());
557-
558-
if (p.token().kind == TokenKind.IDENTIFIER)
559-
p.nextToken();
560-
561-
while (p.token().kind == TokenKind.COMMA) {
562-
p.nextToken();
563-
paramTypes.add(p.parseType());
564-
565-
if (p.token().kind == TokenKind.IDENTIFIER)
566-
p.nextToken();
490+
ReferenceParser.Reference ref = new ReferenceParser(fac).parse(sig);
491+
return m.at(pos).newReferenceTree(sig,
492+
ref.moduleName, ref.qualExpr,
493+
ref.member, ref.paramTypes)
494+
.setEndPos(bp);
495+
} catch (ReferenceParser.ParseException parseException) {
496+
throw new ParseException(parseException.getMessage());
567497
}
568498

569-
if (p.token().kind != TokenKind.EOF)
570-
throw new ParseException("dc.ref.unexpected.input");
571-
572-
return paramTypes.toList();
573499
}
574500

575501
/**

‎src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ReferenceParser.java

+29-9
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ public class ReferenceParser {
4747
* Any, but not all, of the member fields may be null.
4848
*/
4949
static public class Reference {
50+
public final JCTree.JCExpression moduleName;
5051
/** The type, if any, in the signature. */
5152
public final JCTree qualExpr;
5253
/** The member name, if any, in the signature. */
5354
public final Name member;
5455
/** The parameter types, if any, in the signature. */
5556
public final List<JCTree> paramTypes;
5657

57-
Reference(JCTree qualExpr, Name member, List<JCTree> paramTypes) {
58+
Reference(JCTree.JCExpression moduleName, JCTree qualExpr, Name member, List<JCTree> paramTypes) {
59+
this.moduleName = moduleName;
5860
this.qualExpr = qualExpr;
5961
this.member = member;
6062
this.paramTypes = paramTypes;
@@ -89,7 +91,8 @@ public ReferenceParser(ParserFactory fac) {
8991
*/
9092
public Reference parse(String sig) throws ParseException {
9193

92-
// Break sig apart into qualifiedExpr member paramTypes.
94+
// Break sig apart into moduleName qualifiedExpr member paramTypes.
95+
JCTree.JCExpression moduleName;
9396
JCTree qualExpr;
9497
Name member;
9598
List<JCTree> paramTypes;
@@ -98,18 +101,27 @@ public Reference parse(String sig) throws ParseException {
98101
= new Log.DeferredDiagnosticHandler(fac.log);
99102

100103
try {
101-
int hash = sig.indexOf("#");
102-
int lparen = sig.indexOf("(", hash + 1);
103-
if (hash == -1) {
104+
int slash = sig.indexOf("/");
105+
int hash = sig.indexOf("#", slash + 1);
106+
int lparen = sig.indexOf("(", Math.max(slash, hash) + 1);
107+
if (slash > -1) {
108+
moduleName = parseModule(sig.substring(0, slash));
109+
} else {
110+
moduleName = null;
111+
}
112+
if (slash > 0 && sig.length() == slash + 1) {
113+
qualExpr = null;
114+
member = null;
115+
} else if (hash == -1) {
104116
if (lparen == -1) {
105-
qualExpr = parseType(sig);
117+
qualExpr = parseType(sig.substring(slash + 1));
106118
member = null;
107119
} else {
108120
qualExpr = null;
109-
member = parseMember(sig.substring(0, lparen));
121+
member = parseMember(sig.substring(slash + 1, lparen));
110122
}
111123
} else {
112-
qualExpr = (hash == 0) ? null : parseType(sig.substring(0, hash));
124+
qualExpr = (hash == slash + 1) ? null : parseType(sig.substring(slash + 1, hash));
113125
if (lparen == -1)
114126
member = parseMember(sig.substring(hash + 1));
115127
else
@@ -132,7 +144,15 @@ public Reference parse(String sig) throws ParseException {
132144
fac.log.popDiagnosticHandler(deferredDiagnosticHandler);
133145
}
134146

135-
return new Reference(qualExpr, member, paramTypes);
147+
return new Reference(moduleName, qualExpr, member, paramTypes);
148+
}
149+
150+
private JCTree.JCExpression parseModule(String s) throws ParseException {
151+
JavacParser p = fac.newParser(s, false, false, false);
152+
JCTree.JCExpression expr = p.qualident(false);
153+
if (p.token().kind != TokenKind.EOF)
154+
throw new ParseException("dc.ref.unexpected.input");
155+
return expr;
136156
}
137157

138158
private JCTree parseType(String s) throws ParseException {

‎src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -647,13 +647,15 @@ public static class DCReference extends DCEndPosTree<DCReference> implements Ref
647647

648648
// The following are not directly exposed through ReferenceTree
649649
// use DocTrees.getElement(DocTreePath)
650+
public final JCTree.JCExpression moduleName;
650651
public final JCTree qualifierExpression;
651652
public final Name memberName;
652653
public final List<JCTree> paramTypes;
653654

654655

655-
DCReference(String signature, JCTree qualExpr, Name member, List<JCTree> paramTypes) {
656+
DCReference(String signature, JCTree.JCExpression moduleName, JCTree qualExpr, Name member, List<JCTree> paramTypes) {
656657
this.signature = signature;
658+
this.moduleName = moduleName;
657659
qualifierExpression = qualExpr;
658660
memberName = member;
659661
this.paramTypes = paramTypes;

‎src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -378,16 +378,16 @@ public DCProvides newProvidesTree(ReferenceTree name, List<? extends DocTree> de
378378
public DCReference newReferenceTree(String signature) {
379379
try {
380380
ReferenceParser.Reference ref = referenceParser.parse(signature);
381-
DCReference tree = new DCReference(signature, ref.qualExpr, ref.member, ref.paramTypes);
381+
DCReference tree = new DCReference(signature, ref.moduleName, ref.qualExpr, ref.member, ref.paramTypes);
382382
tree.pos = pos;
383383
return tree;
384384
} catch (ReferenceParser.ParseException e) {
385385
throw new IllegalArgumentException("invalid signature", e);
386386
}
387387
}
388388

389-
public DCReference newReferenceTree(String signature, JCTree qualExpr, Name member, List<JCTree> paramTypes) {
390-
DCReference tree = new DCReference(signature, qualExpr, member, paramTypes);
389+
public DCReference newReferenceTree(String signature, JCTree.JCExpression moduleName, JCTree qualExpr, Name member, List<JCTree> paramTypes) {
390+
DCReference tree = new DCReference(signature, moduleName, qualExpr, member, paramTypes);
391391
tree.pos = pos;
392392
return tree;
393393
}

‎src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java

+14-5
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,7 @@ public Content seeTagToContent(Element element, DocTree see) {
998998

999999
CommentHelper ch = utils.getCommentHelper(element);
10001000
String tagName = ch.getTagName(see);
1001-
String seetext = replaceDocRootDir(utils.normalizeNewlines(ch.getText(see)).toString());
1001+
String seetext = replaceDocRootDir(removeTrailingSlash(utils.normalizeNewlines(ch.getText(see)).toString()));
10021002
// Check if @see is an href or "string"
10031003
if (seetext.startsWith("<") || seetext.startsWith("\"")) {
10041004
return new RawHtml(seetext);
@@ -1010,14 +1010,17 @@ public Content seeTagToContent(Element element, DocTree see) {
10101010
Content text = plainOrCode(kind == LINK_PLAIN, new RawHtml(seetext));
10111011

10121012
TypeElement refClass = ch.getReferencedClass(see);
1013-
String refClassName = ch.getReferencedClassName(see);
10141013
Element refMem = ch.getReferencedMember(see);
10151014
String refMemName = ch.getReferencedMemberName(see);
10161015

10171016
if (refMemName == null && refMem != null) {
10181017
refMemName = refMem.toString();
10191018
}
10201019
if (refClass == null) {
1020+
ModuleElement refModule = ch.getReferencedModule(see);
1021+
if (refModule != null && utils.isIncluded(refModule)) {
1022+
return getModuleLink(refModule, label.isEmpty() ? text : label);
1023+
}
10211024
//@see is not referencing an included class
10221025
PackageElement refPackage = ch.getReferencedPackage(see);
10231026
if (refPackage != null && utils.isIncluded(refPackage)) {
@@ -1028,9 +1031,11 @@ public Content seeTagToContent(Element element, DocTree see) {
10281031
return getPackageLink(refPackage, label);
10291032
} else {
10301033
// @see is not referencing an included class, module or package. Check for cross links.
1031-
DocLink elementCrossLink = (configuration.extern.isModule(refClassName))
1032-
? getCrossModuleLink(utils.elementUtils.getModuleElement(refClassName)) :
1033-
(refPackage != null) ? getCrossPackageLink(refPackage) : null;
1034+
String refModuleName = ch.getReferencedModuleName(see);
1035+
DocLink elementCrossLink = (refPackage != null) ? getCrossPackageLink(refPackage) :
1036+
(configuration.extern.isModule(refModuleName))
1037+
? getCrossModuleLink(utils.elementUtils.getModuleElement(refModuleName))
1038+
: null;
10341039
if (elementCrossLink != null) {
10351040
// Element cross link found
10361041
return links.createLink(elementCrossLink,
@@ -1118,6 +1123,10 @@ public Content seeTagToContent(Element element, DocTree see) {
11181123
}
11191124
}
11201125

1126+
private String removeTrailingSlash(String s) {
1127+
return s.endsWith("/") ? s.substring(0, s.length() -1) : s;
1128+
}
1129+
11211130
private Content plainOrCode(boolean plain, Content body) {
11221131
return (plain || body.isEmpty()) ? body : HtmlTree.CODE(body);
11231132
}

‎src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java

+14-10
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import java.util.stream.Collectors;
3232

3333
import javax.lang.model.element.Element;
34-
import javax.lang.model.element.ExecutableElement;
34+
import javax.lang.model.element.ModuleElement;
3535
import javax.lang.model.element.PackageElement;
3636
import javax.lang.model.element.TypeElement;
3737
import javax.lang.model.type.TypeMirror;
@@ -376,23 +376,18 @@ public TypeElement getReferencedClass(DocTree dtree) {
376376
return null;
377377
} else if (utils.isTypeElement(e)) {
378378
return (TypeElement) e;
379-
} else if (!utils.isPackage(e)) {
379+
} else if (!utils.isPackage(e) && !utils.isModule(e)) {
380380
return utils.getEnclosingTypeElement(e);
381381
}
382382
return null;
383383
}
384384

385-
public String getReferencedClassName(DocTree dtree) {
386-
Utils utils = configuration.utils;
387-
Element e = getReferencedClass(dtree);
388-
if (e != null) {
389-
return utils.isTypeElement(e) ? utils.getSimpleName(e) : null;
390-
}
385+
public String getReferencedModuleName(DocTree dtree) {
391386
String s = getReferencedSignature(dtree);
392-
if (s == null) {
387+
if (s == null || s.contains("#") || s.contains("(")) {
393388
return null;
394389
}
395-
int n = s.indexOf("#");
390+
int n = s.indexOf("/");
396391
return (n == -1) ? s : s.substring(0, n);
397392
}
398393

@@ -423,6 +418,15 @@ public PackageElement getReferencedPackage(DocTree dtree) {
423418
return null;
424419
}
425420

421+
public ModuleElement getReferencedModule(DocTree dtree) {
422+
Element e = getReferencedElement(dtree);
423+
if (e != null && configuration.utils.isModule(e)) {
424+
return (ModuleElement) e;
425+
}
426+
return null;
427+
}
428+
429+
426430
public List<? extends DocTree> getFirstSentenceTrees(List<? extends DocTree> body) {
427431
return configuration.docEnv.getDocTrees().getFirstSentence(body);
428432
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8164408
27+
* @summary Add module support for see, link and linkplain javadoc tags
28+
* @library /tools/lib ../../lib
29+
* @modules
30+
* jdk.javadoc/jdk.javadoc.internal.tool
31+
* jdk.compiler/com.sun.tools.javac.api
32+
* jdk.compiler/com.sun.tools.javac.main
33+
* @build javadoc.tester.*
34+
* @run main TestLinkTagletWithModule
35+
*/
36+
37+
import java.nio.file.Path;
38+
import java.nio.file.Paths;
39+
40+
import builder.ClassBuilder;
41+
import builder.ClassBuilder.*;
42+
import toolbox.ModuleBuilder;
43+
import toolbox.ToolBox;
44+
45+
import javadoc.tester.JavadocTester;
46+
47+
public class TestLinkTagletWithModule extends JavadocTester {
48+
49+
final ToolBox tb;
50+
private final Path src;
51+
52+
public static void main(String... args) throws Exception {
53+
TestLinkTagletWithModule tester = new TestLinkTagletWithModule();
54+
tester.runTests(m -> new Object[]{Paths.get(m.getName())});
55+
}
56+
57+
TestLinkTagletWithModule() throws Exception {
58+
tb = new ToolBox();
59+
src = Paths.get("src");
60+
generateSources();
61+
}
62+
63+
@Test
64+
public void testLinkModuleInternal(Path base) throws Exception {
65+
Path out = base.resolve("out");
66+
67+
javadoc("-d", out.toString(),
68+
"--module-source-path", src.toString(),
69+
"--module", "m1,m2,m3",
70+
"m2/com.m2.lib");
71+
72+
checkExit(Exit.OK);
73+
checkOutput("m3/com/m3/app/App.html", true,
74+
"""
75+
<div class="block"><a href="../../../../m1/module-summary.html"><code>m1</code></a>
76+
<a href="../../../../m1/module-summary.html"><code>m1</code></a>
77+
<a href="../../../../m1/com/m1/lib/package-summary.html"><code>package link</code></a>
78+
<a href="../../../../m1/com/m1/lib/Lib.html" title="class in com.m1.lib"><code>Lib</code></a>
79+
<a href="../../../../m1/com/m1/lib/Lib.html#method(java.lang.String)"><code>Lib.method(java.lang.String)</code></a>
80+
<a href="../../../../m1/com/m1/lib/Lib.html#method(java.lang.String)"><code>Lib.method(String)</code></a>
81+
<a href="../../../../m2/module-summary.html">m2</a>
82+
<a href="../../../../m2/module-summary.html">m2</a>
83+
<a href="../../../../m2/com/m2/lib/package-summary.html">com.m2.lib</a>
84+
<a href="../../../../m2/com/m2/lib/Lib.html" title="class in com.m2.lib">Lib</a>
85+
<a href="../../../../m2/com/m2/lib/Lib.html#method(java.lang.String)">class link</a>
86+
<a href="../../../../m2/com/m2/lib/Lib.html#method(java.lang.String)">Lib.method(String)</a></div>
87+
""");
88+
}
89+
90+
@Test
91+
public void testLinkModuleExternal(Path base) throws Exception {
92+
Path out1 = base.resolve("out1"), out2 = base.resolve("out2");
93+
94+
javadoc("-d", out1.toString(),
95+
"--module-source-path", src.toString(),
96+
"--module", "m1,m2",
97+
"m2/com.m2.lib");
98+
javadoc("-d", out2.toString(),
99+
"--module-source-path", src.toString(),
100+
"--add-modules", "m2",
101+
"--module", "m3",
102+
"-link", "../" + out1.getFileName());
103+
104+
checkExit(Exit.OK);
105+
checkOutput("m3/com/m3/app/App.html", true,
106+
"""
107+
<div class="block"><a href="../../../../../out1/m1/module-summary.html" class="external-link"><code>m1</code></a>
108+
<a href="../../../../../out1/m1/module-summary.html" class="external-link"><code>m1</code></a>
109+
<a href="../../../../../out1/m1/com/m1/lib/package-summary.html" class="external-link"><code>package link</code></a>
110+
<a href="../../../../../out1/m1/com/m1/lib/Lib.html" title="class or interface in com.m1.lib"\
111+
class="external-link"><code>Lib</code></a>
112+
<a href="../../../../../out1/m1/com/m1/lib/Lib.html#method(java.lang.String)" title="class or\
113+
interface in com.m1.lib" class="external-link"><code>Lib.method(java.lang.String)</code></a>
114+
<a href="../../../../../out1/m1/com/m1/lib/Lib.html#method(java.lang.String)" title="class or\
115+
interface in com.m1.lib" class="external-link"><code>Lib.method(String)</code></a>
116+
<a href="../../../../../out1/m2/module-summary.html" class="external-link">m2</a>
117+
<a href="../../../../../out1/m2/module-summary.html" class="external-link">m2</a>
118+
<a href="../../../../../out1/m2/com/m2/lib/package-summary.html" class="external-link">m2/com.m2.lib</a>
119+
<a href="../../../../../out1/m2/com/m2/lib/Lib.html" title="class or interface in com.m2.lib" class="external-link">Lib</a>
120+
<a href="../../../../../out1/m2/com/m2/lib/Lib.html#method(java.lang.String)" title="class or\
121+
interface in com.m2.lib" class="external-link">class link</a>
122+
<a href="../../../../../out1/m2/com/m2/lib/Lib.html#method(java.lang.String)" title="class or\
123+
interface in com.m2.lib" class="external-link">Lib.method(String)</a></div>
124+
""");
125+
}
126+
127+
@Test
128+
public void testLinkModuleSameNameInternal(Path base) throws Exception {
129+
Path out = base.resolve("out");
130+
131+
javadoc("-d", out.toString(),
132+
"--module-source-path", src.toString(),
133+
"--module", "com.ex1,com.ex2");
134+
135+
checkExit(Exit.OK);
136+
checkOutput("com.ex2/com/ex2/B.html", true,
137+
"""
138+
<div class="block"><a href="../../../com.ex1/com/ex1/package-summary.html"><code>package link</code></a>
139+
<a href="../../../com.ex1/module-summary.html"><code>module link</code></a>
140+
<a href="../../../com.ex1/com/ex1/package-summary.html"><code>com.ex1</code></a>
141+
<a href="../../../com.ex1/com/ex1/A.html" title="class in com.ex1"><code>class link</code></a>
142+
<a href="../../../com.ex1/com/ex1/A.html#m()"><code>A.m()</code></a>
143+
<a href="../../../com.ex1/com/ex1/A.html#m()"><code>A.m()</code></a>
144+
<a href="package-summary.html"><code>com.ex2</code></a>
145+
<a href="../../module-summary.html"><code>com.ex2</code></a></div>
146+
""");
147+
}
148+
149+
@Test
150+
public void testLinkModuleSameNameExternal(Path base) throws Exception {
151+
Path out1 = base.resolve("out1"), out2 = base.resolve("out2");
152+
153+
javadoc("-d", out1.toString(),
154+
"--module-source-path", src.toString(),
155+
"--module", "com.ex1");
156+
javadoc("-d", out2.toString(),
157+
"--module-source-path", src.toString(),
158+
"--module", "com.ex2",
159+
"-link", "../" + out1.getFileName());
160+
161+
checkExit(Exit.OK);
162+
checkOutput("com.ex2/com/ex2/B.html", true,
163+
"""
164+
<div class="block"><a href="../../../../out1/com.ex1/com/ex1/package-summary.html" class="external-link"><code>package link</code></a>
165+
<a href="../../../../out1/com.ex1/module-summary.html" class="external-link"><code>module link</code></a>
166+
<a href="../../../../out1/com.ex1/com/ex1/package-summary.html" class="external-link"><code>com.ex1/com.ex1</code></a>
167+
<a href="../../../../out1/com.ex1/com/ex1/A.html" title="class or interface in com.ex1" class="external-link"><code>class link</code></a>
168+
<a href="../../../../out1/com.ex1/com/ex1/A.html#m()" title="class or interface in com.ex1" class="external-link"><code>A.m()</code></a>
169+
<a href="../../../../out1/com.ex1/com/ex1/A.html#m()" title="class or interface in com.ex1" class="external-link"><code>A.m()</code></a>
170+
<a href="package-summary.html"><code>com.ex2</code></a>
171+
<a href="../../module-summary.html"><code>com.ex2</code></a></div>
172+
""");
173+
}
174+
void generateSources() throws Exception {
175+
new ModuleBuilder(tb, "m1")
176+
.exports("com.m1.lib")
177+
.classes("""
178+
package com.m1.lib;
179+
public class Lib {
180+
public String method(String s) {
181+
return s;
182+
}
183+
}""")
184+
.write(src);
185+
new ModuleBuilder(tb, "m2")
186+
.classes("""
187+
package com.m2.lib;
188+
public class Lib {
189+
public String method(String s) {
190+
return s;
191+
}
192+
}""")
193+
.write(src);
194+
new ModuleBuilder(tb, "m3")
195+
.exports("com.m3.app")
196+
.requires("m1")
197+
.classes("""
198+
package com.m3.app;\s
199+
public class App{
200+
/**
201+
* {@link m1}
202+
* {@link m1/}
203+
* {@link m1/com.m1.lib package link}
204+
* {@link m1/com.m1.lib.Lib}
205+
* {@link m1/com.m1.lib.Lib#method}
206+
* {@link m1/com.m1.lib.Lib#method(String)}
207+
* {@linkplain m2}
208+
* {@linkplain m2/}
209+
* {@linkplain m2/com.m2.lib}
210+
* {@linkplain m2/com.m2.lib.Lib}
211+
* {@linkplain m2/com.m2.lib.Lib#method class link}
212+
* {@linkplain m2/com.m2.lib.Lib#method(String)}
213+
*/
214+
public App(){}
215+
}
216+
""")
217+
.write(src);
218+
219+
new ModuleBuilder(tb, "com.ex1")
220+
.exports("com.ex1")
221+
.classes("""
222+
package com.ex1;
223+
public class A{
224+
public void m() {}
225+
}""",
226+
"""
227+
package com.ex1;
228+
public class B {}""")
229+
.write(src);
230+
231+
new ModuleBuilder(tb, "com.ex2")
232+
.requires("com.ex1")
233+
.exports("com.ex2")
234+
.classes("""
235+
package com.ex2;\s
236+
import com.ex1.A;
237+
public class B{
238+
/**
239+
* {@link com.ex1 package link}
240+
* {@link com.ex1/ module link}
241+
* {@link com.ex1/com.ex1}
242+
* {@link com.ex1/com.ex1.A class link}
243+
* {@link com.ex1/com.ex1.A#m}
244+
* {@link com.ex1/com.ex1.A#m()}
245+
* {@link com.ex2}
246+
* {@link com.ex2/}
247+
*/
248+
public B(A obj){}
249+
}
250+
""")
251+
.write(src);
252+
253+
}
254+
255+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8164408
27+
* @summary Add module support for see, link and linkplain javadoc tags
28+
* @library /tools/lib ../../lib
29+
* @modules
30+
* jdk.javadoc/jdk.javadoc.internal.tool
31+
* jdk.compiler/com.sun.tools.javac.api
32+
* jdk.compiler/com.sun.tools.javac.main
33+
* @build javadoc.tester.*
34+
* @run main TestSeeTagWithModule
35+
*/
36+
37+
import java.nio.file.Path;
38+
import java.nio.file.Paths;
39+
40+
import builder.ClassBuilder;
41+
import builder.ClassBuilder.*;
42+
import toolbox.ModuleBuilder;
43+
import toolbox.ToolBox;
44+
45+
import javadoc.tester.JavadocTester;
46+
47+
public class TestSeeTagWithModule extends JavadocTester {
48+
49+
final ToolBox tb;
50+
private final Path src;
51+
52+
public static void main(String... args) throws Exception {
53+
TestSeeTagWithModule tester = new TestSeeTagWithModule();
54+
tester.runTests(m -> new Object[]{Paths.get(m.getName())});
55+
}
56+
57+
TestSeeTagWithModule() throws Exception {
58+
tb = new ToolBox();
59+
src = Paths.get("src");
60+
generateSources();
61+
}
62+
63+
@Test
64+
public void testSeeModuleInternal(Path base) throws Exception {
65+
Path out = base.resolve("out");
66+
67+
javadoc("-d", out.toString(),
68+
"--module-source-path", src.toString(),
69+
"--module", "m1,m2,m3",
70+
"m2/com.m2.lib");
71+
72+
checkExit(Exit.OK);
73+
checkOutput("m3/com/m3/app/App.html", true,
74+
"""
75+
<dt>See Also:</dt>
76+
<dd><a href="../../../../m1/module-summary.html"><code>m1</code></a>,\s
77+
<a href="../../../../m1/module-summary.html"><code>m1</code></a>,\s
78+
<a href="../../../../m1/com/m1/lib/package-summary.html"><code>com.m1.lib</code></a>,\s
79+
<a href="../../../../m1/com/m1/lib/Lib.html" title="class in com.m1.lib"><code>Lib</code></a>,\s
80+
<a href="../../../../m1/com/m1/lib/Lib.html#method(java.lang.String)"><code>Lib.method(java.lang.String)</code></a>,\s
81+
<a href="../../../../m1/com/m1/lib/Lib.html#method(java.lang.String)"><code>Lib.method(String)</code></a>,\s
82+
<a href="../../../../m2/module-summary.html"><code>m2</code></a>,\s
83+
<a href="../../../../m2/module-summary.html"><code>m2</code></a>,\s
84+
<a href="../../../../m2/com/m2/lib/package-summary.html"><code>com.m2.lib</code></a>,\s
85+
<a href="../../../../m2/com/m2/lib/Lib.html" title="class in com.m2.lib"><code>Lib</code></a>,\s
86+
<a href="../../../../m2/com/m2/lib/Lib.html#method(java.lang.String)"><code>Lib.method(java.lang.String)</code></a>,\s
87+
<a href="../../../../m2/com/m2/lib/Lib.html#method(java.lang.String)"><code>Lib.method(String)</code></a></dd>
88+
""");
89+
}
90+
91+
@Test
92+
public void testSeeModuleExternal(Path base) throws Exception {
93+
Path out1 = base.resolve("out1"), out2 = base.resolve("out2");
94+
95+
javadoc("-d", out1.toString(),
96+
"--module-source-path", src.toString(),
97+
"--module", "m1,m2",
98+
"m2/com.m2.lib");
99+
javadoc("-d", out2.toString(),
100+
"--module-source-path", src.toString(),
101+
"--add-modules", "m2",
102+
"--module", "m3",
103+
"-link", "../" + out1.getFileName());
104+
105+
checkExit(Exit.OK);
106+
checkOutput("m3/com/m3/app/App.html", true,
107+
"""
108+
<dt>See Also:</dt>
109+
<dd><a href="../../../../../out1/m1/module-summary.html" class="external-link"><code>m1</code></a>,\s
110+
<a href="../../../../../out1/m1/module-summary.html" class="external-link"><code>m1</code></a>,\s
111+
<a href="../../../../../out1/m1/com/m1/lib/package-summary.html" class="external-link"><code>m1/com.m1.lib</code></a>,\s
112+
<a href="../../../../../out1/m1/com/m1/lib/Lib.html" title="class or interface in com.m1.lib" class="external-link"><code>Lib</code></a>,\s
113+
<a href="../../../../../out1/m1/com/m1/lib/Lib.html#method(java.lang.String)" title="class or \
114+
interface in com.m1.lib" class="external-link"><code>Lib.method(java.lang.String)</code></a>,\s
115+
<a href="../../../../../out1/m1/com/m1/lib/Lib.html#method(java.lang.String)" title="class or \
116+
interface in com.m1.lib" class="external-link"><code>Lib.method(String)</code></a>,\s
117+
<a href="../../../../../out1/m2/module-summary.html" class="external-link"><code>m2</code></a>,\s
118+
<a href="../../../../../out1/m2/module-summary.html" class="external-link"><code>m2</code></a>,\s
119+
<a href="../../../../../out1/m2/com/m2/lib/package-summary.html" class="external-link"><code>m2/com.m2.lib</code></a>,\s
120+
<a href="../../../../../out1/m2/com/m2/lib/Lib.html" title="class or interface in com.m2.lib" class="external-link"><code>Lib</code></a>,\s
121+
<a href="../../../../../out1/m2/com/m2/lib/Lib.html#method(java.lang.String)" title="class or \
122+
interface in com.m2.lib" class="external-link"><code>Lib.method(java.lang.String)</code></a>,\s
123+
<a href="../../../../../out1/m2/com/m2/lib/Lib.html#method(java.lang.String)" title="class or \
124+
interface in com.m2.lib" class="external-link"><code>Lib.method(String)</code></a></dd>
125+
""");
126+
}
127+
128+
@Test
129+
public void testSeeModuleSameNameInternal(Path base) throws Exception {
130+
Path out = base.resolve("out");
131+
132+
javadoc("-d", out.toString(),
133+
"--module-source-path", src.toString(),
134+
"--module", "com.ex1,com.ex2");
135+
136+
checkExit(Exit.OK);
137+
checkOutput("com.ex2/com/ex2/B.html", true,
138+
"""
139+
<dt>See Also:</dt>
140+
<dd><a href="../../../com.ex1/com/ex1/package-summary.html"><code>com.ex1</code></a>,\s
141+
<a href="../../../com.ex1/module-summary.html"><code>com.ex1</code></a>,\s
142+
<a href="../../../com.ex1/com/ex1/package-summary.html"><code>com.ex1</code></a>,\s
143+
<a href="../../../com.ex1/com/ex1/A.html" title="class in com.ex1"><code>A</code></a>,\s
144+
<a href="../../../com.ex1/com/ex1/A.html#m()"><code>A.m()</code></a>,\s
145+
<a href="../../../com.ex1/com/ex1/A.html#m()"><code>A.m()</code></a>,\s
146+
<a href="package-summary.html"><code>com.ex2</code></a>,\s
147+
<a href="../../module-summary.html"><code>com.ex2</code></a></dd>
148+
""");
149+
}
150+
151+
@Test
152+
public void testSeeModuleSameNameExternal(Path base) throws Exception {
153+
Path out1 = base.resolve("out1"), out2 = base.resolve("out2");
154+
155+
javadoc("-d", out1.toString(),
156+
"--module-source-path", src.toString(),
157+
"--module", "com.ex1");
158+
javadoc("-d", out2.toString(),
159+
"--module-source-path", src.toString(),
160+
"--module", "com.ex2",
161+
"-link", "../" + out1.getFileName());
162+
163+
checkExit(Exit.OK);
164+
checkOutput("com.ex2/com/ex2/B.html", true,
165+
"""
166+
<dt>See Also:</dt>
167+
<dd><a href="../../../../out1/com.ex1/com/ex1/package-summary.html" class="external-link"><code>com.ex1</code></a>,\s
168+
<a href="../../../../out1/com.ex1/module-summary.html" class="external-link"><code>com.ex1</code></a>,\s
169+
<a href="../../../../out1/com.ex1/com/ex1/package-summary.html" class="external-link"><code>com.ex1/com.ex1</code></a>,\s
170+
<a href="../../../../out1/com.ex1/com/ex1/A.html" title="class or interface in com.ex1" class="external-link"><code>A</code></a>,\s
171+
<a href="../../../../out1/com.ex1/com/ex1/A.html#m()" title="class or interface in com.ex1" class="external-link"><code>A.m()</code></a>,\s
172+
<a href="../../../../out1/com.ex1/com/ex1/A.html#m()" title="class or interface in com.ex1" class="external-link"><code>A.m()</code></a>,\s
173+
<a href="package-summary.html"><code>com.ex2</code></a>,\s
174+
<a href="../../module-summary.html"><code>com.ex2</code></a></dd>
175+
""");
176+
}
177+
178+
@Test
179+
public void testMissingType(Path base) throws Exception {
180+
Path out = base.resolve("outMissingType");
181+
182+
javadoc("-d", out.toString(),
183+
"--module-source-path", src.toString(),
184+
"--module", "fail");
185+
186+
checkExit(Exit.ERROR);
187+
}
188+
189+
void generateSources() throws Exception {
190+
new ModuleBuilder(tb, "m1")
191+
.exports("com.m1.lib")
192+
.classes("""
193+
package com.m1.lib;
194+
public class Lib {
195+
public String method(String s) {
196+
return s;
197+
}
198+
}""")
199+
.write(src);
200+
new ModuleBuilder(tb, "m2")
201+
.classes("""
202+
package com.m2.lib;
203+
public class Lib {
204+
public String method(String s) {
205+
return s;
206+
}
207+
}""")
208+
.write(src);
209+
new ModuleBuilder(tb, "m3")
210+
.exports("com.m3.app")
211+
.requires("m1")
212+
.classes("""
213+
package com.m3.app;\s
214+
public class App{
215+
/**
216+
* @see m1
217+
* @see m1/
218+
* @see m1/com.m1.lib
219+
* @see m1/com.m1.lib.Lib
220+
* @see m1/com.m1.lib.Lib#method
221+
* @see m1/com.m1.lib.Lib#method(String)
222+
* @see m2
223+
* @see m2/
224+
* @see m2/com.m2.lib
225+
* @see m2/com.m2.lib.Lib
226+
* @see m2/com.m2.lib.Lib#method
227+
* @see m2/com.m2.lib.Lib#method(String)
228+
*/
229+
public App(){}
230+
}
231+
""")
232+
.write(src);
233+
234+
new ModuleBuilder(tb, "com.ex1")
235+
.exports("com.ex1")
236+
.classes("""
237+
package com.ex1;
238+
public class A{
239+
public void m() {}
240+
}""",
241+
"""
242+
package com.ex1;
243+
public class B {}""")
244+
.write(src);
245+
246+
new ModuleBuilder(tb, "com.ex2")
247+
.requires("com.ex1")
248+
.exports("com.ex2")
249+
.classes("""
250+
package com.ex2;\s
251+
import com.ex1.A;
252+
public class B{
253+
/**
254+
* @see com.ex1
255+
* @see com.ex1/
256+
* @see com.ex1/com.ex1
257+
* @see com.ex1/com.ex1.A
258+
* @see com.ex1/com.ex1.A#m
259+
* @see com.ex1/com.ex1.A#m()
260+
* @see com.ex2
261+
* @see com.ex2/
262+
*/
263+
public B(A obj){}
264+
}
265+
""")
266+
.write(src);
267+
268+
new ModuleBuilder(tb, "fail")
269+
.exports("pkg.fail")
270+
.classes("""
271+
package pkg.fail;
272+
/**
273+
* @see fail/#foo()
274+
*/
275+
public class F {
276+
public void foo() {}
277+
}
278+
""")
279+
.write(src);
280+
281+
}
282+
283+
}

0 commit comments

Comments
 (0)
Please sign in to comment.