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

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 2367
1737ad9ac984
parent 0
959103a6100f
permissions
-rw-r--r--

merge

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

mercurial