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

Thu, 04 Oct 2012 13:04:53 +0100

author
mcimadamore
date
Thu, 04 Oct 2012 13:04:53 +0100
changeset 1347
1408af4cd8b0
parent 1127
ca49d50318dc
child 1358
fc123bdeddb8
permissions
-rw-r--r--

7177387: Add target-typing support in method context
Summary: Add support for deferred types and speculative attribution
Reviewed-by: jjg, dlsmith

     1 /*
     2  * Copyright (c) 2001, 2011, 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.tree.JCTree;
    43 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
    44 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
    45 import com.sun.tools.javac.util.Abort;
    46 import com.sun.tools.javac.util.Context;
    47 import com.sun.tools.javac.util.List;
    48 import com.sun.tools.javac.util.ListBuffer;
    49 import com.sun.tools.javac.util.Position;
    52 /**
    53  *  This class could be the main entry point for Javadoc when Javadoc is used as a
    54  *  component in a larger software system. It provides operations to
    55  *  construct a new javadoc processor, and to run it on a set of source
    56  *  files.
    57  *  @author Neal Gafter
    58  */
    59 public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
    60     DocEnv docenv;
    62     final Context context;
    63     final Messager messager;
    64     final JavadocClassReader reader;
    65     final JavadocEnter enter;
    66     final Annotate annotate;
    68     /**
    69      * Construct a new JavaCompiler processor, using appropriately
    70      * extended phases of the underlying compiler.
    71      */
    72     protected JavadocTool(Context context) {
    73         super(context);
    74         this.context = context;
    75         messager = Messager.instance0(context);
    76         reader = JavadocClassReader.instance0(context);
    77         enter = JavadocEnter.instance0(context);
    78         annotate = Annotate.instance(context);
    79     }
    81     /**
    82      * For javadoc, the parser needs to keep comments. Overrides method from JavaCompiler.
    83      */
    84     protected boolean keepComments() {
    85         return true;
    86     }
    88     /**
    89      *  Construct a new javadoc tool.
    90      */
    91     public static JavadocTool make0(Context context) {
    92         Messager messager = null;
    93         try {
    94             // force the use of Javadoc's class reader
    95             JavadocClassReader.preRegister(context);
    97             // force the use of Javadoc's own enter phase
    98             JavadocEnter.preRegister(context);
   100             // force the use of Javadoc's own member enter phase
   101             JavadocMemberEnter.preRegister(context);
   103             // force the use of Javadoc's own todo phase
   104             JavadocTodo.preRegister(context);
   106             // force the use of Messager as a Log
   107             messager = Messager.instance0(context);
   109             return new JavadocTool(context);
   110         } catch (CompletionFailure ex) {
   111             messager.error(Position.NOPOS, ex.getMessage());
   112             return null;
   113         }
   114     }
   116     public RootDocImpl getRootDocImpl(String doclocale,
   117                                       String encoding,
   118                                       ModifierFilter filter,
   119                                       List<String> javaNames,
   120                                       List<String[]> options,
   121                                       boolean breakiterator,
   122                                       List<String> subPackages,
   123                                       List<String> excludedPackages,
   124                                       boolean docClasses,
   125                                       boolean legacyDoclet,
   126                       boolean quiet) throws IOException {
   127         docenv = DocEnv.instance(context);
   128         docenv.showAccess = filter;
   129         docenv.quiet = quiet;
   130         docenv.breakiterator = breakiterator;
   131         docenv.setLocale(doclocale);
   132         docenv.setEncoding(encoding);
   133         docenv.docClasses = docClasses;
   134         docenv.legacyDoclet = legacyDoclet;
   135         reader.sourceCompleter = docClasses ? null : this;
   137         ListBuffer<String> names = new ListBuffer<String>();
   138         ListBuffer<JCCompilationUnit> classTrees = new ListBuffer<JCCompilationUnit>();
   139         ListBuffer<JCCompilationUnit> packTrees = new ListBuffer<JCCompilationUnit>();
   141         try {
   142             StandardJavaFileManager fm = (StandardJavaFileManager) docenv.fileManager;
   143             for (List<String> it = javaNames; it.nonEmpty(); it = it.tail) {
   144                 String name = it.head;
   145                 if (!docClasses && name.endsWith(".java") && new File(name).exists()) {
   146                     JavaFileObject fo = fm.getJavaFileObjects(name).iterator().next();
   147                     docenv.notice("main.Loading_source_file", name);
   148                     JCCompilationUnit tree = parse(fo);
   149                     classTrees.append(tree);
   150                 } else if (isValidPackageName(name)) {
   151                     names = names.append(name);
   152                 } else if (name.endsWith(".java")) {
   153                     docenv.error(null, "main.file_not_found", name);
   154                 } else {
   155                     docenv.error(null, "main.illegal_package_name", name);
   156                 }
   157             }
   159             if (!docClasses) {
   160                 // Recursively search given subpackages.  If any packages
   161                 //are found, add them to the list.
   162                 Map<String,List<JavaFileObject>> packageFiles =
   163                         searchSubPackages(subPackages, names, excludedPackages);
   165                 // Parse the packages
   166                 for (List<String> packs = names.toList(); packs.nonEmpty(); packs = packs.tail) {
   167                     // Parse sources ostensibly belonging to package.
   168                     String packageName = packs.head;
   169                     parsePackageClasses(packageName, packageFiles.get(packageName), packTrees, excludedPackages);
   170                 }
   172                 if (messager.nerrors() != 0) return null;
   174                 // Enter symbols for all files
   175                 docenv.notice("main.Building_tree");
   176                 enter.main(classTrees.toList().appendList(packTrees.toList()));
   177             }
   178         } catch (Abort ex) {}
   180         if (messager.nerrors() != 0)
   181             return null;
   183         if (docClasses)
   184             return new RootDocImpl(docenv, javaNames, options);
   185         else
   186             return new RootDocImpl(docenv, listClasses(classTrees.toList()), names.toList(), options);
   187     }
   189     /** Is the given string a valid package name? */
   190     boolean isValidPackageName(String s) {
   191         int index;
   192         while ((index = s.indexOf('.')) != -1) {
   193             if (!isValidClassName(s.substring(0, index))) return false;
   194             s = s.substring(index+1);
   195         }
   196         return isValidClassName(s);
   197     }
   199     /**
   200      * search all directories in path for subdirectory name. Add all
   201      * .java files found in such a directory to args.
   202      */
   203     private void parsePackageClasses(String name,
   204             Iterable<JavaFileObject> files,
   205             ListBuffer<JCCompilationUnit> trees,
   206             List<String> excludedPackages)
   207             throws IOException {
   208         if (excludedPackages.contains(name)) {
   209             return;
   210         }
   212         boolean hasFiles = false;
   213         docenv.notice("main.Loading_source_files_for_package", name);
   215         if (files == null) {
   216             Location location = docenv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
   217                     ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;
   218             ListBuffer<JavaFileObject> lb = new ListBuffer<JavaFileObject>();
   219             for (JavaFileObject fo: docenv.fileManager.list(
   220                     location, name, EnumSet.of(JavaFileObject.Kind.SOURCE), false)) {
   221                 String binaryName = docenv.fileManager.inferBinaryName(location, fo);
   222                 String simpleName = getSimpleName(binaryName);
   223                 if (isValidClassName(simpleName)) {
   224                     lb.append(fo);
   225                 }
   226             }
   227             files = lb.toList();
   228         }
   230         for (JavaFileObject fo : files) {
   231             // messager.notice("main.Loading_source_file", fn);
   232             trees.append(parse(fo));
   233             hasFiles = true;
   234         }
   236         if (!hasFiles) {
   237             messager.warning(null, "main.no_source_files_for_package",
   238                     name.replace(File.separatorChar, '.'));
   239         }
   240     }
   242     /**
   243      * Recursively search all directories in path for subdirectory name.
   244      * Add all packages found in such a directory to packages list.
   245      */
   246     private Map<String,List<JavaFileObject>> searchSubPackages(
   247             List<String> subPackages,
   248             ListBuffer<String> packages,
   249             List<String> excludedPackages)
   250             throws IOException {
   251         Map<String,List<JavaFileObject>> packageFiles =
   252                 new HashMap<String,List<JavaFileObject>>();
   254         Map<String,Boolean> includedPackages = new HashMap<String,Boolean>();
   255         includedPackages.put("", true);
   256         for (String p: excludedPackages)
   257             includedPackages.put(p, false);
   259         StandardLocation path = docenv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
   260                 ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;
   262         searchSubPackages(subPackages,
   263                 includedPackages,
   264                 packages, packageFiles,
   265                 path,
   266                 EnumSet.of(JavaFileObject.Kind.SOURCE));
   268         return packageFiles;
   269     }
   271     private void searchSubPackages(List<String> subPackages,
   272             Map<String,Boolean> includedPackages,
   273             ListBuffer<String> packages,
   274             Map<String, List<JavaFileObject>> packageFiles,
   275             StandardLocation location, Set<JavaFileObject.Kind> kinds)
   276             throws IOException {
   277         for (String subPackage: subPackages) {
   278             if (!isIncluded(subPackage, includedPackages))
   279                 continue;
   281             for (JavaFileObject fo: docenv.fileManager.list(location, subPackage, kinds, true)) {
   282                 String binaryName = docenv.fileManager.inferBinaryName(location, fo);
   283                 String packageName = getPackageName(binaryName);
   284                 String simpleName = getSimpleName(binaryName);
   285                 if (isIncluded(packageName, includedPackages) && isValidClassName(simpleName)) {
   286                     List<JavaFileObject> list = packageFiles.get(packageName);
   287                     list = (list == null ? List.of(fo) : list.prepend(fo));
   288                     packageFiles.put(packageName, list);
   289                     if (!packages.contains(packageName))
   290                         packages.add(packageName);
   291                 }
   292             }
   293         }
   294     }
   296     private String getPackageName(String name) {
   297         int lastDot = name.lastIndexOf(".");
   298         return (lastDot == -1 ? "" : name.substring(0, lastDot));
   299     }
   301     private String getSimpleName(String name) {
   302         int lastDot = name.lastIndexOf(".");
   303         return (lastDot == -1 ? name : name.substring(lastDot + 1));
   304     }
   306     private boolean isIncluded(String packageName, Map<String,Boolean> includedPackages) {
   307         Boolean b = includedPackages.get(packageName);
   308         if (b == null) {
   309             b = isIncluded(getPackageName(packageName), includedPackages);
   310             includedPackages.put(packageName, b);
   311         }
   312         return b;
   313     }
   315     /**
   316      * Recursively search all directories in path for subdirectory name.
   317      * Add all packages found in such a directory to packages list.
   318      */
   319     private void searchSubPackage(String packageName,
   320                                   ListBuffer<String> packages,
   321                                   List<String> excludedPackages,
   322                                   Collection<File> pathnames) {
   323         if (excludedPackages.contains(packageName))
   324             return;
   326         String packageFilename = packageName.replace('.', File.separatorChar);
   327         boolean addedPackage = false;
   328         for (File pathname : pathnames) {
   329             File f = new File(pathname, packageFilename);
   330             String filenames[] = f.list();
   331             // if filenames not null, then found directory
   332             if (filenames != null) {
   333                 for (String filename : filenames) {
   334                     if (!addedPackage
   335                             && (isValidJavaSourceFile(filename) ||
   336                                 isValidJavaClassFile(filename))
   337                             && !packages.contains(packageName)) {
   338                         packages.append(packageName);
   339                         addedPackage = true;
   340                     } else if (isValidClassName(filename) &&
   341                                (new File(f, filename)).isDirectory()) {
   342                         searchSubPackage(packageName + "." + filename,
   343                                          packages, excludedPackages, pathnames);
   344                     }
   345                 }
   346             }
   347         }
   348     }
   350     /**
   351      * Return true if given file name is a valid class file name.
   352      * @param file the name of the file to check.
   353      * @return true if given file name is a valid class file name
   354      * and false otherwise.
   355      */
   356     private static boolean isValidJavaClassFile(String file) {
   357         if (!file.endsWith(".class")) return false;
   358         String clazzName = file.substring(0, file.length() - ".class".length());
   359         return isValidClassName(clazzName);
   360     }
   362     /**
   363      * Return true if given file name is a valid Java source file name.
   364      * @param file the name of the file to check.
   365      * @return true if given file name is a valid Java source file name
   366      * and false otherwise.
   367      */
   368     private static boolean isValidJavaSourceFile(String file) {
   369         if (!file.endsWith(".java")) return false;
   370         String clazzName = file.substring(0, file.length() - ".java".length());
   371         return isValidClassName(clazzName);
   372     }
   374     /** Are surrogates supported?
   375      */
   376     final static boolean surrogatesSupported = surrogatesSupported();
   377     private static boolean surrogatesSupported() {
   378         try {
   379             boolean b = Character.isHighSurrogate('a');
   380             return true;
   381         } catch (NoSuchMethodError ex) {
   382             return false;
   383         }
   384     }
   386     /**
   387      * Return true if given file name is a valid class name
   388      * (including "package-info").
   389      * @param clazzname the name of the class to check.
   390      * @return true if given class name is a valid class name
   391      * and false otherwise.
   392      */
   393     public static boolean isValidClassName(String s) {
   394         if (s.length() < 1) return false;
   395         if (s.equals("package-info")) return true;
   396         if (surrogatesSupported) {
   397             int cp = s.codePointAt(0);
   398             if (!Character.isJavaIdentifierStart(cp))
   399                 return false;
   400             for (int j=Character.charCount(cp); j<s.length(); j+=Character.charCount(cp)) {
   401                 cp = s.codePointAt(j);
   402                 if (!Character.isJavaIdentifierPart(cp))
   403                     return false;
   404             }
   405         } else {
   406             if (!Character.isJavaIdentifierStart(s.charAt(0)))
   407                 return false;
   408             for (int j=1; j<s.length(); j++)
   409                 if (!Character.isJavaIdentifierPart(s.charAt(j)))
   410                     return false;
   411         }
   412         return true;
   413     }
   415     /**
   416      * From a list of top level trees, return the list of contained class definitions
   417      */
   418     List<JCClassDecl> listClasses(List<JCCompilationUnit> trees) {
   419         ListBuffer<JCClassDecl> result = new ListBuffer<JCClassDecl>();
   420         for (JCCompilationUnit t : trees) {
   421             for (JCTree def : t.defs) {
   422                 if (def.hasTag(JCTree.Tag.CLASSDEF))
   423                     result.append((JCClassDecl)def);
   424             }
   425         }
   426         return result.toList();
   427     }
   429 }

mercurial