8144287: Enhance DocTree API to support @index javadoc tags

Reviewed-by: jjg
This commit is contained in:
Kumar Srinivasan 2015-12-01 07:10:35 -08:00
parent 92c2d20bcc
commit 8630db94da
13 changed files with 539 additions and 10 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2015, 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
@ -109,6 +109,12 @@ public interface DocTree {
*/
IDENTIFIER,
/**
* Used for instances of {@index term optional-descr}
* representing a search term.
*/
INDEX("index"),
/**
* Used for instances of {@link InheritDocTree}
* representing an @inheritDoc tag.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2015, 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
@ -137,6 +137,14 @@ public interface DocTreeVisitor<R,P> {
*/
R visitIdentifier(IdentifierTree node, P p);
/**
* Visits an IndexTree node.
* @param node the node being visited
* @param p a parameter value
* @return a result value
*/
R visitIndex(IndexTree node, P p);
/**
* Visits an InheritDocTree node.
* @param node the node being visited

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2015, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.source.doctree;
import java.util.List;
/**
* A tree node for an @index or &#064;index inline tag.
*
* <p>
* {&#064;index keyword optional description} <br>
*
* @since 1.9
*/
@jdk.Exported
public interface IndexTree extends InlineTagTree {
/**
* Returns the specified search term.
* @return the search term
*/
DocTree getSearchTerm();
/**
* Returns the description, if any.
* @return the description
*/
List<? extends DocTree> getDescription();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2015, 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
@ -26,6 +26,7 @@
package com.sun.source.util;
import com.sun.source.doctree.*;
import com.sun.tools.javac.tree.DCTree.DCIndex;
/**
@ -247,6 +248,20 @@ public class DocTreeScanner<R,P> implements DocTreeVisitor<R,P> {
return null;
}
/**
* {@inheritDoc} This implementation returns {@code null}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of scanning
*/
@Override
public R visitIndex(IndexTree node, P p) {
R r = scan(node.getSearchTerm(), p);
r = scanAndReduce(node.getDescription(), p, r);
return r;
}
/**
* {@inheritDoc} This implementation returns {@code null}.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2015, 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
@ -216,6 +216,18 @@ public class SimpleDocTreeVisitor<R,P> implements DocTreeVisitor<R, P> {
return defaultAction(node, p);
}
/**
* {@inheritDoc} This implementation calls {@code defaultAction}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of {@code defaultAction}
*/
@Override
public R visitIndex(IndexTree node, P p) {
return defaultAction(node, p);
}
/**
* {@inheritDoc} This implementation calls {@code defaultAction}.
*

View File

@ -577,13 +577,50 @@ public class DocCommentParser {
return null;
}
/**
* Read a term ie. one word.
* It is an error if the beginning of the next tag is detected.
*/
@SuppressWarnings("fallthrough")
protected DCText inlineWord() {
int pos = bp;
int depth = 0;
loop:
while (bp < buflen) {
switch (ch) {
case '\n':
newline = true;
// fallthrough
case '\r': case '\f': case ' ': case '\t':
return m.at(pos).Text(newString(pos, bp));
case '@':
if (newline)
break loop;
case '{':
depth++;
break;
case '}':
if (depth == 0 || --depth == 0)
return m.at(pos).Text(newString(pos, bp));
break;
}
newline = false;
nextChar();
}
return null;
}
/**
* Read general text content of an inline tag, including HTML entities and elements.
* Matching pairs of { } are skipped; the text is terminated by the first
* unmatched }. It is an error if the beginning of the next tag is detected.
*/
@SuppressWarnings("fallthrough")
protected List<DCTree> inlineContent() {
private List<DCTree> inlineContent() {
ListBuffer<DCTree> trees = new ListBuffer<>();
skipWhitespace();
@ -614,6 +651,8 @@ public class DocCommentParser {
break;
case '{':
if (textStart == -1)
textStart = bp;
newline = false;
depth++;
nextChar();
@ -1022,6 +1061,28 @@ public class DocCommentParser {
}
},
// @index search-term options-description
new TagParser(Kind.INLINE, DCTree.Kind.INDEX) {
public DCTree parse(int pos) throws ParseException {
skipWhitespace();
if (ch == '}') {
throw new ParseException("dc.no.content");
}
DCTree term = ch == '"' ? quotedString() : inlineWord();
if (term == null) {
throw new ParseException("dc.no.content");
}
skipWhitespace();
List<DCTree> description = List.nil();
if (ch != '}') {
description = inlineContent();
} else {
nextChar();
}
return m.at(pos).Index(term, description);
}
},
// {@inheritDoc}
new TagParser(Kind.INLINE, DCTree.Kind.INHERIT_DOC) {
public DCTree parse(int pos) throws ParseException {

View File

@ -408,6 +408,36 @@ public abstract class DCTree implements DocTree {
}
}
public static class DCIndex extends DCInlineTag implements IndexTree {
public final DCTree term;
public final List<DCTree> description;
DCIndex(DCTree term, List<DCTree> description) {
this.term = term;
this.description = description;
}
@Override @DefinedBy(Api.COMPILER_TREE)
public Kind getKind() {
return Kind.INDEX;
}
@Override @DefinedBy(Api.COMPILER_TREE)
public <R, D> R accept(DocTreeVisitor<R, D> v, D d) {
return v.visitIndex(this, d);
}
@Override @DefinedBy(Api.COMPILER_TREE)
public DocTree getSearchTerm() {
return term;
}
@Override @DefinedBy(Api.COMPILER_TREE)
public java.util.List<? extends DocTree> getDescription() {
return description;
}
}
public static class DCInheritDoc extends DCInlineTag implements InheritDocTree {
@Override @DefinedBy(Api.COMPILER_TREE)
public Kind getKind() {

View File

@ -269,6 +269,24 @@ public class DocPretty implements DocTreeVisitor<Void,Void> {
return null;
}
@DefinedBy(Api.COMPILER_TREE)
public Void visitIndex(IndexTree node, Void p) {
try {
print("{");
printTagName(node);
print(" ");
print(node.getSearchTerm());
if (!node.getDescription().isEmpty()) {
print(" ");
print(node.getDescription());
}
print("}");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return null;
}
@DefinedBy(Api.COMPILER_TREE)
public Void visitInheritDoc(InheritDocTree node, Void p) {
try {

View File

@ -50,6 +50,7 @@ import com.sun.tools.javac.tree.DCTree.DCEndElement;
import com.sun.tools.javac.tree.DCTree.DCEntity;
import com.sun.tools.javac.tree.DCTree.DCErroneous;
import com.sun.tools.javac.tree.DCTree.DCIdentifier;
import com.sun.tools.javac.tree.DCTree.DCIndex;
import com.sun.tools.javac.tree.DCTree.DCInheritDoc;
import com.sun.tools.javac.tree.DCTree.DCLink;
import com.sun.tools.javac.tree.DCTree.DCLiteral;
@ -224,6 +225,12 @@ public class DocTreeMaker {
return tree;
}
public DCIndex Index(DCTree term, List<DCTree> description) {
DCIndex tree = new DCIndex(term, description);
tree.pos = pos;
return tree;
}
public DCInheritDoc InheritDoc() {
DCInheritDoc tree = new DCInheritDoc();
tree.pos = pos;

View File

@ -71,7 +71,8 @@ public class TestSearch extends JavadocTester {
@Test
void test3() {
javadoc("-d", "out-3", "-noindex", "-sourcepath", testSrc,
javadoc("-d", "out-3", "-noindex", "-Xdoclint:none",
"-sourcepath", testSrc,
"-use", "pkg", "pkg1", "pkg2", "pkg3");
checkExit(Exit.OK);
checkSearchOutput(false);
@ -86,7 +87,8 @@ public class TestSearch extends JavadocTester {
@Test
void test4() {
javadoc("-d", "out-4", "-html5", "-sourcepath", testSrc,
javadoc("-d", "out-4", "-html5", "-Xdoclint:none",
"-sourcepath", testSrc,
"-use", "pkg", "pkg1", "pkg2", "pkg3");
checkExit(Exit.OK);
checkSearchOutput(true);
@ -101,7 +103,8 @@ public class TestSearch extends JavadocTester {
@Test
void test5() {
javadoc("-d", "out-5", "-noindex", "-html5", "-sourcepath", testSrc,
javadoc("-d", "out-5", "-noindex", "-html5", "-Xdoclint:none",
"-sourcepath", testSrc,
"-use", "pkg", "pkg1", "pkg2", "pkg3");
checkExit(Exit.OK);
checkSearchOutput(false);
@ -116,7 +119,8 @@ public class TestSearch extends JavadocTester {
@Test
void test6() {
javadoc("-d", "out-6", "-nocomment", "-sourcepath", testSrc,
javadoc("-d", "out-6", "-nocomment", "-Xdoclint:none",
"-sourcepath", testSrc,
"-use", "pkg", "pkg1", "pkg2", "pkg3");
checkExit(Exit.OK);
checkSearchOutput(true);
@ -131,7 +135,8 @@ public class TestSearch extends JavadocTester {
@Test
void test7() {
javadoc("-d", "out-7", "-nodeprecated", "-sourcepath", testSrc,
javadoc("-d", "out-7", "-nodeprecated", "-Xdoclint:none",
"-sourcepath", testSrc,
"-use", "pkg", "pkg1", "pkg2", "pkg3");
checkExit(Exit.OK);
checkSearchOutput(true);

View File

@ -444,6 +444,18 @@ public class DocCommentTester {
return null;
}
@Override
public Void visitIndex(IndexTree node, Void p) {
header(node);
indent(+1);
print("term", node.getSearchTerm());
print("description", node.getDescription());
indent(-1);
indent();
out.println("]");
return null;
}
public Void visitInheritDoc(InheritDocTree node, Void p) {
header(node, "");
return null;
@ -619,11 +631,19 @@ public class DocCommentTester {
throw new UnsupportedOperationException("Not supported yet.");
}
/*
* Use this method to start printing a multi-line representation of a
* DocTree node. The representation should be termintated by calling
* out.println("]").
*/
void header(DocTree node) {
indent();
out.println(simpleClassName(node) + "[" + node.getKind() + ", pos:" + ((DCTree) node).pos);
}
/*
* Use this method to print a single-line representation of a DocTree node.
*/
void header(DocTree node, String rest) {
indent();
out.println(simpleClassName(node) + "[" + node.getKind() + ", pos:" + ((DCTree) node).pos

View File

@ -0,0 +1,289 @@
/*
* Copyright (c) 2015, 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 8144287
* @summary extend com.sun.source API to support parsing javadoc comments
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.tree
* jdk.compiler/com.sun.tools.javac.util
* @build DocCommentTester
* @run main DocCommentTester IndexTest.java
*/
class IndexTest {
/**
* abc {@index xyz} def
*/
void simple_term() {}
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, xyz]
description: empty
]
Text[TEXT, pos:17, _def]
body: empty
block tags: empty
]
*/
/**
* abc {@index lmn pqr stu} def
*/
void simple_term_with_description() { }
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, lmn]
description: 1
Text[TEXT, pos:17, pqr_stu]
]
Text[TEXT, pos:25, _def]
body: empty
block tags: empty
]
*/
/**
* abc {@index ijk {lmn opq} } def
*/
void phrase_with_curly_description() { }
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, ijk]
description: 1
Text[TEXT, pos:17, {lmn_opq}_]
]
Text[TEXT, pos:28, _def]
body: empty
block tags: empty
]
*/
/**
* abc {@index ijk lmn
* opq
* rst
* } def
*/
void phrase_with_nl_description() { }
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, ijk]
description: 1
Text[TEXT, pos:17, lmn|_opq|_rst|_]
]
Text[TEXT, pos:33, _def]
body: empty
block tags: empty
]
*/
/**
* abc {@index "lmn pqr"} def
*/
void phrase_no_description() { }
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, "lmn_pqr"]
description: empty
]
Text[TEXT, pos:23, _def]
body: empty
block tags: empty
]
*/
/**
* abc {@index "ijk lmn" pqr xyz} def
*/
void phrase_with_description() { }
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, "ijk_lmn"]
description: 1
Text[TEXT, pos:23, pqr_xyz]
]
Text[TEXT, pos:31, _def]
body: empty
block tags: empty
]
*/
/**
* abc {@index {@xyz} "{@see xyz}" def}
*/
void term_and_description_with_nested_tag() {}
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 2
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, {@xyz}]
description: 1
Text[TEXT, pos:20, "{@see_xyz}"_def]
]
body: empty
block tags: empty
]
*/
/**
* abc {@index @def lmn } xyz
*/
void term_with_at() { }
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, @def]
description: 1
Text[TEXT, pos:18, lmn_]
]
Text[TEXT, pos:23, _xyz]
body: empty
block tags: empty
]
*/
/**
* abc {@index ijk@lmn pqr } xyz
*/
void term_with_text_at() { }
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, ijk@lmn]
description: 1
Text[TEXT, pos:21, pqr_]
]
Text[TEXT, pos:26, _xyz]
body: empty
block tags: empty
]
*/
/**
* abc {@index ""} def
*/
void empty_index_in_quotes() {}
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Index[INDEX, pos:5
term:
Text[TEXT, pos:13, ""]
description: empty
]
Text[TEXT, pos:16, _def]
body: empty
block tags: empty
]
*/
/**
* abc {@index
* @return def} xyz
*/
void bad_nl_at_in_term() {}
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 2
Text[TEXT, pos:1, abc_]
Erroneous[ERRONEOUS, pos:5
code: compiler.err.dc.no.content
body: {@index
]
body: empty
block tags: 1
Return[RETURN, pos:14
description: 1
Text[TEXT, pos:22, def}_xyz]
]
]
*/
/**
* abc {@index "xyz } def
*/
void bad_unbalanced_quote() {}
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 2
Text[TEXT, pos:1, abc_]
Erroneous[ERRONEOUS, pos:5
code: compiler.err.dc.no.content
body: {@index_"xyz_}_def
]
body: empty
block tags: empty
]
*/
/**
* abc {@index} def
*/
void bad_no_index() {}
/*
DocComment[DOC_COMMENT, pos:1
firstSentence: 3
Text[TEXT, pos:1, abc_]
Erroneous[ERRONEOUS, pos:5
code: compiler.err.dc.no.content
body: {@index
]
Text[TEXT, pos:12, }_def]
body: empty
block tags: empty
]
*/
}

View File

@ -1049,6 +1049,13 @@ public class DPrinter {
return visitTree(node, null);
}
public Void visitIndex(IndexTree node, Void p) {
printString("kind", node.getKind().name());
printDocTree("term", node.getSearchTerm());
printList("desc", node.getDescription());
return visitInlineTag(node, p);
}
public Void visitInheritDoc(InheritDocTree node, Void p) {
return visitInlineTag(node, null);
}