--- old/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocEnv.java Fri Jan 22 12:20:56 2016 +++ /dev/null Fri Jan 22 12:20:56 2016 @@ -1,861 +0,0 @@ -/* - * Copyright (c) 2000, 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.tools.javadoc; - -import java.lang.reflect.Modifier; -import java.util.*; - -import javax.tools.JavaFileManager; - -import com.sun.javadoc.*; -import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.util.JavacTask; -import com.sun.source.util.TreePath; -import com.sun.tools.doclint.DocLint; -import com.sun.tools.javac.api.BasicJavacTask; -import com.sun.tools.javac.code.*; -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.PackageSymbol; -import com.sun.tools.javac.code.Symbol.VarSymbol; -import com.sun.tools.javac.code.Type.ClassType; -import com.sun.tools.javac.comp.Check; -import com.sun.tools.javac.comp.Enter; -import com.sun.tools.javac.file.JavacFileManager; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCClassDecl; -import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; -import com.sun.tools.javac.tree.JCTree.JCPackageDecl; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Names; - -/** - * Holds the environment for a run of javadoc. - * Holds only the information needed throughout the - * run and not the compiler info that could be GC'ed - * or ported. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - * - * @since 1.4 - * @author Robert Field - * @author Neal Gafter (rewrite) - * @author Scott Seligman (generics) - */ -public class DocEnv { - protected static final Context.Key docEnvKey = new Context.Key<>(); - - public static DocEnv instance(Context context) { - DocEnv instance = context.get(docEnvKey); - if (instance == null) - instance = new DocEnv(context); - return instance; - } - - DocLocale doclocale; - - private final Messager messager; - - /** Predefined symbols known to the compiler. */ - final Symtab syms; - - /** Referenced directly in RootDocImpl. */ - private final ClassFinder finder; - - /** Javadoc's own version of the compiler's enter phase. */ - final Enter enter; - - /** The name table. */ - private Names names; - - /** The encoding name. */ - private String encoding; - - final Symbol externalizableSym; - - /** Access filter (public, protected, ...). */ - protected ModifierFilter showAccess; - - /** True if we are using a sentence BreakIterator. */ - boolean breakiterator; - - /** - * True if we do not want to print any notifications at all. - */ - boolean quiet = false; - - Check chk; - Types types; - JavaFileManager fileManager; - Context context; - DocLint doclint; - - WeakHashMap treePaths = new WeakHashMap<>(); - - /** Allow documenting from class files? */ - boolean docClasses = false; - - /** Does the doclet only expect pre-1.5 doclet API? */ - protected boolean legacyDoclet = true; - - /** - * Set this to true if you would like to not emit any errors, warnings and - * notices. - */ - private boolean silent = false; - - /** - * The source language version. - */ - protected Source source; - - /** - * Constructor - * - * @param context Context for this javadoc instance. - */ - protected DocEnv(Context context) { - context.put(docEnvKey, this); - this.context = context; - - messager = Messager.instance0(context); - syms = Symtab.instance(context); - finder = JavadocClassFinder.instance(context); - enter = JavadocEnter.instance(context); - names = Names.instance(context); - externalizableSym = syms.enterClass(names.fromString("java.io.Externalizable")); - chk = Check.instance(context); - types = Types.instance(context); - fileManager = context.get(JavaFileManager.class); - if (fileManager instanceof JavacFileManager) { - ((JavacFileManager)fileManager).setSymbolFileEnabled(false); - } - - // Default. Should normally be reset with setLocale. - this.doclocale = new DocLocale(this, "", breakiterator); - source = Source.instance(context); - } - - public void setSilent(boolean silent) { - this.silent = silent; - } - - /** - * Look up ClassDoc by qualified name. - */ - public ClassDocImpl lookupClass(String name) { - ClassSymbol c = getClassSymbol(name); - if (c != null) { - return getClassDoc(c); - } else { - return null; - } - } - - /** - * Load ClassDoc by qualified name. - */ - public ClassDocImpl loadClass(String name) { - try { - ClassSymbol c = finder.loadClass(names.fromString(name)); - return getClassDoc(c); - } catch (CompletionFailure ex) { - chk.completionError(null, ex); - return null; - } - } - - /** - * Look up PackageDoc by qualified name. - */ - public PackageDocImpl lookupPackage(String name) { - //### Jing alleges that class check is needed - //### to avoid a compiler bug. Most likely - //### instead a dummy created for error recovery. - //### Should investigate this. - PackageSymbol p = syms.packages.get(names.fromString(name)); - ClassSymbol c = getClassSymbol(name); - if (p != null && c == null) { - return getPackageDoc(p); - } else { - return null; - } - } - // where - /** Retrieve class symbol by fully-qualified name. - */ - ClassSymbol getClassSymbol(String name) { - // Name may contain nested class qualification. - // Generate candidate flatnames with successively shorter - // package qualifiers and longer nested class qualifiers. - int nameLen = name.length(); - char[] nameChars = name.toCharArray(); - int idx = name.length(); - for (;;) { - ClassSymbol s = syms.classes.get(names.fromChars(nameChars, 0, nameLen)); - if (s != null) - return s; // found it! - idx = name.substring(0, idx).lastIndexOf('.'); - if (idx < 0) break; - nameChars[idx] = '$'; - } - return null; - } - - /** - * Set the locale. - */ - public void setLocale(String localeName) { - // create locale specifics - doclocale = new DocLocale(this, localeName, breakiterator); - // update Messager if locale has changed. - messager.setLocale(doclocale.locale); - } - - /** Check whether this member should be documented. */ - public boolean shouldDocument(VarSymbol sym) { - long mod = sym.flags(); - - if ((mod & Flags.SYNTHETIC) != 0) { - return false; - } - - return showAccess.checkModifier(translateModifiers(mod)); - } - - /** Check whether this member should be documented. */ - public boolean shouldDocument(MethodSymbol sym) { - long mod = sym.flags(); - - if ((mod & Flags.SYNTHETIC) != 0) { - return false; - } - - return showAccess.checkModifier(translateModifiers(mod)); - } - - /** check whether this class should be documented. */ - public boolean shouldDocument(ClassSymbol sym) { - return - (sym.flags_field&Flags.SYNTHETIC) == 0 && // no synthetics - (docClasses || getClassDoc(sym).tree != null) && - isVisible(sym); - } - - //### Comment below is inaccurate wrt modifier filter testing - /** - * Check the visibility if this is an nested class. - * if this is not a nested class, return true. - * if this is an static visible nested class, - * return true. - * if this is an visible nested class - * if the outer class is visible return true. - * else return false. - * IMPORTANT: This also allows, static nested classes - * to be defined inside an nested class, which is not - * allowed by the compiler. So such an test case will - * not reach upto this method itself, but if compiler - * allows it, then that will go through. - */ - protected boolean isVisible(ClassSymbol sym) { - long mod = sym.flags_field; - if (!showAccess.checkModifier(translateModifiers(mod))) { - return false; - } - ClassSymbol encl = sym.owner.enclClass(); - return (encl == null || (mod & Flags.STATIC) != 0 || isVisible(encl)); - } - - //---------------- print forwarders ----------------// - - /** - * Print error message, increment error count. - * - * @param msg message to print. - */ - public void printError(String msg) { - if (silent) - return; - messager.printError(msg); - } - - /** - * Print error message, increment error count. - * - * @param key selects message from resource - */ - public void error(DocImpl doc, String key) { - if (silent) - return; - messager.error(doc==null ? null : doc.position(), key); - } - - /** - * Print error message, increment error count. - * - * @param key selects message from resource - */ - public void error(SourcePosition pos, String key) { - if (silent) - return; - messager.error(pos, key); - } - - /** - * Print error message, increment error count. - * - * @param msg message to print. - */ - public void printError(SourcePosition pos, String msg) { - if (silent) - return; - messager.printError(pos, msg); - } - - /** - * Print error message, increment error count. - * - * @param key selects message from resource - * @param a1 first argument - */ - public void error(DocImpl doc, String key, String a1) { - if (silent) - return; - messager.error(doc==null ? null : doc.position(), key, a1); - } - - /** - * Print error message, increment error count. - * - * @param key selects message from resource - * @param a1 first argument - * @param a2 second argument - */ - public void error(DocImpl doc, String key, String a1, String a2) { - if (silent) - return; - messager.error(doc==null ? null : doc.position(), key, a1, a2); - } - - /** - * Print error message, increment error count. - * - * @param key selects message from resource - * @param a1 first argument - * @param a2 second argument - * @param a3 third argument - */ - public void error(DocImpl doc, String key, String a1, String a2, String a3) { - if (silent) - return; - messager.error(doc==null ? null : doc.position(), key, a1, a2, a3); - } - - /** - * Print warning message, increment warning count. - * - * @param msg message to print. - */ - public void printWarning(String msg) { - if (silent) - return; - messager.printWarning(msg); - } - - /** - * Print warning message, increment warning count. - * - * @param key selects message from resource - */ - public void warning(DocImpl doc, String key) { - if (silent) - return; - messager.warning(doc==null ? null : doc.position(), key); - } - - /** - * Print warning message, increment warning count. - * - * @param msg message to print. - */ - public void printWarning(SourcePosition pos, String msg) { - if (silent) - return; - messager.printWarning(pos, msg); - } - - /** - * Print warning message, increment warning count. - * - * @param key selects message from resource - * @param a1 first argument - */ - public void warning(DocImpl doc, String key, String a1) { - if (silent) - return; - // suppress messages that have (probably) been covered by doclint - if (doclint != null && doc != null && key.startsWith("tag")) - return; - messager.warning(doc==null ? null : doc.position(), key, a1); - } - - /** - * Print warning message, increment warning count. - * - * @param key selects message from resource - * @param a1 first argument - * @param a2 second argument - */ - public void warning(DocImpl doc, String key, String a1, String a2) { - if (silent) - return; - messager.warning(doc==null ? null : doc.position(), key, a1, a2); - } - - /** - * Print warning message, increment warning count. - * - * @param key selects message from resource - * @param a1 first argument - * @param a2 second argument - * @param a3 third argument - */ - public void warning(DocImpl doc, String key, String a1, String a2, String a3) { - if (silent) - return; - messager.warning(doc==null ? null : doc.position(), key, a1, a2, a3); - } - - /** - * Print warning message, increment warning count. - * - * @param key selects message from resource - * @param a1 first argument - * @param a2 second argument - * @param a3 third argument - */ - public void warning(DocImpl doc, String key, String a1, String a2, String a3, - String a4) { - if (silent) - return; - messager.warning(doc==null ? null : doc.position(), key, a1, a2, a3, a4); - } - - /** - * Print a message. - * - * @param msg message to print. - */ - public void printNotice(String msg) { - if (silent || quiet) - return; - messager.printNotice(msg); - } - - - /** - * Print a message. - * - * @param key selects message from resource - */ - public void notice(String key) { - if (silent || quiet) - return; - messager.notice(key); - } - - /** - * Print a message. - * - * @param msg message to print. - */ - public void printNotice(SourcePosition pos, String msg) { - if (silent || quiet) - return; - messager.printNotice(pos, msg); - } - - /** - * Print a message. - * - * @param key selects message from resource - * @param a1 first argument - */ - public void notice(String key, String a1) { - if (silent || quiet) - return; - messager.notice(key, a1); - } - - /** - * Print a message. - * - * @param key selects message from resource - * @param a1 first argument - * @param a2 second argument - */ - public void notice(String key, String a1, String a2) { - if (silent || quiet) - return; - messager.notice(key, a1, a2); - } - - /** - * Print a message. - * - * @param key selects message from resource - * @param a1 first argument - * @param a2 second argument - * @param a3 third argument - */ - public void notice(String key, String a1, String a2, String a3) { - if (silent || quiet) - return; - messager.notice(key, a1, a2, a3); - } - - /** - * Exit, reporting errors and warnings. - */ - public void exit() { - // Messager should be replaced by a more general - // compilation environment. This can probably - // subsume DocEnv as well. - messager.exit(); - } - - protected Map packageMap = new HashMap<>(); - /** - * Return the PackageDoc of this package symbol. - */ - public PackageDocImpl getPackageDoc(PackageSymbol pack) { - PackageDocImpl result = packageMap.get(pack); - if (result != null) return result; - result = new PackageDocImpl(this, pack); - packageMap.put(pack, result); - return result; - } - - /** - * Create the PackageDoc (or a subtype) for a package symbol. - */ - void makePackageDoc(PackageSymbol pack, TreePath treePath) { - PackageDocImpl result = packageMap.get(pack); - if (result != null) { - if (treePath != null) result.setTreePath(treePath); - } else { - result = new PackageDocImpl(this, pack, treePath); - packageMap.put(pack, result); - } - } - - - protected Map classMap = new HashMap<>(); - /** - * Return the ClassDoc (or a subtype) of this class symbol. - */ - public ClassDocImpl getClassDoc(ClassSymbol clazz) { - ClassDocImpl result = classMap.get(clazz); - if (result != null) return result; - if (isAnnotationType(clazz)) { - result = new AnnotationTypeDocImpl(this, clazz); - } else { - result = new ClassDocImpl(this, clazz); - } - classMap.put(clazz, result); - return result; - } - - /** - * Create the ClassDoc (or a subtype) for a class symbol. - */ - protected void makeClassDoc(ClassSymbol clazz, TreePath treePath) { - ClassDocImpl result = classMap.get(clazz); - if (result != null) { - if (treePath != null) result.setTreePath(treePath); - return; - } - if (isAnnotationType((JCClassDecl) treePath.getLeaf())) { // flags of clazz may not yet be set - result = new AnnotationTypeDocImpl(this, clazz, treePath); - } else { - result = new ClassDocImpl(this, clazz, treePath); - } - classMap.put(clazz, result); - } - - protected static boolean isAnnotationType(ClassSymbol clazz) { - return ClassDocImpl.isAnnotationType(clazz); - } - - protected static boolean isAnnotationType(JCClassDecl tree) { - return (tree.mods.flags & Flags.ANNOTATION) != 0; - } - - protected Map fieldMap = new HashMap<>(); - /** - * Return the FieldDoc of this var symbol. - */ - public FieldDocImpl getFieldDoc(VarSymbol var) { - FieldDocImpl result = fieldMap.get(var); - if (result != null) return result; - result = new FieldDocImpl(this, var); - fieldMap.put(var, result); - return result; - } - /** - * Create a FieldDoc for a var symbol. - */ - protected void makeFieldDoc(VarSymbol var, TreePath treePath) { - FieldDocImpl result = fieldMap.get(var); - if (result != null) { - if (treePath != null) result.setTreePath(treePath); - } else { - result = new FieldDocImpl(this, var, treePath); - fieldMap.put(var, result); - } - } - - protected Map methodMap = new HashMap<>(); - /** - * Create a MethodDoc for this MethodSymbol. - * Should be called only on symbols representing methods. - */ - protected void makeMethodDoc(MethodSymbol meth, TreePath treePath) { - MethodDocImpl result = (MethodDocImpl)methodMap.get(meth); - if (result != null) { - if (treePath != null) result.setTreePath(treePath); - } else { - result = new MethodDocImpl(this, meth, treePath); - methodMap.put(meth, result); - } - } - - /** - * Return the MethodDoc for a MethodSymbol. - * Should be called only on symbols representing methods. - */ - public MethodDocImpl getMethodDoc(MethodSymbol meth) { - assert !meth.isConstructor() : "not expecting a constructor symbol"; - MethodDocImpl result = (MethodDocImpl)methodMap.get(meth); - if (result != null) return result; - result = new MethodDocImpl(this, meth); - methodMap.put(meth, result); - return result; - } - - /** - * Create the ConstructorDoc for a MethodSymbol. - * Should be called only on symbols representing constructors. - */ - protected void makeConstructorDoc(MethodSymbol meth, TreePath treePath) { - ConstructorDocImpl result = (ConstructorDocImpl)methodMap.get(meth); - if (result != null) { - if (treePath != null) result.setTreePath(treePath); - } else { - result = new ConstructorDocImpl(this, meth, treePath); - methodMap.put(meth, result); - } - } - - /** - * Return the ConstructorDoc for a MethodSymbol. - * Should be called only on symbols representing constructors. - */ - public ConstructorDocImpl getConstructorDoc(MethodSymbol meth) { - assert meth.isConstructor() : "expecting a constructor symbol"; - ConstructorDocImpl result = (ConstructorDocImpl)methodMap.get(meth); - if (result != null) return result; - result = new ConstructorDocImpl(this, meth); - methodMap.put(meth, result); - return result; - } - - /** - * Create the AnnotationTypeElementDoc for a MethodSymbol. - * Should be called only on symbols representing annotation type elements. - */ - protected void makeAnnotationTypeElementDoc(MethodSymbol meth, TreePath treePath) { - AnnotationTypeElementDocImpl result = - (AnnotationTypeElementDocImpl)methodMap.get(meth); - if (result != null) { - if (treePath != null) result.setTreePath(treePath); - } else { - result = - new AnnotationTypeElementDocImpl(this, meth, treePath); - methodMap.put(meth, result); - } - } - - /** - * Return the AnnotationTypeElementDoc for a MethodSymbol. - * Should be called only on symbols representing annotation type elements. - */ - public AnnotationTypeElementDocImpl getAnnotationTypeElementDoc( - MethodSymbol meth) { - - AnnotationTypeElementDocImpl result = - (AnnotationTypeElementDocImpl)methodMap.get(meth); - if (result != null) return result; - result = new AnnotationTypeElementDocImpl(this, meth); - methodMap.put(meth, result); - return result; - } - -// private Map parameterizedTypeMap = -// new HashMap(); - /** - * Return the ParameterizedType of this instantiation. -// * ### Could use Type.sameTypeAs() instead of equality matching in hashmap -// * ### to avoid some duplication. - */ - ParameterizedTypeImpl getParameterizedType(ClassType t) { - return new ParameterizedTypeImpl(this, t); -// ParameterizedTypeImpl result = parameterizedTypeMap.get(t); -// if (result != null) return result; -// result = new ParameterizedTypeImpl(this, t); -// parameterizedTypeMap.put(t, result); -// return result; - } - - TreePath getTreePath(JCCompilationUnit tree) { - TreePath p = treePaths.get(tree); - if (p == null) - treePaths.put(tree, p = new TreePath(tree)); - return p; - } - - TreePath getTreePath(JCCompilationUnit toplevel, JCPackageDecl tree) { - TreePath p = treePaths.get(tree); - if (p == null) - treePaths.put(tree, p = new TreePath(getTreePath(toplevel), tree)); - return p; - } - - TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl tree) { - TreePath p = treePaths.get(tree); - if (p == null) - treePaths.put(tree, p = new TreePath(getTreePath(toplevel), tree)); - return p; - } - - TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl cdecl, JCTree tree) { - return new TreePath(getTreePath(toplevel, cdecl), tree); - } - - /** - * Set the encoding. - */ - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - /** - * Get the encoding. - */ - public String getEncoding() { - return encoding; - } - - /** - * Convert modifier bits from private coding used by - * the compiler to that of java.lang.reflect.Modifier. - */ - static int translateModifiers(long flags) { - int result = 0; - if ((flags & Flags.ABSTRACT) != 0) - result |= Modifier.ABSTRACT; - if ((flags & Flags.FINAL) != 0) - result |= Modifier.FINAL; - if ((flags & Flags.INTERFACE) != 0) - result |= Modifier.INTERFACE; - if ((flags & Flags.NATIVE) != 0) - result |= Modifier.NATIVE; - if ((flags & Flags.PRIVATE) != 0) - result |= Modifier.PRIVATE; - if ((flags & Flags.PROTECTED) != 0) - result |= Modifier.PROTECTED; - if ((flags & Flags.PUBLIC) != 0) - result |= Modifier.PUBLIC; - if ((flags & Flags.STATIC) != 0) - result |= Modifier.STATIC; - if ((flags & Flags.SYNCHRONIZED) != 0) - result |= Modifier.SYNCHRONIZED; - if ((flags & Flags.TRANSIENT) != 0) - result |= Modifier.TRANSIENT; - if ((flags & Flags.VOLATILE) != 0) - result |= Modifier.VOLATILE; - return result; - } - - void initDoclint(Collection opts, Collection customTagNames, String htmlVersion) { - ArrayList doclintOpts = new ArrayList<>(); - boolean msgOptionSeen = false; - - for (String opt : opts) { - if (opt.startsWith(DocLint.XMSGS_OPTION)) { - if (opt.equals(DocLint.XMSGS_CUSTOM_PREFIX + "none")) - return; - msgOptionSeen = true; - } - doclintOpts.add(opt); - } - - if (!msgOptionSeen) { - doclintOpts.add(DocLint.XMSGS_OPTION); - } - - String sep = ""; - StringBuilder customTags = new StringBuilder(); - for (String customTag : customTagNames) { - customTags.append(sep); - customTags.append(customTag); - sep = DocLint.SEPARATOR; - } - doclintOpts.add(DocLint.XCUSTOM_TAGS_PREFIX + customTags.toString()); - doclintOpts.add(DocLint.XHTML_VERSION_PREFIX + htmlVersion); - - JavacTask t = BasicJavacTask.instance(context); - doclint = new DocLint(); - // standard doclet normally generates H1, H2 - doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2"); - doclint.init(t, doclintOpts.toArray(new String[doclintOpts.size()]), false); - } - - boolean showTagMessages() { - return (doclint == null); - } - - Map shouldCheck = new HashMap<>(); - - boolean shouldCheck(CompilationUnitTree unit) { - return shouldCheck.computeIfAbsent(unit, doclint :: shouldCheck); - } -} --- /dev/null Fri Jan 22 12:20:56 2016 +++ new/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/DocEnv.java Fri Jan 22 12:20:55 2016 @@ -0,0 +1,847 @@ +/* + * Copyright (c) 2000, 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 jdk.javadoc.internal.tool; + + +import java.lang.reflect.Modifier; +import java.util.*; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.SimpleElementVisitor9; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; + +import com.sun.source.util.DocTrees; +import com.sun.source.util.TreePath; +import com.sun.tools.javac.api.JavacTrees; +import com.sun.tools.javac.code.ClassFinder; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Kinds.Kind; +import com.sun.tools.javac.code.Source; +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.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.Check; +import com.sun.tools.javac.comp.Enter; +import com.sun.tools.javac.comp.Env; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.model.JavacElements; +import com.sun.tools.javac.model.JavacTypes; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCPackageDecl; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.DefinedBy; +import com.sun.tools.javac.util.DefinedBy.Api; +import com.sun.tools.javac.util.Names; + +import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; + +/** + * Holds the environment for a run of javadoc. + * Holds only the information needed throughout the + * run and not the compiler info that could be GC'ed + * or ported. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @since 1.4 + * @author Robert Field + * @author Neal Gafter (rewrite) + * @author Scott Seligman (generics) + */ +public class DocEnv { + protected static final Context.Key docEnvKey = new Context.Key<>(); + + public static DocEnv instance(Context context) { + DocEnv instance = context.get(docEnvKey); + if (instance == null) + instance = new DocEnv(context); + return instance; + } + + private final Messager messager; + + /** Predefined symbols known to the compiler. */ + public final Symtab syms; + + /** Referenced directly in RootDocImpl. */ + private final ClassFinder finder; + + /** Javadoc's own version of the compiler's enter phase. */ + final Enter enter; + + /** The name table. */ + private Names names; + + /** The encoding name. */ + private String encoding; + + final Symbol externalizableSym; + + /** Access filter (public, protected, ...). */ + protected ModifierFilter filter; + + /** + * True if we do not want to print any notifications at all. + */ + boolean quiet = false; + + Check chk; + com.sun.tools.javac.code.Types types; + JavaFileManager fileManager; + public final Context context; + + WeakHashMap treePaths = new WeakHashMap<>(); + + public final HashMap pkgToJavaFOMap = new HashMap<>(); + + /** Allow documenting from class files? */ + boolean docClasses = false; + + /** + * The source language version. + */ + public final Source source; + + public final Elements elements; + + public final JavacTypes typeutils; + + protected RootDocImpl root; + + public final DocTrees docTrees; + + public final Map elementToTreePath; + + /** + * Constructor + * + * @param context Context for this javadoc instance. + */ + protected DocEnv(Context context) { + context.put(docEnvKey, this); + this.context = context; + + messager = Messager.instance0(context); + syms = Symtab.instance(context); + finder = JavadocClassFinder.instance(context); + enter = JavadocEnter.instance(context); + names = Names.instance(context); + externalizableSym = syms.enterClass(names.fromString("java.io.Externalizable")); + chk = Check.instance(context); + types = com.sun.tools.javac.code.Types.instance(context); + fileManager = context.get(JavaFileManager.class); + if (fileManager instanceof JavacFileManager) { + ((JavacFileManager)fileManager).setSymbolFileEnabled(false); + } + docTrees = JavacTrees.instance(context); + source = Source.instance(context); + elements = JavacElements.instance(context); + typeutils = JavacTypes.instance(context); + elementToTreePath = new HashMap<>(); + } + + public void intialize(String encoding, + String showAccess, + String overviewpath, + List javaNames, + Iterable fileObjects, + List subPackages, + List excludedPackages, + boolean docClasses, + boolean quiet) { + this.filter = ModifierFilter.getModifierFilter(showAccess); + this.quiet = quiet; + + this.setEncoding(encoding); + this.docClasses = docClasses; + } + + /** + * Load a class by qualified name. + */ + public TypeElement loadClass(String name) { + try { + ClassSymbol c = finder.loadClass(names.fromString(name)); + return c; + } catch (CompletionFailure ex) { + chk.completionError(null, ex); + return null; + } + } + + private boolean isSynthetic(long flags) { + return (flags & Flags.SYNTHETIC) != 0; + } + + private boolean isSynthetic(Symbol sym) { + return isSynthetic(sym.flags_field); + } + + SimpleElementVisitor9 shouldDocumentVisitor = null; + public boolean shouldDocument(Element e) { + if (shouldDocumentVisitor == null) { + shouldDocumentVisitor = new SimpleElementVisitor9() { + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitType(TypeElement e, Void p) { + return shouldDocument((ClassSymbol)e); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitVariable(VariableElement e, Void p) { + return shouldDocument((VarSymbol)e); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitExecutable(ExecutableElement e, Void p) { + return shouldDocument((MethodSymbol)e); + } + }; + } + return shouldDocumentVisitor.visit(e); + } + + /** Check whether this member should be documented. */ + public boolean shouldDocument(VarSymbol sym) { + long mod = sym.flags(); + if (isSynthetic(mod)) { + return false; + } + return filter.checkModifier(translateModifiers(mod)); + } + + /** Check whether this member should be documented. */ + public boolean shouldDocument(MethodSymbol sym) { + long mod = sym.flags(); + if (isSynthetic(mod)) { + return false; + } + return filter.checkModifier(translateModifiers(mod)); + } + + void setElementToTreePath(Element e, TreePath tree) { + if (e == null || tree == null) + return; + elementToTreePath.put(e, tree); + } + + private boolean hasLeaf(ClassSymbol sym) { + TreePath path = elementToTreePath.get(sym); + if (path == null) + return false; + return path.getLeaf() != null; + } + + /** check whether this class should be documented. */ + public boolean shouldDocument(ClassSymbol sym) { + return + !isSynthetic(sym.flags_field) && // no synthetics + (docClasses || hasLeaf(sym)) && + isVisible(sym); + } + + //### Comment below is inaccurate wrt modifier filter testing + /** + * Check the visibility if this is an nested class. + * if this is not a nested class, return true. + * if this is an static visible nested class, + * return true. + * if this is an visible nested class + * if the outer class is visible return true. + * else return false. + * IMPORTANT: This also allows, static nested classes + * to be defined inside an nested class, which is not + * allowed by the compiler. So such an test case will + * not reach upto this method itself, but if compiler + * allows it, then that will go through. + */ + public boolean isVisible(ClassSymbol sym) { + long mod = sym.flags_field; + if (!filter.checkModifier(translateModifiers(mod))) { + return false; + } + ClassSymbol encl = sym.owner.enclClass(); + return (encl == null || (mod & Flags.STATIC) != 0 || isVisible(encl)); + } + + //---------------- print forwarders ----------------// + + // ERRORS + /** + * Print error message, increment error count. + * + * @param msg message to print. + */ + public void printError(String msg) { + messager.printError(msg); + } + +// /** +// * Print error message, increment error count. +// * +// * @param key selects message from resource +// */ +// public void error(Element element, String key) { +// if (element == null) +// messager.error(key); +// else +// messager.error(element, key); +// } +// +// public void error(String prefix, String key) { +// printError(prefix + ":" + messager.getText(key)); +// } +// +// /** +// * Print error message, increment error count. +// * +// * @param path the path to the source +// * @param key selects message from resource +// */ +// public void error(DocTreePath path, String key) { +// messager.error(path, key); +// } +// +// /** +// * Print error message, increment error count. +// * +// * @param path the path to the source +// * @param msg message to print. +// */ +// public void printError(DocTreePath path, String msg) { +// messager.printError(path, msg); +// } +// +// /** +// * Print error message, increment error count. +// * @param e the target element +// * @param msg message to print. +// */ +// public void printError(Element e, String msg) { +// messager.printError(e, msg); +// } + + /** + * Print error message, increment error count. + * + * @param element the source element + * @param key selects message from resource + * @param args replacement arguments + */ + public void error(Element element, String key, String... args) { + if (element == null) + messager.error(key, (Object[]) args); + else + messager.error(element, key, (Object[]) args); + } + + // WARNINGS + +// /** +// * Print warning message, increment warning count. +// * +// * @param msg message to print. +// */ +// public void printWarning(String msg) { +// messager.printWarning(msg); +// } +// +// public void warning(String key) { +// warning((Element)null, key); +// } + + public void warning(String key, String... args) { + warning((Element)null, key, args); + } + +// /** +// * Print warning message, increment warning count. +// * +// * @param element the source element +// * @param key selects message from resource +// */ +// public void warning(Element element, String key) { +// if (element == null) +// messager.warning(key); +// else +// messager.warning(element, key); +// } +// +// /** +// * Print warning message, increment warning count. +// * +// * @param path the path to the source +// * @param msg message to print. +// */ +// public void printWarning(DocTreePath path, String msg) { +// messager.printWarning(path, msg); +// } +// +// /** +// * Print warning message, increment warning count. +// * +// * @param e the source element +// * @param msg message to print. +// */ +// public void printWarning(Element e, String msg) { +// messager.printWarning(e, msg); +// } + + /** + * Print warning message, increment warning count. + * + * @param e the source element + * @param key selects message from resource + * @param args the replace arguments + */ + public void warning(Element e, String key, String... args) { + if (e == null) + messager.warning(key, (Object[]) args); + else + messager.warning(e, key, (Object[]) args); + } + +// Note: no longer required +// /** +// * Print a message. +// * +// * @param msg message to print. +// */ +// public void printNotice(String msg) { +// if (quiet) { +// return; +// } +// messager.printNotice(msg); +// } + +// Note: no longer required +// /** +// * Print a message. +// * +// * @param e the source element +// * @param msg message to print. +// */ +// public void printNotice(Element e, String msg) { +// if (quiet) { +// return; +// } +// messager.printNotice(e, msg); +// } + + // NOTICES + /** + * Print a message. + * + * @param key selects message from resource + */ + public void notice(String key) { + if (quiet) { + return; + } + messager.notice(key); + } + +// Note: not used anymore +// /** +// * Print a message. +// * +// * @param path the path to the source +// * @param msg message to print. +// */ +// public void printNotice(DocTreePath path, String msg) { +// if (quiet) { +// return; +// } +// messager.printNotice(path, msg); +// } + + /** + * Print a message. + * + * @param key selects message from resource + * @param a1 first argument + */ + public void notice(String key, String a1) { + if (quiet) { + return; + } + messager.notice(key, a1); + } + +// Note: not used anymore +// /** +// * Print a message. +// * +// * @param key selects message from resource +// * @param a1 first argument +// * @param a2 second argument +// */ +// public void notice(String key, String a1, String a2) { +// if (quiet) { +// return; +// } +// messager.notice(key, a1, a2); +// } +// + +// Note: not used anymore +// /** +// * Print a message. +// * +// * @param key selects message from resource +// * @param a1 first argument +// * @param a2 second argument +// * @param a3 third argument +// */ +// public void notice(String key, String a1, String a2, String a3) { +// if (quiet) { +// return; +// } +// messager.notice(key, a1, a2, a3); +// } + + /** + * Exit, reporting errors and warnings. + */ + public void exit() { + // Messager should be replaced by a more general + // compilation environment. This can probably + // subsume DocEnv as well. + messager.exit(); + } + + /** + * Adds all inner classes of this class, and their inner classes recursively, to the list + */ + void addAllClasses(Collection list, TypeElement typeElement, boolean filtered) { + ClassSymbol klass = (ClassSymbol)typeElement; + try { + if (isSynthetic(klass.flags())) return; + // sometimes synthetic classes are not marked synthetic + if (!JavadocTool.isValidClassName(klass.name.toString())) return; + if (filtered && !shouldDocument(klass)) return; + if (list.contains(klass)) return; + list.add(klass); + for (Symbol sym : klass.members().getSymbols(NON_RECURSIVE)) { + if (sym != null && sym.kind == Kind.TYP) { + ClassSymbol s = (ClassSymbol)sym; + if (!isSynthetic(s.flags())) { + addAllClasses(list, s, filtered); + } + } + } + } catch (CompletionFailure e) { + // quietly ignore completion failures + } + } + + /** + * Return a list of all classes contained in this package, including + * member classes of those classes, and their member classes, etc. + */ + void addAllClasses(Collection list, PackageElement pkg) { + boolean filtered = true; + PackageSymbol sym = (PackageSymbol)pkg; + for (Symbol isym : sym.members().getSymbols(NON_RECURSIVE)) { + if (isym != null) { + ClassSymbol s = (ClassSymbol)isym; + if (!isSynthetic(s)) { + addAllClasses(list, s, filtered); + } + } + } + } + + TreePath getTreePath(JCCompilationUnit tree) { + TreePath p = treePaths.get(tree); + if (p == null) + treePaths.put(tree, p = new TreePath(tree)); + return p; + } + + TreePath getTreePath(JCCompilationUnit toplevel, JCPackageDecl tree) { + TreePath p = treePaths.get(tree); + if (p == null) + treePaths.put(tree, p = new TreePath(getTreePath(toplevel), tree)); + return p; + } + + TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl tree) { + TreePath p = treePaths.get(tree); + if (p == null) + treePaths.put(tree, p = new TreePath(getTreePath(toplevel), tree)); + return p; + } + + TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl cdecl, JCTree tree) { + return new TreePath(getTreePath(toplevel, cdecl), tree); + } + + public com.sun.tools.javac.code.Types getTypes() { + return types; + } + + /** + * Set the encoding. + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public Env getEnv(ClassSymbol tsym) { + return enter.getEnv(tsym); + } + + /** + * Get the encoding. + */ + public String getEncoding() { + return encoding; + } + + /** + * Convert modifier bits from private coding used by + * the compiler to that of java.lang.reflect.Modifier. + */ + static int translateModifiers(long flags) { + int result = 0; + if ((flags & Flags.ABSTRACT) != 0) + result |= Modifier.ABSTRACT; + if ((flags & Flags.FINAL) != 0) + result |= Modifier.FINAL; + if ((flags & Flags.INTERFACE) != 0) + result |= Modifier.INTERFACE; + if ((flags & Flags.NATIVE) != 0) + result |= Modifier.NATIVE; + if ((flags & Flags.PRIVATE) != 0) + result |= Modifier.PRIVATE; + if ((flags & Flags.PROTECTED) != 0) + result |= Modifier.PROTECTED; + if ((flags & Flags.PUBLIC) != 0) + result |= Modifier.PUBLIC; + if ((flags & Flags.STATIC) != 0) + result |= Modifier.STATIC; + if ((flags & Flags.SYNCHRONIZED) != 0) + result |= Modifier.SYNCHRONIZED; + if ((flags & Flags.TRANSIENT) != 0) + result |= Modifier.TRANSIENT; + if ((flags & Flags.VOLATILE) != 0) + result |= Modifier.VOLATILE; + return result; + } + + private final Set includedSet = new HashSet<>(); + + public void setIncluded(Element element) { + includedSet.add(element); + } + + private SimpleElementVisitor9 includedVisitor = null; + + public boolean isIncluded(Element e) { + if (e == null) { + return false; + } + if (includedVisitor == null) { + includedVisitor = new SimpleElementVisitor9() { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitType(TypeElement e, Void p) { + if (includedSet.contains(e)) { + return true; + } + if (shouldDocument(e)) { + // Class is nameable from top-level and + // the class and all enclosing classes + // pass the modifier filter. + PackageElement pkg = elements.getPackageOf(e); + if (includedSet.contains(pkg)) { + setIncluded(e); + return true; + } + Element enclosing = e.getEnclosingElement(); + if (enclosing != null && includedSet.contains(enclosing)) { + setIncluded(e); + return true; + } + } + return false; + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean defaultAction(Element e, Void p) { + if (includedSet.contains(e) || shouldDocument(e)) { + return true; + } + return false; + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitPackage(PackageElement e, Void p) { + return includedSet.contains(e); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Boolean visitUnknown(Element e, Void p) { + throw new AssertionError("got element: " + e); + } + }; + } + return includedVisitor.visit(e); + } + + public boolean isQuiet() { + return quiet; + } + + /** + * A class which filters the access flags on classes, fields, methods, etc. + * + *

+ * This is NOT part of any supported API. If you write code that depends on this, you do so + * at your own risk. This code and its internal interfaces are subject to change or deletion + * without notice. + * + * @see javax.lang.model.element.Modifier + * @author Robert Field + */ + + private static class ModifierFilter { + + static enum FilterFlag { + PACKAGE, + PRIVATE, + PROTECTED, + PUBLIC + } + + private Set oneOf; + + /** + * Constructor - Specify a filter. + * + * @param oneOf a set containing desired flags to be matched. + */ + ModifierFilter(Set oneOf) { + this.oneOf = oneOf; + } + + /** + * Constructor - Specify a filter. + * + * @param oneOf an array containing desired flags to be matched. + */ + ModifierFilter(FilterFlag... oneOf) { + this.oneOf = new HashSet<>(); + this.oneOf.addAll(Arrays.asList(oneOf)); + } + + static ModifierFilter getModifierFilter(String showAccess) { + switch (showAccess) { + case "public": + return new ModifierFilter(FilterFlag.PUBLIC); + case "package": + return new ModifierFilter(FilterFlag.PUBLIC, FilterFlag.PROTECTED, + FilterFlag.PACKAGE); + case "private": + return new ModifierFilter(FilterFlag.PRIVATE); + default: + return new ModifierFilter(FilterFlag.PUBLIC, FilterFlag.PROTECTED); + } + } + + private boolean hasFlag(long flag, long modifierBits) { + return (flag & modifierBits) != 0; + } + + private List flagsToModifiers(long modifierBits) { + List list = new ArrayList<>(); + boolean isPackage = true; + if (hasFlag(com.sun.tools.javac.code.Flags.PRIVATE, modifierBits)) { + list.add(FilterFlag.PRIVATE); + isPackage = false; + } + if (hasFlag(com.sun.tools.javac.code.Flags.PROTECTED, modifierBits)) { + list.add(FilterFlag.PROTECTED); + isPackage = false; + } + if (hasFlag(com.sun.tools.javac.code.Flags.PUBLIC, modifierBits)) { + list.add(FilterFlag.PUBLIC); + isPackage = false; + } + if (isPackage) { + list.add(FilterFlag.PACKAGE); + } + return list; + } + + /** + * Filter on modifier bits. + * + * @param modifierBits Bits as specified in the Modifier class + * + * @return Whether the modifierBits pass this filter. + */ + public boolean checkModifier(int modifierBits) { + return checkModifier(flagsToModifiers(modifierBits)); + } + + /** + * Filter on Filter flags + * + * @param modifiers Flags as specified in the FilterFlags enumeration. + * + * @return if the modifier is contained. + */ + public boolean checkModifier(List modifiers) { + if (oneOf.contains(FilterFlag.PRIVATE)) { + return true; + } + for (FilterFlag mod : modifiers) { + if (oneOf.contains(mod)) { + return true; + } + } + return false; + } + + } // end ModifierFilter +}