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/ClassDocImpl.java
38899 views
1
/*
2
* Copyright (c) 1997, 2013, 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.lang.reflect.Modifier;
31
import java.net.URI;
32
import java.util.HashSet;
33
import java.util.Set;
34
35
import javax.tools.FileObject;
36
import javax.tools.JavaFileManager.Location;
37
import javax.tools.StandardJavaFileManager;
38
import javax.tools.StandardLocation;
39
40
import com.sun.javadoc.*;
41
import com.sun.source.util.TreePath;
42
import com.sun.tools.javac.code.Flags;
43
import com.sun.tools.javac.code.Kinds;
44
import com.sun.tools.javac.code.Scope;
45
import com.sun.tools.javac.code.Symbol;
46
import com.sun.tools.javac.code.Symbol.*;
47
import com.sun.tools.javac.code.Type;
48
import com.sun.tools.javac.code.Type.ClassType;
49
import com.sun.tools.javac.code.TypeTag;
50
import com.sun.tools.javac.comp.AttrContext;
51
import com.sun.tools.javac.comp.Env;
52
import com.sun.tools.javac.tree.JCTree;
53
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
54
import com.sun.tools.javac.tree.JCTree.JCImport;
55
import com.sun.tools.javac.tree.TreeInfo;
56
import com.sun.tools.javac.util.List;
57
import com.sun.tools.javac.util.ListBuffer;
58
import com.sun.tools.javac.util.Name;
59
import com.sun.tools.javac.util.Names;
60
import com.sun.tools.javac.util.Position;
61
import static com.sun.tools.javac.code.Kinds.*;
62
import static com.sun.tools.javac.code.TypeTag.CLASS;
63
import static com.sun.tools.javac.tree.JCTree.Tag.*;
64
65
/**
66
* Represents a java class and provides access to information
67
* about the class, the class' comment and tags, and the
68
* members of the class. A ClassDocImpl only exists if it was
69
* processed in this run of javadoc. References to classes
70
* which may or may not have been processed in this run are
71
* referred to using Type (which can be converted to ClassDocImpl,
72
* if possible).
73
*
74
* <p><b>This is NOT part of any supported API.
75
* If you write code that depends on this, you do so at your own risk.
76
* This code and its internal interfaces are subject to change or
77
* deletion without notice.</b>
78
*
79
* @see Type
80
*
81
* @since 1.2
82
* @author Robert Field
83
* @author Neal Gafter (rewrite)
84
* @author Scott Seligman (generics, enums, annotations)
85
*/
86
87
public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc {
88
89
public final ClassType type; // protected->public for debugging
90
protected final ClassSymbol tsym;
91
92
boolean isIncluded = false; // Set in RootDocImpl
93
94
private SerializedForm serializedForm;
95
96
/**
97
* Constructor
98
*/
99
public ClassDocImpl(DocEnv env, ClassSymbol sym) {
100
this(env, sym, null);
101
}
102
103
/**
104
* Constructor
105
*/
106
public ClassDocImpl(DocEnv env, ClassSymbol sym, TreePath treePath) {
107
super(env, sym, treePath);
108
this.type = (ClassType)sym.type;
109
this.tsym = sym;
110
}
111
112
public com.sun.javadoc.Type getElementType() {
113
return null;
114
}
115
116
/**
117
* Returns the flags in terms of javac's flags
118
*/
119
protected long getFlags() {
120
return getFlags(tsym);
121
}
122
123
/**
124
* Returns the flags of a ClassSymbol in terms of javac's flags
125
*/
126
static long getFlags(ClassSymbol clazz) {
127
try {
128
return clazz.flags();
129
} catch (CompletionFailure ex) {
130
/* Quietly ignore completion failures and try again - the type
131
* for which the CompletionFailure was thrown shouldn't be completed
132
* again by the completer that threw the CompletionFailure.
133
*/
134
return getFlags(clazz);
135
}
136
}
137
138
/**
139
* Is a ClassSymbol an annotation type?
140
*/
141
static boolean isAnnotationType(ClassSymbol clazz) {
142
return (getFlags(clazz) & Flags.ANNOTATION) != 0;
143
}
144
145
/**
146
* Identify the containing class
147
*/
148
protected ClassSymbol getContainingClass() {
149
return tsym.owner.enclClass();
150
}
151
152
/**
153
* Return true if this is a class, not an interface.
154
*/
155
@Override
156
public boolean isClass() {
157
return !Modifier.isInterface(getModifiers());
158
}
159
160
/**
161
* Return true if this is a ordinary class,
162
* not an enumeration, exception, an error, or an interface.
163
*/
164
@Override
165
public boolean isOrdinaryClass() {
166
if (isEnum() || isInterface() || isAnnotationType()) {
167
return false;
168
}
169
for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
170
if (t.tsym == env.syms.errorType.tsym ||
171
t.tsym == env.syms.exceptionType.tsym) {
172
return false;
173
}
174
}
175
return true;
176
}
177
178
/**
179
* Return true if this is an enumeration.
180
* (For legacy doclets, return false.)
181
*/
182
@Override
183
public boolean isEnum() {
184
return (getFlags() & Flags.ENUM) != 0
185
&&
186
!env.legacyDoclet;
187
}
188
189
/**
190
* Return true if this is an interface, but not an annotation type.
191
* Overridden by AnnotationTypeDocImpl.
192
*/
193
@Override
194
public boolean isInterface() {
195
return Modifier.isInterface(getModifiers());
196
}
197
198
/**
199
* Return true if this is an exception class
200
*/
201
@Override
202
public boolean isException() {
203
if (isEnum() || isInterface() || isAnnotationType()) {
204
return false;
205
}
206
for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
207
if (t.tsym == env.syms.exceptionType.tsym) {
208
return true;
209
}
210
}
211
return false;
212
}
213
214
/**
215
* Return true if this is an error class
216
*/
217
@Override
218
public boolean isError() {
219
if (isEnum() || isInterface() || isAnnotationType()) {
220
return false;
221
}
222
for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
223
if (t.tsym == env.syms.errorType.tsym) {
224
return true;
225
}
226
}
227
return false;
228
}
229
230
/**
231
* Return true if this is a throwable class
232
*/
233
public boolean isThrowable() {
234
if (isEnum() || isInterface() || isAnnotationType()) {
235
return false;
236
}
237
for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
238
if (t.tsym == env.syms.throwableType.tsym) {
239
return true;
240
}
241
}
242
return false;
243
}
244
245
/**
246
* Return true if this class is abstract
247
*/
248
public boolean isAbstract() {
249
return Modifier.isAbstract(getModifiers());
250
}
251
252
/**
253
* Returns true if this class was synthesized by the compiler.
254
*/
255
public boolean isSynthetic() {
256
return (getFlags() & Flags.SYNTHETIC) != 0;
257
}
258
259
/**
260
* Return true if this class is included in the active set.
261
* A ClassDoc is included iff either it is specified on the
262
* commandline, or if it's containing package is specified
263
* on the command line, or if it is a member class of an
264
* included class.
265
*/
266
267
public boolean isIncluded() {
268
if (isIncluded) {
269
return true;
270
}
271
if (env.shouldDocument(tsym)) {
272
// Class is nameable from top-level and
273
// the class and all enclosing classes
274
// pass the modifier filter.
275
if (containingPackage().isIncluded()) {
276
return isIncluded=true;
277
}
278
ClassDoc outer = containingClass();
279
if (outer != null && outer.isIncluded()) {
280
return isIncluded=true;
281
}
282
}
283
return false;
284
}
285
286
/**
287
* Return the package that this class is contained in.
288
*/
289
@Override
290
public PackageDoc containingPackage() {
291
PackageDocImpl p = env.getPackageDoc(tsym.packge());
292
if (p.setDocPath == false) {
293
FileObject docPath;
294
try {
295
Location location = env.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
296
? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;
297
298
docPath = env.fileManager.getFileForInput(
299
location, p.qualifiedName(), "package.html");
300
} catch (IOException e) {
301
docPath = null;
302
}
303
304
if (docPath == null) {
305
// fall back on older semantics of looking in same directory as
306
// source file for this class
307
SourcePosition po = position();
308
if (env.fileManager instanceof StandardJavaFileManager &&
309
po instanceof SourcePositionImpl) {
310
URI uri = ((SourcePositionImpl) po).filename.toUri();
311
if ("file".equals(uri.getScheme())) {
312
File f = new File(uri);
313
File dir = f.getParentFile();
314
if (dir != null) {
315
File pf = new File(dir, "package.html");
316
if (pf.exists()) {
317
StandardJavaFileManager sfm = (StandardJavaFileManager) env.fileManager;
318
docPath = sfm.getJavaFileObjects(pf).iterator().next();
319
}
320
}
321
322
}
323
}
324
}
325
326
p.setDocPath(docPath);
327
}
328
return p;
329
}
330
331
/**
332
* Return the class name without package qualifier - but with
333
* enclosing class qualifier - as a String.
334
* <pre>
335
* Examples:
336
* for java.util.Hashtable
337
* return Hashtable
338
* for java.util.Map.Entry
339
* return Map.Entry
340
* </pre>
341
*/
342
public String name() {
343
if (name == null) {
344
name = getClassName(tsym, false);
345
}
346
return name;
347
}
348
349
private String name;
350
351
/**
352
* Return the qualified class name as a String.
353
* <pre>
354
* Example:
355
* for java.util.Hashtable
356
* return java.util.Hashtable
357
* if no qualifier, just return flat name
358
* </pre>
359
*/
360
public String qualifiedName() {
361
if (qualifiedName == null) {
362
qualifiedName = getClassName(tsym, true);
363
}
364
return qualifiedName;
365
}
366
367
private String qualifiedName;
368
369
/**
370
* Return unqualified name of type excluding any dimension information.
371
* <p>
372
* For example, a two dimensional array of String returns 'String'.
373
*/
374
public String typeName() {
375
return name();
376
}
377
378
/**
379
* Return qualified name of type excluding any dimension information.
380
*<p>
381
* For example, a two dimensional array of String
382
* returns 'java.lang.String'.
383
*/
384
public String qualifiedTypeName() {
385
return qualifiedName();
386
}
387
388
/**
389
* Return the simple name of this type.
390
*/
391
public String simpleTypeName() {
392
if (simpleTypeName == null) {
393
simpleTypeName = tsym.name.toString();
394
}
395
return simpleTypeName;
396
}
397
398
private String simpleTypeName;
399
400
/**
401
* Return the qualified name and any type parameters.
402
* Each parameter is a type variable with optional bounds.
403
*/
404
@Override
405
public String toString() {
406
return classToString(env, tsym, true);
407
}
408
409
/**
410
* Return the class name as a string. If "full" is true the name is
411
* qualified, otherwise it is qualified by its enclosing class(es) only.
412
*/
413
static String getClassName(ClassSymbol c, boolean full) {
414
if (full) {
415
return c.getQualifiedName().toString();
416
} else {
417
String n = "";
418
for ( ; c != null; c = c.owner.enclClass()) {
419
n = c.name + (n.equals("") ? "" : ".") + n;
420
}
421
return n;
422
}
423
}
424
425
/**
426
* Return the class name with any type parameters as a string.
427
* Each parameter is a type variable with optional bounds.
428
* If "full" is true all names are qualified, otherwise they are
429
* qualified by their enclosing class(es) only.
430
*/
431
static String classToString(DocEnv env, ClassSymbol c, boolean full) {
432
StringBuilder s = new StringBuilder();
433
if (!c.isInner()) { // if c is not an inner class
434
s.append(getClassName(c, full));
435
} else {
436
// c is an inner class, so include type params of outer.
437
ClassSymbol encl = c.owner.enclClass();
438
s.append(classToString(env, encl, full))
439
.append('.')
440
.append(c.name);
441
}
442
s.append(TypeMaker.typeParametersString(env, c, full));
443
return s.toString();
444
}
445
446
/**
447
* Is this class (or any enclosing class) generic? That is, does
448
* it have type parameters?
449
*/
450
static boolean isGeneric(ClassSymbol c) {
451
return c.type.allparams().nonEmpty();
452
}
453
454
/**
455
* Return the formal type parameters of this class or interface.
456
* Return an empty array if there are none.
457
*/
458
public TypeVariable[] typeParameters() {
459
if (env.legacyDoclet) {
460
return new TypeVariable[0];
461
}
462
TypeVariable res[] = new TypeVariable[type.getTypeArguments().length()];
463
TypeMaker.getTypes(env, type.getTypeArguments(), res);
464
return res;
465
}
466
467
/**
468
* Return the type parameter tags of this class or interface.
469
*/
470
public ParamTag[] typeParamTags() {
471
return (env.legacyDoclet)
472
? new ParamTag[0]
473
: comment().typeParamTags();
474
}
475
476
/**
477
* Return the modifier string for this class. If it's an interface
478
* exclude 'abstract' keyword from the modifier string
479
*/
480
@Override
481
public String modifiers() {
482
return Modifier.toString(modifierSpecifier());
483
}
484
485
@Override
486
public int modifierSpecifier() {
487
int modifiers = getModifiers();
488
return (isInterface() || isAnnotationType())
489
? modifiers & ~Modifier.ABSTRACT
490
: modifiers;
491
}
492
493
/**
494
* Return the superclass of this class
495
*
496
* @return the ClassDocImpl for the superclass of this class, null
497
* if there is no superclass.
498
*/
499
public ClassDoc superclass() {
500
if (isInterface() || isAnnotationType()) return null;
501
if (tsym == env.syms.objectType.tsym) return null;
502
ClassSymbol c = (ClassSymbol)env.types.supertype(type).tsym;
503
if (c == null || c == tsym) c = (ClassSymbol)env.syms.objectType.tsym;
504
return env.getClassDoc(c);
505
}
506
507
/**
508
* Return the superclass of this class. Return null if this is an
509
* interface. A superclass is represented by either a
510
* <code>ClassDoc</code> or a <code>ParameterizedType</code>.
511
*/
512
public com.sun.javadoc.Type superclassType() {
513
if (isInterface() || isAnnotationType() ||
514
(tsym == env.syms.objectType.tsym))
515
return null;
516
Type sup = env.types.supertype(type);
517
return TypeMaker.getType(env,
518
(sup.hasTag(TypeTag.NONE)) ? env.syms.objectType : sup);
519
}
520
521
/**
522
* Test whether this class is a subclass of the specified class.
523
*
524
* @param cd the candidate superclass.
525
* @return true if cd is a superclass of this class.
526
*/
527
public boolean subclassOf(ClassDoc cd) {
528
return tsym.isSubClass(((ClassDocImpl)cd).tsym, env.types);
529
}
530
531
/**
532
* Return interfaces implemented by this class or interfaces
533
* extended by this interface.
534
*
535
* @return An array of ClassDocImpl representing the interfaces.
536
* Return an empty array if there are no interfaces.
537
*/
538
public ClassDoc[] interfaces() {
539
ListBuffer<ClassDocImpl> ta = new ListBuffer<ClassDocImpl>();
540
for (Type t : env.types.interfaces(type)) {
541
ta.append(env.getClassDoc((ClassSymbol)t.tsym));
542
}
543
//### Cache ta here?
544
return ta.toArray(new ClassDocImpl[ta.length()]);
545
}
546
547
/**
548
* Return interfaces implemented by this class or interfaces extended
549
* by this interface. Includes only directly-declared interfaces, not
550
* inherited interfaces.
551
* Return an empty array if there are no interfaces.
552
*/
553
public com.sun.javadoc.Type[] interfaceTypes() {
554
//### Cache result here?
555
return TypeMaker.getTypes(env, env.types.interfaces(type));
556
}
557
558
/**
559
* Return fields in class.
560
* @param filter include only the included fields if filter==true
561
*/
562
public FieldDoc[] fields(boolean filter) {
563
return fields(filter, false);
564
}
565
566
/**
567
* Return included fields in class.
568
*/
569
public FieldDoc[] fields() {
570
return fields(true, false);
571
}
572
573
/**
574
* Return the enum constants if this is an enum type.
575
*/
576
public FieldDoc[] enumConstants() {
577
return fields(false, true);
578
}
579
580
/**
581
* Return fields in class.
582
* @param filter if true, return only the included fields
583
* @param enumConstants if true, return the enum constants instead
584
*/
585
private FieldDoc[] fields(boolean filter, boolean enumConstants) {
586
List<FieldDocImpl> fields = List.nil();
587
for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
588
if (e.sym != null && e.sym.kind == VAR) {
589
VarSymbol s = (VarSymbol)e.sym;
590
boolean isEnum = ((s.flags() & Flags.ENUM) != 0) &&
591
!env.legacyDoclet;
592
if (isEnum == enumConstants &&
593
(!filter || env.shouldDocument(s))) {
594
fields = fields.prepend(env.getFieldDoc(s));
595
}
596
}
597
}
598
return fields.toArray(new FieldDocImpl[fields.length()]);
599
}
600
601
/**
602
* Return methods in class.
603
* This method is overridden by AnnotationTypeDocImpl.
604
*
605
* @param filter include only the included methods if filter==true
606
* @return an array of MethodDocImpl for representing the visible
607
* methods in this class. Does not include constructors.
608
*/
609
public MethodDoc[] methods(boolean filter) {
610
Names names = tsym.name.table.names;
611
List<MethodDocImpl> methods = List.nil();
612
for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
613
if (e.sym != null
614
&& e.sym.kind == Kinds.MTH
615
&& e.sym.name != names.init
616
&& e.sym.name != names.clinit) {
617
MethodSymbol s = (MethodSymbol)e.sym;
618
if (!filter || env.shouldDocument(s)) {
619
methods = methods.prepend(env.getMethodDoc(s));
620
}
621
}
622
}
623
//### Cache methods here?
624
return methods.toArray(new MethodDocImpl[methods.length()]);
625
}
626
627
/**
628
* Return included methods in class.
629
*
630
* @return an array of MethodDocImpl for representing the visible
631
* methods in this class. Does not include constructors.
632
*/
633
public MethodDoc[] methods() {
634
return methods(true);
635
}
636
637
/**
638
* Return constructors in class.
639
*
640
* @param filter include only the included constructors if filter==true
641
* @return an array of ConstructorDocImpl for representing the visible
642
* constructors in this class.
643
*/
644
public ConstructorDoc[] constructors(boolean filter) {
645
Names names = tsym.name.table.names;
646
List<ConstructorDocImpl> constructors = List.nil();
647
for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
648
if (e.sym != null &&
649
e.sym.kind == Kinds.MTH && e.sym.name == names.init) {
650
MethodSymbol s = (MethodSymbol)e.sym;
651
if (!filter || env.shouldDocument(s)) {
652
constructors = constructors.prepend(env.getConstructorDoc(s));
653
}
654
}
655
}
656
//### Cache constructors here?
657
return constructors.toArray(new ConstructorDocImpl[constructors.length()]);
658
}
659
660
/**
661
* Return included constructors in class.
662
*
663
* @return an array of ConstructorDocImpl for representing the visible
664
* constructors in this class.
665
*/
666
public ConstructorDoc[] constructors() {
667
return constructors(true);
668
}
669
670
/**
671
* Adds all inner classes of this class, and their
672
* inner classes recursively, to the list l.
673
*/
674
void addAllClasses(ListBuffer<ClassDocImpl> l, boolean filtered) {
675
try {
676
if (isSynthetic()) return;
677
// sometimes synthetic classes are not marked synthetic
678
if (!JavadocTool.isValidClassName(tsym.name.toString())) return;
679
if (filtered && !env.shouldDocument(tsym)) return;
680
if (l.contains(this)) return;
681
l.append(this);
682
List<ClassDocImpl> more = List.nil();
683
for (Scope.Entry e = tsym.members().elems; e != null;
684
e = e.sibling) {
685
if (e.sym != null && e.sym.kind == Kinds.TYP) {
686
ClassSymbol s = (ClassSymbol)e.sym;
687
ClassDocImpl c = env.getClassDoc(s);
688
if (c.isSynthetic()) continue;
689
if (c != null) more = more.prepend(c);
690
}
691
}
692
// this extra step preserves the ordering from oldjavadoc
693
for (; more.nonEmpty(); more=more.tail) {
694
more.head.addAllClasses(l, filtered);
695
}
696
} catch (CompletionFailure e) {
697
// quietly ignore completion failures
698
}
699
}
700
701
/**
702
* Return inner classes within this class.
703
*
704
* @param filter include only the included inner classes if filter==true.
705
* @return an array of ClassDocImpl for representing the visible
706
* classes defined in this class. Anonymous and local classes
707
* are not included.
708
*/
709
public ClassDoc[] innerClasses(boolean filter) {
710
ListBuffer<ClassDocImpl> innerClasses = new ListBuffer<ClassDocImpl>();
711
for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
712
if (e.sym != null && e.sym.kind == Kinds.TYP) {
713
ClassSymbol s = (ClassSymbol)e.sym;
714
if ((s.flags_field & Flags.SYNTHETIC) != 0) continue;
715
if (!filter || env.isVisible(s)) {
716
innerClasses.prepend(env.getClassDoc(s));
717
}
718
}
719
}
720
//### Cache classes here?
721
return innerClasses.toArray(new ClassDocImpl[innerClasses.length()]);
722
}
723
724
/**
725
* Return included inner classes within this class.
726
*
727
* @return an array of ClassDocImpl for representing the visible
728
* classes defined in this class. Anonymous and local classes
729
* are not included.
730
*/
731
public ClassDoc[] innerClasses() {
732
return innerClasses(true);
733
}
734
735
/**
736
* Find a class within the context of this class.
737
* Search order: qualified name, in this class (inner),
738
* in this package, in the class imports, in the package
739
* imports.
740
* Return the ClassDocImpl if found, null if not found.
741
*/
742
//### The specified search order is not the normal rule the
743
//### compiler would use. Leave as specified or change it?
744
public ClassDoc findClass(String className) {
745
ClassDoc searchResult = searchClass(className);
746
if (searchResult == null) {
747
ClassDocImpl enclosingClass = (ClassDocImpl)containingClass();
748
//Expand search space to include enclosing class.
749
while (enclosingClass != null && enclosingClass.containingClass() != null) {
750
enclosingClass = (ClassDocImpl)enclosingClass.containingClass();
751
}
752
searchResult = enclosingClass == null ?
753
null : enclosingClass.searchClass(className);
754
}
755
return searchResult;
756
}
757
758
private ClassDoc searchClass(String className) {
759
Names names = tsym.name.table.names;
760
761
// search by qualified name first
762
ClassDoc cd = env.lookupClass(className);
763
if (cd != null) {
764
return cd;
765
}
766
767
// search inner classes
768
//### Add private entry point to avoid creating array?
769
//### Replicate code in innerClasses here to avoid consing?
770
for (ClassDoc icd : innerClasses()) {
771
if (icd.name().equals(className) ||
772
//### This is from original javadoc but it looks suspicious to me...
773
//### I believe it is attempting to compensate for the confused
774
//### convention of including the nested class qualifiers in the
775
//### 'name' of the inner class, rather than the true simple name.
776
icd.name().endsWith("." + className)) {
777
return icd;
778
} else {
779
ClassDoc innercd = ((ClassDocImpl) icd).searchClass(className);
780
if (innercd != null) {
781
return innercd;
782
}
783
}
784
}
785
786
// check in this package
787
cd = containingPackage().findClass(className);
788
if (cd != null) {
789
return cd;
790
}
791
792
// make sure that this symbol has been completed
793
if (tsym.completer != null) {
794
tsym.complete();
795
}
796
797
// search imports
798
799
if (tsym.sourcefile != null) {
800
801
//### This information is available only for source classes.
802
803
Env<AttrContext> compenv = env.enter.getEnv(tsym);
804
if (compenv == null) return null;
805
806
Scope s = compenv.toplevel.namedImportScope;
807
for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
808
if (e.sym.kind == Kinds.TYP) {
809
ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
810
return c;
811
}
812
}
813
814
s = compenv.toplevel.starImportScope;
815
for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
816
if (e.sym.kind == Kinds.TYP) {
817
ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
818
return c;
819
}
820
}
821
}
822
823
return null; // not found
824
}
825
826
827
private boolean hasParameterTypes(MethodSymbol method, String[] argTypes) {
828
829
if (argTypes == null) {
830
// wildcard
831
return true;
832
}
833
834
int i = 0;
835
List<Type> types = method.type.getParameterTypes();
836
837
if (argTypes.length != types.length()) {
838
return false;
839
}
840
841
for (Type t : types) {
842
String argType = argTypes[i++];
843
// For vararg method, "T..." matches type T[].
844
if (i == argTypes.length) {
845
argType = argType.replace("...", "[]");
846
}
847
if (!hasTypeName(env.types.erasure(t), argType)) { //###(gj)
848
return false;
849
}
850
}
851
return true;
852
}
853
// where
854
private boolean hasTypeName(Type t, String name) {
855
return
856
name.equals(TypeMaker.getTypeName(t, true))
857
||
858
name.equals(TypeMaker.getTypeName(t, false))
859
||
860
(qualifiedName() + "." + name).equals(TypeMaker.getTypeName(t, true));
861
}
862
863
864
865
/**
866
* Find a method in this class scope.
867
* Search order: this class, interfaces, superclasses, outerclasses.
868
* Note that this is not necessarily what the compiler would do!
869
*
870
* @param methodName the unqualified name to search for.
871
* @param paramTypes the array of Strings for method parameter types.
872
* @return the first MethodDocImpl which matches, null if not found.
873
*/
874
public MethodDocImpl findMethod(String methodName, String[] paramTypes) {
875
// Use hash table 'searched' to avoid searching same class twice.
876
//### It is not clear how this could happen.
877
return searchMethod(methodName, paramTypes, new HashSet<ClassDocImpl>());
878
}
879
880
private MethodDocImpl searchMethod(String methodName,
881
String[] paramTypes, Set<ClassDocImpl> searched) {
882
//### Note that this search is not necessarily what the compiler would do!
883
884
Names names = tsym.name.table.names;
885
// do not match constructors
886
if (names.init.contentEquals(methodName)) {
887
return null;
888
}
889
890
ClassDocImpl cdi;
891
MethodDocImpl mdi;
892
893
if (searched.contains(this)) {
894
return null;
895
}
896
searched.add(this);
897
898
//DEBUG
899
/*---------------------------------*
900
System.out.print("searching " + this + " for " + methodName);
901
if (paramTypes == null) {
902
System.out.println("()");
903
} else {
904
System.out.print("(");
905
for (int k=0; k < paramTypes.length; k++) {
906
System.out.print(paramTypes[k]);
907
if ((k + 1) < paramTypes.length) {
908
System.out.print(", ");
909
}
910
}
911
System.out.println(")");
912
}
913
*---------------------------------*/
914
915
// search current class
916
Scope.Entry e = tsym.members().lookup(names.fromString(methodName));
917
918
//### Using modifier filter here isn't really correct,
919
//### but emulates the old behavior. Instead, we should
920
//### apply the normal rules of visibility and inheritance.
921
922
if (paramTypes == null) {
923
// If no parameters specified, we are allowed to return
924
// any method with a matching name. In practice, the old
925
// code returned the first method, which is now the last!
926
// In order to provide textually identical results, we
927
// attempt to emulate the old behavior.
928
MethodSymbol lastFound = null;
929
for (; e.scope != null; e = e.next()) {
930
if (e.sym.kind == Kinds.MTH) {
931
//### Should intern methodName as Name.
932
if (e.sym.name.toString().equals(methodName)) {
933
lastFound = (MethodSymbol)e.sym;
934
}
935
}
936
}
937
if (lastFound != null) {
938
return env.getMethodDoc(lastFound);
939
}
940
} else {
941
for (; e.scope != null; e = e.next()) {
942
if (e.sym != null &&
943
e.sym.kind == Kinds.MTH) {
944
//### Should intern methodName as Name.
945
if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
946
return env.getMethodDoc((MethodSymbol)e.sym);
947
}
948
}
949
}
950
}
951
952
//### If we found a MethodDoc above, but which did not pass
953
//### the modifier filter, we should return failure here!
954
955
// search superclass
956
cdi = (ClassDocImpl)superclass();
957
if (cdi != null) {
958
mdi = cdi.searchMethod(methodName, paramTypes, searched);
959
if (mdi != null) {
960
return mdi;
961
}
962
}
963
964
// search interfaces
965
ClassDoc intf[] = interfaces();
966
for (int i = 0; i < intf.length; i++) {
967
cdi = (ClassDocImpl)intf[i];
968
mdi = cdi.searchMethod(methodName, paramTypes, searched);
969
if (mdi != null) {
970
return mdi;
971
}
972
}
973
974
// search enclosing class
975
cdi = (ClassDocImpl)containingClass();
976
if (cdi != null) {
977
mdi = cdi.searchMethod(methodName, paramTypes, searched);
978
if (mdi != null) {
979
return mdi;
980
}
981
}
982
983
//###(gj) As a temporary measure until type variables are better
984
//### handled, try again without the parameter types.
985
//### This should most often find the right method, and occassionally
986
//### find the wrong one.
987
//if (paramTypes != null) {
988
// return findMethod(methodName, null);
989
//}
990
991
return null;
992
}
993
994
/**
995
* Find constructor in this class.
996
*
997
* @param constrName the unqualified name to search for.
998
* @param paramTypes the array of Strings for constructor parameters.
999
* @return the first ConstructorDocImpl which matches, null if not found.
1000
*/
1001
public ConstructorDoc findConstructor(String constrName,
1002
String[] paramTypes) {
1003
Names names = tsym.name.table.names;
1004
for (Scope.Entry e = tsym.members().lookup(names.fromString("<init>")); e.scope != null; e = e.next()) {
1005
if (e.sym.kind == Kinds.MTH) {
1006
if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
1007
return env.getConstructorDoc((MethodSymbol)e.sym);
1008
}
1009
}
1010
}
1011
1012
//###(gj) As a temporary measure until type variables are better
1013
//### handled, try again without the parameter types.
1014
//### This will often find the right constructor, and occassionally
1015
//### find the wrong one.
1016
//if (paramTypes != null) {
1017
// return findConstructor(constrName, null);
1018
//}
1019
1020
return null;
1021
}
1022
1023
/**
1024
* Find a field in this class scope.
1025
* Search order: this class, outerclasses, interfaces,
1026
* superclasses. IMP: If see tag is defined in an inner class,
1027
* which extends a super class and if outerclass and the super
1028
* class have a visible field in common then Java compiler cribs
1029
* about the ambiguity, but the following code will search in the
1030
* above given search order.
1031
*
1032
* @param fieldName the unqualified name to search for.
1033
* @return the first FieldDocImpl which matches, null if not found.
1034
*/
1035
public FieldDoc findField(String fieldName) {
1036
return searchField(fieldName, new HashSet<ClassDocImpl>());
1037
}
1038
1039
private FieldDocImpl searchField(String fieldName, Set<ClassDocImpl> searched) {
1040
Names names = tsym.name.table.names;
1041
if (searched.contains(this)) {
1042
return null;
1043
}
1044
searched.add(this);
1045
1046
for (Scope.Entry e = tsym.members().lookup(names.fromString(fieldName)); e.scope != null; e = e.next()) {
1047
if (e.sym.kind == Kinds.VAR) {
1048
//### Should intern fieldName as Name.
1049
return env.getFieldDoc((VarSymbol)e.sym);
1050
}
1051
}
1052
1053
//### If we found a FieldDoc above, but which did not pass
1054
//### the modifier filter, we should return failure here!
1055
1056
ClassDocImpl cdi = (ClassDocImpl)containingClass();
1057
if (cdi != null) {
1058
FieldDocImpl fdi = cdi.searchField(fieldName, searched);
1059
if (fdi != null) {
1060
return fdi;
1061
}
1062
}
1063
1064
// search superclass
1065
cdi = (ClassDocImpl)superclass();
1066
if (cdi != null) {
1067
FieldDocImpl fdi = cdi.searchField(fieldName, searched);
1068
if (fdi != null) {
1069
return fdi;
1070
}
1071
}
1072
1073
// search interfaces
1074
ClassDoc intf[] = interfaces();
1075
for (int i = 0; i < intf.length; i++) {
1076
cdi = (ClassDocImpl)intf[i];
1077
FieldDocImpl fdi = cdi.searchField(fieldName, searched);
1078
if (fdi != null) {
1079
return fdi;
1080
}
1081
}
1082
1083
return null;
1084
}
1085
1086
/**
1087
* Get the list of classes declared as imported.
1088
* These are called "single-type-import declarations" in the JLS.
1089
* This method is deprecated in the ClassDoc interface.
1090
*
1091
* @return an array of ClassDocImpl representing the imported classes.
1092
*
1093
* @deprecated Import declarations are implementation details that
1094
* should not be exposed here. In addition, not all imported
1095
* classes are imported through single-type-import declarations.
1096
*/
1097
@Deprecated
1098
public ClassDoc[] importedClasses() {
1099
// information is not available for binary classfiles
1100
if (tsym.sourcefile == null) return new ClassDoc[0];
1101
1102
ListBuffer<ClassDocImpl> importedClasses = new ListBuffer<ClassDocImpl>();
1103
1104
Env<AttrContext> compenv = env.enter.getEnv(tsym);
1105
if (compenv == null) return new ClassDocImpl[0];
1106
1107
Name asterisk = tsym.name.table.names.asterisk;
1108
for (JCTree t : compenv.toplevel.defs) {
1109
if (t.hasTag(IMPORT)) {
1110
JCTree imp = ((JCImport) t).qualid;
1111
if ((TreeInfo.name(imp) != asterisk) &&
1112
(imp.type.tsym.kind & Kinds.TYP) != 0) {
1113
importedClasses.append(
1114
env.getClassDoc((ClassSymbol)imp.type.tsym));
1115
}
1116
}
1117
}
1118
1119
return importedClasses.toArray(new ClassDocImpl[importedClasses.length()]);
1120
}
1121
1122
/**
1123
* Get the list of packages declared as imported.
1124
* These are called "type-import-on-demand declarations" in the JLS.
1125
* This method is deprecated in the ClassDoc interface.
1126
*
1127
* @return an array of PackageDocImpl representing the imported packages.
1128
*
1129
* ###NOTE: the syntax supports importing all inner classes from a class as well.
1130
* @deprecated Import declarations are implementation details that
1131
* should not be exposed here. In addition, this method's
1132
* return type does not allow for all type-import-on-demand
1133
* declarations to be returned.
1134
*/
1135
@Deprecated
1136
public PackageDoc[] importedPackages() {
1137
// information is not available for binary classfiles
1138
if (tsym.sourcefile == null) return new PackageDoc[0];
1139
1140
ListBuffer<PackageDocImpl> importedPackages = new ListBuffer<PackageDocImpl>();
1141
1142
//### Add the implicit "import java.lang.*" to the result
1143
Names names = tsym.name.table.names;
1144
importedPackages.append(env.getPackageDoc(env.reader.enterPackage(names.java_lang)));
1145
1146
Env<AttrContext> compenv = env.enter.getEnv(tsym);
1147
if (compenv == null) return new PackageDocImpl[0];
1148
1149
for (JCTree t : compenv.toplevel.defs) {
1150
if (t.hasTag(IMPORT)) {
1151
JCTree imp = ((JCImport) t).qualid;
1152
if (TreeInfo.name(imp) == names.asterisk) {
1153
JCFieldAccess sel = (JCFieldAccess)imp;
1154
Symbol s = sel.selected.type.tsym;
1155
PackageDocImpl pdoc = env.getPackageDoc(s.packge());
1156
if (!importedPackages.contains(pdoc))
1157
importedPackages.append(pdoc);
1158
}
1159
}
1160
}
1161
1162
return importedPackages.toArray(new PackageDocImpl[importedPackages.length()]);
1163
}
1164
1165
/**
1166
* Return the type's dimension information.
1167
* Always return "", as this is not an array type.
1168
*/
1169
public String dimension() {
1170
return "";
1171
}
1172
1173
/**
1174
* Return this type as a class, which it already is.
1175
*/
1176
public ClassDoc asClassDoc() {
1177
return this;
1178
}
1179
1180
/**
1181
* Return null (unless overridden), as this is not an annotation type.
1182
*/
1183
public AnnotationTypeDoc asAnnotationTypeDoc() {
1184
return null;
1185
}
1186
1187
/**
1188
* Return null, as this is not a class instantiation.
1189
*/
1190
public ParameterizedType asParameterizedType() {
1191
return null;
1192
}
1193
1194
/**
1195
* Return null, as this is not a type variable.
1196
*/
1197
public TypeVariable asTypeVariable() {
1198
return null;
1199
}
1200
1201
/**
1202
* Return null, as this is not a wildcard type.
1203
*/
1204
public WildcardType asWildcardType() {
1205
return null;
1206
}
1207
1208
/**
1209
* Returns null, as this is not an annotated type.
1210
*/
1211
public AnnotatedType asAnnotatedType() {
1212
return null;
1213
}
1214
1215
/**
1216
* Return false, as this is not a primitive type.
1217
*/
1218
public boolean isPrimitive() {
1219
return false;
1220
}
1221
1222
//--- Serialization ---
1223
1224
//### These methods ignore modifier filter.
1225
1226
/**
1227
* Return true if this class implements <code>java.io.Serializable</code>.
1228
*
1229
* Since <code>java.io.Externalizable</code> extends
1230
* <code>java.io.Serializable</code>,
1231
* Externalizable objects are also Serializable.
1232
*/
1233
public boolean isSerializable() {
1234
try {
1235
return env.types.isSubtype(type, env.syms.serializableType);
1236
} catch (CompletionFailure ex) {
1237
// quietly ignore completion failures
1238
return false;
1239
}
1240
}
1241
1242
/**
1243
* Return true if this class implements
1244
* <code>java.io.Externalizable</code>.
1245
*/
1246
public boolean isExternalizable() {
1247
try {
1248
return env.types.isSubtype(type, env.externalizableSym.type);
1249
} catch (CompletionFailure ex) {
1250
// quietly ignore completion failures
1251
return false;
1252
}
1253
}
1254
1255
/**
1256
* Return the serialization methods for this class.
1257
*
1258
* @return an array of <code>MethodDocImpl</code> that represents
1259
* the serialization methods for this class.
1260
*/
1261
public MethodDoc[] serializationMethods() {
1262
if (serializedForm == null) {
1263
serializedForm = new SerializedForm(env, tsym, this);
1264
}
1265
//### Clone this?
1266
return serializedForm.methods();
1267
}
1268
1269
/**
1270
* Return the Serializable fields of class.<p>
1271
*
1272
* Return either a list of default fields documented by
1273
* <code>serial</code> tag<br>
1274
* or return a single <code>FieldDoc</code> for
1275
* <code>serialPersistentField</code> member.
1276
* There should be a <code>serialField</code> tag for
1277
* each Serializable field defined by an <code>ObjectStreamField</code>
1278
* array component of <code>serialPersistentField</code>.
1279
*
1280
* @returns an array of <code>FieldDoc</code> for the Serializable fields
1281
* of this class.
1282
*
1283
* @see #definesSerializableFields()
1284
* @see SerialFieldTagImpl
1285
*/
1286
public FieldDoc[] serializableFields() {
1287
if (serializedForm == null) {
1288
serializedForm = new SerializedForm(env, tsym, this);
1289
}
1290
//### Clone this?
1291
return serializedForm.fields();
1292
}
1293
1294
/**
1295
* Return true if Serializable fields are explicitly defined with
1296
* the special class member <code>serialPersistentFields</code>.
1297
*
1298
* @see #serializableFields()
1299
* @see SerialFieldTagImpl
1300
*/
1301
public boolean definesSerializableFields() {
1302
if (!isSerializable() || isExternalizable()) {
1303
return false;
1304
} else {
1305
if (serializedForm == null) {
1306
serializedForm = new SerializedForm(env, tsym, this);
1307
}
1308
//### Clone this?
1309
return serializedForm.definesSerializableFields();
1310
}
1311
}
1312
1313
/**
1314
* Determine if a class is a RuntimeException.
1315
* <p>
1316
* Used only by ThrowsTagImpl.
1317
*/
1318
boolean isRuntimeException() {
1319
return tsym.isSubClass(env.syms.runtimeExceptionType.tsym, env.types);
1320
}
1321
1322
/**
1323
* Return the source position of the entity, or null if
1324
* no position is available.
1325
*/
1326
@Override
1327
public SourcePosition position() {
1328
if (tsym.sourcefile == null) return null;
1329
return SourcePositionImpl.make(tsym.sourcefile,
1330
(tree==null) ? Position.NOPOS : tree.pos,
1331
lineMap);
1332
}
1333
}
1334
1335