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

Thu, 18 Sep 2008 18:39:44 -0700

author
jjg
date
Thu, 18 Sep 2008 18:39:44 -0700
changeset 115
829dea15ff99
parent 54
eaf608c64fec
child 197
1bf037016426
permissions
-rw-r--r--

6744408: Extra ouput is appearing in stderr
Reviewed-by: bpatel

     1 /*
     2  * Copyright 2001-2008 Sun Microsystems, Inc.  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.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.tools.javadoc;
    28 import java.io.*;
    30 import java.util.Collection;
    32 import com.sun.tools.javac.code.Symbol.*;
    33 import com.sun.tools.javac.comp.*;
    34 import com.sun.tools.javac.file.Paths;
    35 import com.sun.tools.javac.parser.DocCommentScanner;
    36 import com.sun.tools.javac.tree.*;
    37 import com.sun.tools.javac.tree.JCTree.*;
    38 import com.sun.tools.javac.util.*;
    41 /**
    42  *  This class could be the main entry point for Javadoc when Javadoc is used as a
    43  *  component in a larger software system. It provides operations to
    44  *  construct a new javadoc processor, and to run it on a set of source
    45  *  files.
    46  *  @author Neal Gafter
    47  */
    48 public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
    49     DocEnv docenv;
    51     final Context context;
    52     final Messager messager;
    53     final JavadocClassReader reader;
    54     final JavadocEnter enter;
    55     final Annotate annotate;
    56     private final Paths paths;
    58     /**
    59      * Construct a new JavaCompiler processor, using appropriately
    60      * extended phases of the underlying compiler.
    61      */
    62     protected JavadocTool(Context context) {
    63         super(context);
    64         this.context = context;
    65         messager = Messager.instance0(context);
    66         reader = JavadocClassReader.instance0(context);
    67         enter = JavadocEnter.instance0(context);
    68         annotate = Annotate.instance(context);
    69         paths = Paths.instance(context);
    70     }
    72     /**
    73      * For javadoc, the parser needs to keep comments. Overrides method from JavaCompiler.
    74      */
    75     protected boolean keepComments() {
    76         return true;
    77     }
    79     /**
    80      *  Construct a new javadoc tool.
    81      */
    82     public static JavadocTool make0(Context context) {
    83         Messager messager = null;
    84         try {
    85             // force the use of Javadoc's class reader
    86             JavadocClassReader.preRegister(context);
    88             // force the use of Javadoc's own enter phase
    89             JavadocEnter.preRegister(context);
    91             // force the use of Javadoc's own member enter phase
    92             JavadocMemberEnter.preRegister(context);
    94             // force the use of Javadoc's own todo phase
    95             JavadocTodo.preRegister(context);
    97             // force the use of Messager as a Log
    98             messager = Messager.instance0(context);
   100             // force the use of the scanner that captures Javadoc comments
   101             DocCommentScanner.Factory.preRegister(context);
   103             return new JavadocTool(context);
   104         } catch (CompletionFailure ex) {
   105             messager.error(Position.NOPOS, ex.getMessage());
   106             return null;
   107         }
   108     }
   110     public RootDocImpl getRootDocImpl(String doclocale,
   111                                       String encoding,
   112                                       ModifierFilter filter,
   113                                       List<String> javaNames,
   114                                       List<String[]> options,
   115                                       boolean breakiterator,
   116                                       List<String> subPackages,
   117                                       List<String> excludedPackages,
   118                                       boolean docClasses,
   119                                       boolean legacyDoclet,
   120                       boolean quiet) throws IOException {
   121         docenv = DocEnv.instance(context);
   122         docenv.showAccess = filter;
   123     docenv.quiet = quiet;
   124         docenv.breakiterator = breakiterator;
   125         docenv.setLocale(doclocale);
   126         docenv.setEncoding(encoding);
   127         docenv.docClasses = docClasses;
   128         docenv.legacyDoclet = legacyDoclet;
   129         reader.sourceCompleter = docClasses ? null : this;
   131         ListBuffer<String> names = new ListBuffer<String>();
   132         ListBuffer<JCCompilationUnit> classTrees = new ListBuffer<JCCompilationUnit>();
   133         ListBuffer<JCCompilationUnit> packTrees = new ListBuffer<JCCompilationUnit>();
   135         try {
   136             for (List<String> it = javaNames; it.nonEmpty(); it = it.tail) {
   137                 String name = it.head;
   138                 if (!docClasses && name.endsWith(".java") && new File(name).exists()) {
   139                     docenv.notice("main.Loading_source_file", name);
   140                         JCCompilationUnit tree = parse(name);
   141                         classTrees.append(tree);
   142                 } else if (isValidPackageName(name)) {
   143                     names = names.append(name);
   144                 } else if (name.endsWith(".java")) {
   145                     docenv.error(null, "main.file_not_found", name);
   146                 } else {
   147                     docenv.error(null, "main.illegal_package_name", name);
   148                 }
   149             }
   151             if (!docClasses) {
   152                 // Recursively search given subpackages.  If any packages
   153                 //are found, add them to the list.
   154                 searchSubPackages(subPackages, names, excludedPackages);
   156                 // Parse the packages
   157                 for (List<String> packs = names.toList(); packs.nonEmpty(); packs = packs.tail) {
   158                     // Parse sources ostensibly belonging to package.
   159                     parsePackageClasses(packs.head, packTrees, excludedPackages);
   160                 }
   162                 if (messager.nerrors() != 0) return null;
   164                 // Enter symbols for all files
   165                 docenv.notice("main.Building_tree");
   166                 enter.main(classTrees.toList().appendList(packTrees.toList()));
   167             }
   168         } catch (Abort ex) {}
   170         if (messager.nerrors() != 0) return null;
   172         if (docClasses)
   173             return new RootDocImpl(docenv, javaNames, options);
   174         else
   175             return new RootDocImpl(docenv, listClasses(classTrees.toList()), names.toList(), options);
   176     }
   178     /** Is the given string a valid package name? */
   179     boolean isValidPackageName(String s) {
   180         int index;
   181         while ((index = s.indexOf('.')) != -1) {
   182             if (!isValidClassName(s.substring(0, index))) return false;
   183             s = s.substring(index+1);
   184         }
   185         return isValidClassName(s);
   186     }
   189     private final static char pathSep = File.pathSeparatorChar;
   191     /**
   192      * search all directories in path for subdirectory name. Add all
   193      * .java files found in such a directory to args.
   194      */
   195     private void parsePackageClasses(String name,
   196                                      ListBuffer<JCCompilationUnit> trees,
   197                                      List<String> excludedPackages)
   198         throws IOException {
   199         if (excludedPackages.contains(name)) {
   200             return;
   201         }
   202         boolean hasFiles = false;
   203         docenv.notice("main.Loading_source_files_for_package", name);
   204         name = name.replace('.', File.separatorChar);
   205         for (File pathname : paths.sourceSearchPath()) {
   206             File f = new File(pathname, name);
   207             String names[] = f.list();
   208             // if names not null, then found directory with source files
   209             if (names != null) {
   210                 String dir = f.getAbsolutePath();
   211                 if (!dir.endsWith(File.separator))
   212                     dir = dir + File.separator;
   213                 for (int j = 0; j < names.length; j++) {
   214                     if (isValidJavaSourceFile(names[j])) {
   215                         String fn = dir + names[j];
   216                         // messager.notice("main.Loading_source_file", fn);
   217                             trees.append(parse(fn));
   218                         hasFiles = true;
   219                     }
   220                 }
   221             }
   222         }
   223         if (!hasFiles)
   224             messager.warning(null, "main.no_source_files_for_package",
   225                              name.replace(File.separatorChar, '.'));
   226     }
   228     /**
   229      * Recursively search all directories in path for subdirectory name.
   230      * Add all packages found in such a directory to packages list.
   231      */
   232     private void searchSubPackages(List<String> subPackages,
   233                                    ListBuffer<String> packages,
   234                                    List<String> excludedPackages) {
   235         // FIXME: This search path is bogus.
   236         // Only the effective source path should be searched for sources.
   237         // Only the effective class path should be searched for classes.
   238         // Should the bootclasspath/extdirs also be searched for classes?
   239         java.util.List<File> pathnames = new java.util.ArrayList<File>();
   240         if (paths.sourcePath() != null)
   241             for (File elt : paths.sourcePath())
   242                 pathnames.add(elt);
   243         for (File elt : paths.userClassPath())
   244             pathnames.add(elt);
   246         for (String subPackage : subPackages)
   247             searchSubPackage(subPackage, packages, excludedPackages, pathnames);
   248     }
   250     /**
   251      * Recursively search all directories in path for subdirectory name.
   252      * Add all packages found in such a directory to packages list.
   253      */
   254     private void searchSubPackage(String packageName,
   255                                   ListBuffer<String> packages,
   256                                   List<String> excludedPackages,
   257                                   Collection<File> pathnames) {
   258         if (excludedPackages.contains(packageName))
   259             return;
   261         String packageFilename = packageName.replace('.', File.separatorChar);
   262         boolean addedPackage = false;
   263         for (File pathname : pathnames) {
   264             File f = new File(pathname, packageFilename);
   265             String filenames[] = f.list();
   266             // if filenames not null, then found directory
   267             if (filenames != null) {
   268                 for (String filename : filenames) {
   269                     if (!addedPackage
   270                             && (isValidJavaSourceFile(filename) ||
   271                                 isValidJavaClassFile(filename))
   272                             && !packages.contains(packageName)) {
   273                         packages.append(packageName);
   274                         addedPackage = true;
   275                     } else if (isValidClassName(filename) &&
   276                                (new File(f, filename)).isDirectory()) {
   277                         searchSubPackage(packageName + "." + filename,
   278                                          packages, excludedPackages, pathnames);
   279                     }
   280                 }
   281             }
   282         }
   283     }
   285     /**
   286      * Return true if given file name is a valid class file name.
   287      * @param file the name of the file to check.
   288      * @return true if given file name is a valid class file name
   289      * and false otherwise.
   290      */
   291     private static boolean isValidJavaClassFile(String file) {
   292         if (!file.endsWith(".class")) return false;
   293         String clazzName = file.substring(0, file.length() - ".class".length());
   294         return isValidClassName(clazzName);
   295     }
   297     /**
   298      * Return true if given file name is a valid Java source file name.
   299      * @param file the name of the file to check.
   300      * @return true if given file name is a valid Java source file name
   301      * and false otherwise.
   302      */
   303     private static boolean isValidJavaSourceFile(String file) {
   304         if (!file.endsWith(".java")) return false;
   305         String clazzName = file.substring(0, file.length() - ".java".length());
   306         return isValidClassName(clazzName);
   307     }
   309     /** Are surrogates supported?
   310      */
   311     final static boolean surrogatesSupported = surrogatesSupported();
   312     private static boolean surrogatesSupported() {
   313         try {
   314             boolean b = Character.isHighSurrogate('a');
   315             return true;
   316         } catch (NoSuchMethodError ex) {
   317             return false;
   318         }
   319     }
   321     /**
   322      * Return true if given file name is a valid class name
   323      * (including "package-info").
   324      * @param clazzname the name of the class to check.
   325      * @return true if given class name is a valid class name
   326      * and false otherwise.
   327      */
   328     public static boolean isValidClassName(String s) {
   329         if (s.length() < 1) return false;
   330         if (s.equals("package-info")) return true;
   331         if (surrogatesSupported) {
   332             int cp = s.codePointAt(0);
   333             if (!Character.isJavaIdentifierStart(cp))
   334                 return false;
   335             for (int j=Character.charCount(cp); j<s.length(); j+=Character.charCount(cp)) {
   336                 cp = s.codePointAt(j);
   337                 if (!Character.isJavaIdentifierPart(cp))
   338                     return false;
   339             }
   340         } else {
   341             if (!Character.isJavaIdentifierStart(s.charAt(0)))
   342                 return false;
   343             for (int j=1; j<s.length(); j++)
   344                 if (!Character.isJavaIdentifierPart(s.charAt(j)))
   345                     return false;
   346         }
   347         return true;
   348     }
   350     /**
   351      * From a list of top level trees, return the list of contained class definitions
   352      */
   353     List<JCClassDecl> listClasses(List<JCCompilationUnit> trees) {
   354         ListBuffer<JCClassDecl> result = new ListBuffer<JCClassDecl>();
   355         for (JCCompilationUnit t : trees) {
   356             for (JCTree def : t.defs) {
   357                 if (def.getTag() == JCTree.CLASSDEF)
   358                     result.append((JCClassDecl)def);
   359             }
   360         }
   361         return result.toList();
   362     }
   364 }

mercurial