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