src/share/classes/com/sun/tools/javadoc/JavadocTool.java

Fri, 05 Aug 2011 19:41:05 -0700

author
ksrini
date
Fri, 05 Aug 2011 19:41:05 -0700
changeset 1065
e9f118c2bd3c
parent 695
3c9b64e55c5d
child 1094
dea82aa3ca4f
permissions
-rw-r--r--

7064544: (javadoc) miscellaneous fixes requested by netbeans
Summary: Contributed by netbeans team, modified to suit by the langtools team.
Reviewed-by: jjg, bpatel

     1 /*
     2  * Copyright (c) 2001, 2010, 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javadoc;
    28 import java.io.File;
    29 import java.io.IOException;
    30 import java.util.Collection;
    31 import java.util.EnumSet;
    32 import java.util.HashMap;
    33 import java.util.Map;
    34 import java.util.Set;
    35 import javax.tools.JavaFileManager.Location;
    36 import javax.tools.JavaFileObject;
    37 import javax.tools.StandardJavaFileManager;
    38 import javax.tools.StandardLocation;
    40 import com.sun.tools.javac.code.Symbol.CompletionFailure;
    41 import com.sun.tools.javac.comp.Annotate;
    42 import com.sun.tools.javac.parser.DocCommentScanner;
    43 import com.sun.tools.javac.tree.JCTree;
    44 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
    45 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
    46 import com.sun.tools.javac.util.Abort;
    47 import com.sun.tools.javac.util.Context;
    48 import com.sun.tools.javac.util.List;
    49 import com.sun.tools.javac.util.ListBuffer;
    50 import com.sun.tools.javac.util.Position;
    53 /**
    54  *  This class could be the main entry point for Javadoc when Javadoc is used as a
    55  *  component in a larger software system. It provides operations to
    56  *  construct a new javadoc processor, and to run it on a set of source
    57  *  files.
    58  *  @author Neal Gafter
    59  */
    60 public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
    61     DocEnv docenv;
    63     final Context context;
    64     final Messager messager;
    65     final JavadocClassReader reader;
    66     final JavadocEnter enter;
    67     final Annotate annotate;
    69     /**
    70      * Construct a new JavaCompiler processor, using appropriately
    71      * extended phases of the underlying compiler.
    72      */
    73     protected JavadocTool(Context context) {
    74         super(context);
    75         this.context = context;
    76         messager = Messager.instance0(context);
    77         reader = JavadocClassReader.instance0(context);
    78         enter = JavadocEnter.instance0(context);
    79         annotate = Annotate.instance(context);
    80     }
    82     /**
    83      * For javadoc, the parser needs to keep comments. Overrides method from JavaCompiler.
    84      */
    85     protected boolean keepComments() {
    86         return true;
    87     }
    89     /**
    90      *  Construct a new javadoc tool.
    91      */
    92     public static JavadocTool make0(Context context) {
    93         Messager messager = null;
    94         try {
    95             // force the use of Javadoc's class reader
    96             JavadocClassReader.preRegister(context);
    98             // force the use of Javadoc's own enter phase
    99             JavadocEnter.preRegister(context);
   101             // force the use of Javadoc's own member enter phase
   102             JavadocMemberEnter.preRegister(context);
   104             // force the use of Javadoc's own todo phase
   105             JavadocTodo.preRegister(context);
   107             // force the use of Messager as a Log
   108             messager = Messager.instance0(context);
   110             return new JavadocTool(context);
   111         } catch (CompletionFailure ex) {
   112             messager.error(Position.NOPOS, ex.getMessage());
   113             return null;
   114         }
   115     }
   117     public RootDocImpl getRootDocImpl(String doclocale,
   118                                       String encoding,
   119                                       ModifierFilter filter,
   120                                       List<String> javaNames,
   121                                       List<String[]> options,
   122                                       boolean breakiterator,
   123                                       List<String> subPackages,
   124                                       List<String> excludedPackages,
   125                                       boolean docClasses,
   126                                       boolean legacyDoclet,
   127                       boolean quiet) throws IOException {
   128         docenv = DocEnv.instance(context);
   129         docenv.showAccess = filter;
   130         docenv.quiet = quiet;
   131         docenv.breakiterator = breakiterator;
   132         docenv.setLocale(doclocale);
   133         docenv.setEncoding(encoding);
   134         docenv.docClasses = docClasses;
   135         docenv.legacyDoclet = legacyDoclet;
   136         reader.sourceCompleter = docClasses ? null : this;
   138         ListBuffer<String> names = new ListBuffer<String>();
   139         ListBuffer<JCCompilationUnit> classTrees = new ListBuffer<JCCompilationUnit>();
   140         ListBuffer<JCCompilationUnit> packTrees = new ListBuffer<JCCompilationUnit>();
   142         try {
   143             StandardJavaFileManager fm = (StandardJavaFileManager) docenv.fileManager;
   144             for (List<String> it = javaNames; it.nonEmpty(); it = it.tail) {
   145                 String name = it.head;
   146                 if (!docClasses && name.endsWith(".java") && new File(name).exists()) {
   147                     JavaFileObject fo = fm.getJavaFileObjects(name).iterator().next();
   148                     docenv.notice("main.Loading_source_file", name);
   149                     JCCompilationUnit tree = parse(fo);
   150                     classTrees.append(tree);
   151                 } else if (isValidPackageName(name)) {
   152                     names = names.append(name);
   153                 } else if (name.endsWith(".java")) {
   154                     docenv.error(null, "main.file_not_found", name);
   155                 } else {
   156                     docenv.error(null, "main.illegal_package_name", name);
   157                 }
   158             }
   160             if (!docClasses) {
   161                 // Recursively search given subpackages.  If any packages
   162                 //are found, add them to the list.
   163                 Map<String,List<JavaFileObject>> packageFiles =
   164                         searchSubPackages(subPackages, names, excludedPackages);
   166                 // Parse the packages
   167                 for (List<String> packs = names.toList(); packs.nonEmpty(); packs = packs.tail) {
   168                     // Parse sources ostensibly belonging to package.
   169                     String packageName = packs.head;
   170                     parsePackageClasses(packageName, packageFiles.get(packageName), packTrees, excludedPackages);
   171                 }
   173                 if (messager.nerrors() != 0) return null;
   175                 // Enter symbols for all files
   176                 docenv.notice("main.Building_tree");
   177                 enter.main(classTrees.toList().appendList(packTrees.toList()));
   178             }
   179         } catch (Abort ex) {}
   181         if (messager.nerrors() != 0)
   182             return null;
   184         if (docClasses)
   185             return new RootDocImpl(docenv, javaNames, options);
   186         else
   187             return new RootDocImpl(docenv, listClasses(classTrees.toList()), names.toList(), options);
   188     }
   190     /** Is the given string a valid package name? */
   191     boolean isValidPackageName(String s) {
   192         int index;
   193         while ((index = s.indexOf('.')) != -1) {
   194             if (!isValidClassName(s.substring(0, index))) return false;
   195             s = s.substring(index+1);
   196         }
   197         return isValidClassName(s);
   198     }
   200     /**
   201      * search all directories in path for subdirectory name. Add all
   202      * .java files found in such a directory to args.
   203      */
   204     private void parsePackageClasses(String name,
   205             Iterable<JavaFileObject> files,
   206             ListBuffer<JCCompilationUnit> trees,
   207             List<String> excludedPackages)
   208             throws IOException {
   209         if (excludedPackages.contains(name)) {
   210             return;
   211         }
   213         boolean hasFiles = false;
   214         docenv.notice("main.Loading_source_files_for_package", name);
   216         if (files == null) {
   217             Location location = docenv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
   218                     ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;
   219             ListBuffer<JavaFileObject> lb = new ListBuffer<JavaFileObject>();
   220             for (JavaFileObject fo: docenv.fileManager.list(
   221                     location, name, EnumSet.of(JavaFileObject.Kind.SOURCE), false)) {
   222                 String binaryName = docenv.fileManager.inferBinaryName(location, fo);
   223                 String simpleName = getSimpleName(binaryName);
   224                 if (isValidClassName(simpleName)) {
   225                     lb.append(fo);
   226                 }
   227             }
   228             files = lb.toList();
   229         }
   231         for (JavaFileObject fo : files) {
   232             // messager.notice("main.Loading_source_file", fn);
   233             trees.append(parse(fo));
   234             hasFiles = true;
   235         }
   237         if (!hasFiles) {
   238             messager.warning(null, "main.no_source_files_for_package",
   239                     name.replace(File.separatorChar, '.'));
   240         }
   241     }
   243     /**
   244      * Recursively search all directories in path for subdirectory name.
   245      * Add all packages found in such a directory to packages list.
   246      */
   247     private Map<String,List<JavaFileObject>> searchSubPackages(
   248             List<String> subPackages,
   249             ListBuffer<String> packages,
   250             List<String> excludedPackages)
   251             throws IOException {
   252         Map<String,List<JavaFileObject>> packageFiles =
   253                 new HashMap<String,List<JavaFileObject>>();
   255         Map<String,Boolean> includedPackages = new HashMap<String,Boolean>();
   256         includedPackages.put("", true);
   257         for (String p: excludedPackages)
   258             includedPackages.put(p, false);
   260         if (docenv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)) {
   261             searchSubPackages(subPackages,
   262                     includedPackages,
   263                     packages, packageFiles,
   264                     StandardLocation.SOURCE_PATH,
   265                     EnumSet.of(JavaFileObject.Kind.SOURCE));
   266             searchSubPackages(subPackages,
   267                     includedPackages,
   268                     packages, packageFiles,
   269                     StandardLocation.CLASS_PATH,
   270                     EnumSet.of(JavaFileObject.Kind.CLASS));
   271         } else {
   272             searchSubPackages(subPackages,
   273                     includedPackages,
   274                     packages, packageFiles,
   275                     StandardLocation.CLASS_PATH,
   276                     EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS));
   277         }
   278         return packageFiles;
   279     }
   281     private void searchSubPackages(List<String> subPackages,
   282             Map<String,Boolean> includedPackages,
   283             ListBuffer<String> packages,
   284             Map<String, List<JavaFileObject>> packageFiles,
   285             StandardLocation location, Set<JavaFileObject.Kind> kinds)
   286             throws IOException {
   287         for (String subPackage: subPackages) {
   288             if (!isIncluded(subPackage, includedPackages))
   289                 continue;
   291             for (JavaFileObject fo: docenv.fileManager.list(location, subPackage, kinds, true)) {
   292                 String binaryName = docenv.fileManager.inferBinaryName(location, fo);
   293                 String packageName = getPackageName(binaryName);
   294                 String simpleName = getSimpleName(binaryName);
   295                 if (isIncluded(packageName, includedPackages) && isValidClassName(simpleName)) {
   296                     List<JavaFileObject> list = packageFiles.get(packageName);
   297                     list = (list == null ? List.of(fo) : list.prepend(fo));
   298                     packageFiles.put(packageName, list);
   299                     if (!packages.contains(packageName))
   300                         packages.add(packageName);
   301                 }
   302             }
   303         }
   304     }
   306     private String getPackageName(String name) {
   307         int lastDot = name.lastIndexOf(".");
   308         return (lastDot == -1 ? "" : name.substring(0, lastDot));
   309     }
   311     private String getSimpleName(String name) {
   312         int lastDot = name.lastIndexOf(".");
   313         return (lastDot == -1 ? name : name.substring(lastDot + 1));
   314     }
   316     private boolean isIncluded(String packageName, Map<String,Boolean> includedPackages) {
   317         Boolean b = includedPackages.get(packageName);
   318         if (b == null) {
   319             b = isIncluded(getPackageName(packageName), includedPackages);
   320             includedPackages.put(packageName, b);
   321         }
   322         return b;
   323     }
   325     /**
   326      * Recursively search all directories in path for subdirectory name.
   327      * Add all packages found in such a directory to packages list.
   328      */
   329     private void searchSubPackage(String packageName,
   330                                   ListBuffer<String> packages,
   331                                   List<String> excludedPackages,
   332                                   Collection<File> pathnames) {
   333         if (excludedPackages.contains(packageName))
   334             return;
   336         String packageFilename = packageName.replace('.', File.separatorChar);
   337         boolean addedPackage = false;
   338         for (File pathname : pathnames) {
   339             File f = new File(pathname, packageFilename);
   340             String filenames[] = f.list();
   341             // if filenames not null, then found directory
   342             if (filenames != null) {
   343                 for (String filename : filenames) {
   344                     if (!addedPackage
   345                             && (isValidJavaSourceFile(filename) ||
   346                                 isValidJavaClassFile(filename))
   347                             && !packages.contains(packageName)) {
   348                         packages.append(packageName);
   349                         addedPackage = true;
   350                     } else if (isValidClassName(filename) &&
   351                                (new File(f, filename)).isDirectory()) {
   352                         searchSubPackage(packageName + "." + filename,
   353                                          packages, excludedPackages, pathnames);
   354                     }
   355                 }
   356             }
   357         }
   358     }
   360     /**
   361      * Return true if given file name is a valid class file name.
   362      * @param file the name of the file to check.
   363      * @return true if given file name is a valid class file name
   364      * and false otherwise.
   365      */
   366     private static boolean isValidJavaClassFile(String file) {
   367         if (!file.endsWith(".class")) return false;
   368         String clazzName = file.substring(0, file.length() - ".class".length());
   369         return isValidClassName(clazzName);
   370     }
   372     /**
   373      * Return true if given file name is a valid Java source file name.
   374      * @param file the name of the file to check.
   375      * @return true if given file name is a valid Java source file name
   376      * and false otherwise.
   377      */
   378     private static boolean isValidJavaSourceFile(String file) {
   379         if (!file.endsWith(".java")) return false;
   380         String clazzName = file.substring(0, file.length() - ".java".length());
   381         return isValidClassName(clazzName);
   382     }
   384     /** Are surrogates supported?
   385      */
   386     final static boolean surrogatesSupported = surrogatesSupported();
   387     private static boolean surrogatesSupported() {
   388         try {
   389             boolean b = Character.isHighSurrogate('a');
   390             return true;
   391         } catch (NoSuchMethodError ex) {
   392             return false;
   393         }
   394     }
   396     /**
   397      * Return true if given file name is a valid class name
   398      * (including "package-info").
   399      * @param clazzname the name of the class to check.
   400      * @return true if given class name is a valid class name
   401      * and false otherwise.
   402      */
   403     public static boolean isValidClassName(String s) {
   404         if (s.length() < 1) return false;
   405         if (s.equals("package-info")) return true;
   406         if (surrogatesSupported) {
   407             int cp = s.codePointAt(0);
   408             if (!Character.isJavaIdentifierStart(cp))
   409                 return false;
   410             for (int j=Character.charCount(cp); j<s.length(); j+=Character.charCount(cp)) {
   411                 cp = s.codePointAt(j);
   412                 if (!Character.isJavaIdentifierPart(cp))
   413                     return false;
   414             }
   415         } else {
   416             if (!Character.isJavaIdentifierStart(s.charAt(0)))
   417                 return false;
   418             for (int j=1; j<s.length(); j++)
   419                 if (!Character.isJavaIdentifierPart(s.charAt(j)))
   420                     return false;
   421         }
   422         return true;
   423     }
   425     /**
   426      * From a list of top level trees, return the list of contained class definitions
   427      */
   428     List<JCClassDecl> listClasses(List<JCCompilationUnit> trees) {
   429         ListBuffer<JCClassDecl> result = new ListBuffer<JCClassDecl>();
   430         for (JCCompilationUnit t : trees) {
   431             for (JCTree def : t.defs) {
   432                 if (def.getTag() == JCTree.CLASSDEF)
   433                     result.append((JCClassDecl)def);
   434             }
   435         }
   436         return result.toList();
   437     }
   439 }

mercurial