8169608: Compiler Tree API's Doctrees.getDocTreePath needs to accept a PackageElement

8157611: field visiblePackages is null for the unnamed module producing NPE when accessed

Reviewed-by: jjg, jlahoda
This commit is contained in:
Kumar Srinivasan 2017-01-19 13:16:19 -08:00
parent 362b794a82
commit 8045fb0059
11 changed files with 250 additions and 80 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -31,6 +31,7 @@ import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.JavaCompiler.CompilationTask;
@ -127,17 +128,22 @@ public abstract class DocTrees extends Trees {
/**
* Returns a doc tree path containing the doc comment tree of the given file.
* The file must be an HTML file, in which case the doc comment tree represents the
* contents of the <body> tag, and any enclosing tags are ignored.
* The file must be an HTML file, in which case the doc comment tree represents
* the contents of the {@code <body>} tag, and any enclosing tags are ignored.
* Any references to source code elements contained in {@code @see} and
* {@code {@link}} tags in the doc comment tree will be evaluated in the
* context of the given package element.
* Returns {@code null} if no doc comment was found.
* Future releases may support additional file types.
*
* @param fileObject the content container
* @return a doc tree path containing the doc comment read from the given file.
* @param fileObject a file object encapsulating the HTML content
* @param packageElement a package element to associate with the given file object
* representing a legacy package.html, null otherwise
* @return a doc tree path containing the doc comment parsed from the given file
* @throws IllegalArgumentException if the fileObject is not an HTML file
*
* @since 9
*/
public abstract DocTreePath getDocTreePath(FileObject fileObject);
public abstract DocTreePath getDocTreePath(FileObject fileObject, PackageElement packageElement);
/**
* Returns the language model element referred to by the leaf node of the given

View File

@ -174,7 +174,6 @@ public class JavacTrees extends DocTrees {
private JavaFileManager fileManager;
private ParserFactory parser;
private Symtab syms;
private Map<JavaFileObject, PackageSymbol> javaFileObjectToPackageMap;
// called reflectively from Trees.instance(CompilationTask task)
public static JavacTrees instance(JavaCompiler.CompilationTask task) {
@ -198,7 +197,6 @@ public class JavacTrees extends DocTrees {
}
protected JavacTrees(Context context) {
javaFileObjectToPackageMap = new HashMap<>();
this.breakIterator = null;
context.put(JavacTrees.class, this);
init(context);
@ -1039,10 +1037,11 @@ public class JavacTrees extends DocTrees {
}
@Override @DefinedBy(Api.COMPILER_TREE)
public DocTreePath getDocTreePath(FileObject fileObject) {
public DocTreePath getDocTreePath(FileObject fileObject, PackageElement packageElement) {
JavaFileObject jfo = asJavaFileObject(fileObject);
DocCommentTree docCommentTree = getDocCommentTree(jfo);
return new DocTreePath(makeTreePath(jfo, docCommentTree), docCommentTree);
TreePath treePath = makeTreePath((PackageSymbol)packageElement, jfo, docCommentTree);
return new DocTreePath(treePath, docCommentTree);
}
@Override @DefinedBy(Api.COMPILER_TREE)
@ -1160,17 +1159,8 @@ public class JavacTrees extends DocTrees {
}
}
/**
* Register a file object, such as for a package.html, that provides
* doc comments for a package.
* @param psym the PackageSymbol representing the package.
* @param jfo the JavaFileObject for the given package.
*/
public void putJavaFileObject(PackageSymbol psym, JavaFileObject jfo) {
javaFileObjectToPackageMap.putIfAbsent(jfo, psym);
}
private TreePath makeTreePath(final JavaFileObject jfo, DocCommentTree dcTree) {
private TreePath makeTreePath(final PackageSymbol psym, final JavaFileObject jfo,
DocCommentTree dcTree) {
JCCompilationUnit jcCompilationUnit = new JCCompilationUnit(List.nil()) {
public int getPos() {
return Position.FIRSTPOS;
@ -1191,9 +1181,6 @@ public class JavacTrees extends DocTrees {
}
};
PackageSymbol psym = javaFileObjectToPackageMap.getOrDefault(jfo,
syms.unnamedModule.unnamedPackage);
jcCompilationUnit.docComments = new DocCommentTable() {
@Override
public boolean hasComment(JCTree tree) {

View File

@ -1070,6 +1070,8 @@ public abstract class Symbol extends AnnoConstruct implements Element {
public Name fullname;
public ClassSymbol package_info; // see bug 6443073
public ModuleSymbol modle;
// the file containing the documentation comments for the package
public JavaFileObject sourcefile;
public PackageSymbol(Name name, Type type, Symbol owner) {
super(PCK, 0, name, type, owner);

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,6 +35,19 @@
package jdk.javadoc.internal.doclets.toolkit;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.doctree.DocTree;
@ -45,22 +58,6 @@ import com.sun.source.util.DocTreeFactory;
import com.sun.source.util.DocTreePath;
import com.sun.source.util.DocTrees;
import com.sun.source.util.TreePath;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
@ -177,10 +174,18 @@ public class CommentUtils {
*/
public DocCommentDuo getHtmlCommentDuo(Element e) {
FileObject fo = null;
if (e.getKind().equals(ElementKind.OTHER)) {
fo = configuration.getOverviewPath();
} else if (e.getKind().equals(ElementKind.PACKAGE)) {
fo = configuration.workArounds.getJavaFileObject((PackageElement)e);
PackageElement pe = null;
switch (e.getKind()) {
case OTHER:
fo = configuration.getOverviewPath();
pe = configuration.workArounds.getUnnamedPackage();
break;
case PACKAGE:
fo = configuration.workArounds.getJavaFileObject((PackageElement)e);
pe = (PackageElement)e;
break;
default:
return null;
}
if (fo == null) {
return null;
@ -190,7 +195,7 @@ public class CommentUtils {
if (dcTree == null) {
return null;
}
DocTreePath treePath = trees.getDocTreePath(fo);
DocTreePath treePath = trees.getDocTreePath(fo, pe);
return new DocCommentDuo(treePath.getTreePath(), dcTree);
}

View File

@ -44,6 +44,7 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.tools.FileObject;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
@ -59,7 +60,9 @@ import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.model.JavacElements;
@ -192,11 +195,24 @@ public class WorkArounds {
return ((VarSymbol)ve).getConstValue();
}
//TODO: DocTrees: Trees.getPath(Element e) is slow a factor 4-5 times.
// TODO: DocTrees: Trees.getPath(Element e) is slow a factor 4-5 times.
public Map<Element, TreePath> getElementToTreePath() {
return toolEnv.elementToTreePath;
}
// TODO: we need ElementUtils.getPackage to cope with input strings
// to return the proper unnamedPackage for all supported releases.
PackageElement getUnnamedPackage() {
return (toolEnv.source.allowModules())
? toolEnv.syms.unnamedModule.unnamedPackage
: toolEnv.syms.noModule.unnamedPackage;
}
// TODO: implement in either jx.l.m API (preferred) or DocletEnvironment.
FileObject getJavaFileObject(PackageElement packageElement) {
return ((PackageSymbol)packageElement).sourcefile;
}
// TODO: needs to ported to jx.l.m.
public TypeElement searchClass(TypeElement klass, String className) {
// search by qualified name first
@ -530,12 +546,6 @@ public class WorkArounds {
}
}
// TODO: this is a fast way to get the JavaFileObject for
// a package.html file, however we need to eliminate this.
public JavaFileObject getJavaFileObject(PackageElement pe) {
return toolEnv.pkgToJavaFOMap.get(pe);
}
// TODO: we need to eliminate this, as it is hacky.
/**
* Returns a representation of the package truncated to two levels.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -39,14 +39,12 @@ import java.util.Set;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.ModuleElement.ExportsDirective;
import javax.lang.model.element.ModuleElement.RequiresDirective;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.tools.JavaFileManager;
@ -54,15 +52,12 @@ import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Kinds.Kind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.comp.Modules;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
@ -75,9 +70,11 @@ import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.doclet.DocletEnvironment.ModuleMode;
import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
import static javax.tools.JavaFileObject.Kind.*;
import static jdk.javadoc.internal.tool.Main.Result.*;
import static jdk.javadoc.internal.tool.JavadocTool.isValidClassName;
/**
* This class manages elements specified on the command line, and
* produces "specified" and "included" data sets, needed by the
@ -864,7 +861,7 @@ public class ElementsTable {
}
private boolean isTypeElementSelected(TypeElement te) {
return (xclasses || toolEnv.isFromSource(te)) && isSelected(te);
return (xclasses || toolEnv.getFileKind(te) == SOURCE) && isSelected(te);
}
SimpleElementVisitor9<Boolean, Void> visibleElementVisitor = null;

View File

@ -88,8 +88,7 @@ public class JavadocClassFinder extends ClassFinder {
@Override
protected void extraFileActions(PackageSymbol pack, JavaFileObject fo) {
if (fo.isNameCompatible("package", JavaFileObject.Kind.HTML)) {
toolEnv.pkgToJavaFOMap.put(pack, fo);
trees.putJavaFileObject(pack, fo);
pack.sourcefile = fo;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
@ -29,7 +29,6 @@ package jdk.javadoc.internal.tool;
import java.util.*;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.JavaFileManager;
@ -116,8 +115,6 @@ public class ToolEnvironment {
WeakHashMap<JCTree, TreePath> treePaths = new WeakHashMap<>();
public final HashMap<PackageElement, JavaFileObject> pkgToJavaFOMap = new HashMap<>();
/** Allow documenting from class files? */
boolean docClasses = false;
@ -193,21 +190,11 @@ public class ToolEnvironment {
elementToTreePath.put(e, tree);
}
/**
* Returns true if the type element originates from source.
* Primarily used to disambiguate a type element associated with a source
* file versus a class file.
* @param te the type element
* @return true if the symbol is from source
*/
public boolean isFromSource(TypeElement te) {
return getFileKind(te) == Kind.SOURCE;
}
public Kind getFileKind(TypeElement te) {
JavaFileObject jfo = ((ClassSymbol)te).outermostClass().classfile;
return jfo == null ? Kind.SOURCE : jfo.getKind();
}
/**
* Print a notice, iff <em>quiet</em> is not specified.
*

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2016, 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 8157611
* @summary test DocTrees is working correctly relative to HTML access
* @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 /tools/lib
* @build toolbox.ToolBox toolbox.TestRunner
* @run main TestDocTrees
*/
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import toolbox.*;
import toolbox.Task.Expect;
import static toolbox.Task.OutputKind.*;
/**
* This class is used to test DocTrees functionality relating to
* package and overview HTML files.
*/
public class TestDocTrees extends TestRunner {
final ToolBox tb;
final File testFile;
final File testSrc;
final File overviewFile;
TestDocTrees() throws IOException {
super(System.err);
tb = new ToolBox();
testSrc = new File(System.getProperty("test.src"));
testFile = new File(testSrc, "TestDocTrees.java");
overviewFile = new File(testSrc, "overview.html");
}
protected void runTests() throws Exception {
runTests(m -> new Object[]{Paths.get(m.getName())});
}
public static void main(String... args) throws Exception {
new TestDocTrees().runTests();
}
@Test
public void testOverviewWithRelease8(Path out) {
execTask("-d", out.toString(),
"--release", "8",
"-Xdoclint:all",
"-Xdoclint:-missing",
"-sourcepath", testSrc.getAbsolutePath(),
testFile.getAbsolutePath(),
"-overview", overviewFile.getAbsolutePath());
}
@Test
public void testOverviewWithoutRelease(Path out) throws Exception {
execTask("-d", out.toString(),
"-Xdoclint:all",
"-Xdoclint:-missing",
"-sourcepath", testSrc.getAbsolutePath(),
testFile.getAbsolutePath(),
"-overview", overviewFile.getAbsolutePath());
}
private Task.Result execTask(String... args) {
JavadocTask et = new JavadocTask(tb, Task.Mode.CMDLINE);
//args.forEach((a -> System.err.println("arg: " + a)));
return et.options(args).run();
}
}

View File

@ -0,0 +1,27 @@
<!--
Copyright (c) 2016, 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
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.
-->
<html>
<body>
<b>{@link omg.what.gives}</b>
</body>
</html>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2016, 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
@ -23,7 +23,7 @@
/*
* @test
* @bug 8132096
* @bug 8132096 8157611
* @summary test the APIs in the DocTree interface
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.file
@ -48,12 +48,15 @@ import java.util.List;
import java.util.Locale;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.lang.model.util.Elements;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.util.DocTreePath;
import com.sun.source.util.DocTrees;
import com.sun.source.util.JavacTask;
import com.sun.tools.javac.api.JavacTool;
@ -90,6 +93,9 @@ public class DocCommentTreeApiTester {
// tests files relative path in an unnamed package
test.runRelativePathTest("OverviewTest.java", "overview0.html");
// tests doctreepath using package element and package.html
test.runDocTreePath("pkg/Anchor.java", "package.html");
// test for correct parsing using valid and some invalid html tags
for (int i = 0; i < 7; i++) {
String hname = "overview" + i + ".html";
@ -152,6 +158,7 @@ public class DocCommentTreeApiTester {
}
}
}
/**
* Tests DocTrees.getDocCommentTree(Element e, String relpath) using relative path.
*
@ -219,6 +226,49 @@ public class DocCommentTreeApiTester {
}
}
/**
* Tests DocTrees.getDocTreePath(PackageElement p, FileObject fo).
*
* @param javaFileName the java anchor file
* @param pkgFileName the package file name
* @throws Exception e if something goes awry
*/
public void runDocTreePath(String javaFileName, String pkgFileName) throws Exception {
List<File> javaFiles = new ArrayList<>();
javaFiles.add(new File(testSrc, javaFileName));
List<File> dirs = new ArrayList<>();
dirs.add(new File(testSrc));
try (StandardJavaFileManager fm = javac.getStandardFileManager(null, null, null)) {
fm.setLocation(javax.tools.StandardLocation.SOURCE_PATH, dirs);
Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(javaFiles);
final JavacTask t = javac.getTask(null, fm, null, null, null, fos);
final DocTrees trees = DocTrees.instance(t);
final Elements elementUtils = t.getElements();
Iterable<? extends Element> elements = t.analyze();
Element klass = elements.iterator().next();
PackageElement pkg = elementUtils.getPackageOf(klass);
FileObject htmlFo = fm.getFileForInput(javax.tools.StandardLocation.SOURCE_PATH,
t.getElements().getPackageOf(klass).getQualifiedName().toString(),
"package.html");
System.out.println();
DocTreePath treePath = trees.getDocTreePath(htmlFo, pkg);
DocCommentTree dcTree = treePath.getDocComment();
StringWriter sw = new StringWriter();
printer.print(dcTree, sw);
String found = sw.toString();
String expected = getExpected(htmlFo.openReader(true));
astcheck(pkgFileName, expected, found);
}
}
void astcheck(String testinfo, String expected, String found) {
System.err.print("ASTChecker: " + testinfo);
check0(expected, found);