1 /* gnu.classpath.tools.gjdoc.ClassDocImpl
2    Copyright (C) 2001, 2012 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 package gnu.classpath.tools.gjdoc;
39 
40 import com.sun.javadoc.*;
41 import java.util.*;
42 import java.io.*;
43 import gnu.classpath.tools.gjdoc.expr.EvaluatorEnvironment;
44 import gnu.classpath.tools.gjdoc.expr.CircularExpressionException;
45 import gnu.classpath.tools.gjdoc.expr.IllegalExpressionException;
46 import gnu.classpath.tools.gjdoc.expr.UnknownIdentifierException;
47 
48 public class ClassDocImpl
49    extends ProgramElementDocImpl
50    implements ClassDoc, WritableType, EvaluatorEnvironment {
51 
52    private ClassDoc baseClassDoc;
53    private ClassDoc[] importedClasses;
54    private PackageDoc[] importedPackages;
55    private boolean definesSerializableFields;
56    private FieldDoc[] serialPersistentField;
57    private MethodDoc[] serializationMethods;
58    private String dimension = "";
59 
ClassDocImpl(ClassDoc containingClass, PackageDoc containingPackage, int accessLevel, boolean isFinal, boolean isStatic, SourcePosition position)60    public ClassDocImpl(ClassDoc containingClass,
61                        PackageDoc containingPackage,
62                        int accessLevel,
63                        boolean isFinal,
64                        boolean isStatic,
65                        SourcePosition position) {
66       super(containingClass, containingPackage, accessLevel, isFinal, isStatic,
67             position);
68       this.baseClassDoc = this;
69    }
70 
ClassDocImpl(ClassDoc containingClass, PackageDoc containingPackage, ClassDoc[] importedClasses, PackageDoc[] importedPackages, SourcePosition position)71    public ClassDocImpl(ClassDoc containingClass,
72                        PackageDoc containingPackage,
73                        ClassDoc[] importedClasses,
74                        PackageDoc[] importedPackages,
75                        SourcePosition position) {
76       super(containingClass, containingPackage,
77             position);
78       this.importedClasses=importedClasses;
79       this.importedPackages=importedPackages;
80       this.baseClassDoc = this;
81    }
82 
83    // Return constructors in class.
constructors()84    public ConstructorDoc[] constructors() {
85       return constructors(true);
86    }
87 
constructors(boolean filter)88    public ConstructorDoc[] constructors(boolean filter) {
89       return filter ? filteredConstructors : unfilteredConstructors;
90    }
91 
92    // Return true if Serializable fields are explicitly defined with the special class member serialPersistentFields.
definesSerializableFields()93    public boolean definesSerializableFields() {
94       return definesSerializableFields;
95    }
96 
97    // Return fields in class.
fields()98    public FieldDoc[] fields() {
99       return fields(true);
100    }
101 
fields(boolean filter)102    public FieldDoc[] fields(boolean filter) {
103       return filter ? filteredFields : unfilteredFields;
104    }
105 
106    private static Set<String> primitiveNames;
107    static {
108       primitiveNames = new HashSet<String>();
109       primitiveNames.add("int");
110       primitiveNames.add("long");
111       primitiveNames.add("char");
112       primitiveNames.add("short");
113       primitiveNames.add("byte");
114       primitiveNames.add("float");
115       primitiveNames.add("double");
116       primitiveNames.add("boolean");
117    }
118 
119   private Map<String,ClassDoc> findClassCache = new HashMap<String,ClassDoc>();
120 
findClass(String className, String dimension)121    public ClassDoc findClass(String className, String dimension)
122    {
123       ClassDoc cached = findClassCache.get(className + dimension);
124       if (null != cached) {
125          return cached;
126       }
127       else {
128          ClassDoc classDoc = findClass(className);
129 
130          if (null!=classDoc) {
131             try {
132                if (classDoc.dimension().equals(dimension)) {
133                   return classDoc;
134                }
135                else {
136                   ClassDoc rc = (ClassDoc) ((WritableType)classDoc).clone();
137                   ((WritableType)rc).setDimension(dimension);
138                   findClassCache.put(className + dimension, rc);
139                   return rc;
140                }
141             }
142             catch (CloneNotSupportedException e) {
143                throw new RuntimeException(e);
144             }
145          }
146          else {
147             return null;
148          }
149       }
150    }
151 
findClass(String className)152    public ClassDoc findClass(String className)
153    {
154       String qualifiedName = Main.getRootDoc().resolveClassName(className, this);
155       ClassDoc rc=Main.getRootDoc().classNamed(qualifiedName);
156 
157       if (null == rc) {
158          for (ClassDoc cdi=this; cdi!=null; cdi=cdi.containingClass()) {
159             for (ClassDoc sdi=cdi; sdi!=null; sdi=sdi.superclass()) {
160                if (sdi instanceof ClassDocProxy) {
161                   ClassDoc realClass = Main.getRootDoc().classNamed(sdi.qualifiedName());
162                   if (null != realClass) {
163                      sdi = realClass;
164                   }
165                }
166                rc=Main.getRootDoc().classNamed(sdi.qualifiedName()+"."+className);
167                if (rc!=null) return rc;
168             }
169          }
170       }
171 
172       return rc;
173    }
174 
175    // Get the list of classes declared as imported.
importedClasses()176    public ClassDoc[] importedClasses() {
177       return importedClasses;
178    }
179 
180    // Get the list of packages declared as imported.
importedPackages()181    public PackageDoc[] importedPackages() {
182       return importedPackages;
183    }
184 
185    // Return inner classes within this class.
innerClasses()186    public ClassDoc[] innerClasses() {
187       return innerClasses(true);
188    }
189 
innerClasses(boolean filtered)190    public ClassDoc[] innerClasses(boolean filtered) {
191       return filtered ? filteredInnerClasses : unfilteredInnerClasses;
192    }
193 
setFilteredInnerClasses(ClassDoc[] filteredInnerClasses)194    void setFilteredInnerClasses(ClassDoc[] filteredInnerClasses) {
195       this.filteredInnerClasses=filteredInnerClasses;
196    }
197 
setInnerClasses(ClassDoc[] unfilteredInnerClasses)198    void setInnerClasses(ClassDoc[] unfilteredInnerClasses) {
199       this.unfilteredInnerClasses=unfilteredInnerClasses;
200    }
201 
202    // Return interfaces implemented by this class or interfaces extended by this interface.
interfaces()203    public ClassDoc[] interfaces() {
204       return interfaces;
205    }
206 
setInterfaces(ClassDoc[] interfaces)207    public void setInterfaces(ClassDoc[] interfaces) {
208       this.interfaces=interfaces;
209    }
210 
211    // Return true if this class is abstract
isAbstract()212    public boolean isAbstract() {
213       return isAbstract || isInterface();
214    }
215 
isInterface()216    public boolean isInterface() {
217       return isInterface;
218    }
219 
isAnnotation()220    public boolean isAnnotation() {
221       return isAnnotation;
222    }
223 
isEnum()224   public boolean isEnum()
225   {
226     return isEnum;
227   }
228 
229    // Return true if this class is abstract
setIsAbstract(boolean b)230    public void setIsAbstract(boolean b) {
231       this.isAbstract=b;
232    }
233 
234    // Return true if this class implements java.io.Externalizable.
isExternalizable()235    public boolean isExternalizable() {
236       return implementsInterface("java.io.Externalizable");
237    }
238 
239    // Return true if this class implements java.io.Serializable.
isSerializable()240    public boolean isSerializable() {
241       return implementsInterface("java.io.Serializable");
242    }
243 
implementsInterface(String name)244    public boolean implementsInterface(String name) {
245       for (ClassDoc cdi=this; cdi!=null; cdi=(ClassDoc)cdi.superclass()) {
246          if (cdi instanceof ClassDocImpl) {
247             ClassDoc[] cdiInterfaces=(ClassDoc[])cdi.interfaces();
248             if (null != cdiInterfaces) {
249                for (int i=0; i<cdiInterfaces.length; ++i) {
250                   if (cdiInterfaces[i].qualifiedName().equals(name))
251                      return true;
252                }
253             }
254          }
255          else {
256             //throw new RuntimeException("implementsInterface(\""+name+"\") failed: Not a ClassDocImpl:"+cdi);
257          }
258       }
259       return false;
260    }
261 
262    // Return methods in class.
methods()263    public MethodDoc[] methods() {
264       return methods(true);
265    }
266 
267    // Return methods in class.
methods(boolean filter)268    public MethodDoc[] methods(boolean filter) {
269       return filter ? filteredMethods : unfilteredMethods;
270    }
271 
272    // Return the Serializable fields of class. Return either a list of default fields documented by serial tag or return a single FieldDoc for serialPersistentField member.
serializableFields()273    public FieldDoc[] serializableFields() {
274       if (serialPersistentField!=null) {
275          return serialPersistentField;
276       }
277       else{
278          return serializableFields;
279       }
280    }
281 
282    // Return the serialization methods for this class.
serializationMethods()283    public MethodDoc[] serializationMethods() {
284       return serializationMethods;
285    }
286 
287    // Test whether this class is a subclass of the specified class.
subclassOf(ClassDoc cd)288    public boolean subclassOf(ClassDoc cd) {
289       for (ClassDocImpl cdi=(ClassDocImpl)superclass(); cdi!=null; cdi=(ClassDocImpl)cdi.superclass()) {
290          if (cdi.equals(cd))
291             return true;
292       }
293       return false;
294    }
295 
296    // Return the superclass of this class
superclass()297    public ClassDoc superclass() {
298       return superclass;
299    }
300 
301    // Implementation of Interface Type
302 
asClassDoc()303    public ClassDoc asClassDoc() {
304 
305       return (ClassDoc)this;
306    }
307 
typeName()308    public String typeName() { return name(); }
309 
qualifiedTypeName()310    public String qualifiedTypeName() {
311       return (containingPackage()!=null && !containingPackage().equals(PackageDocImpl.DEFAULT_PACKAGE))?(containingPackage().name()+"."+name()):(name());
312    }
313 
qualifiedName()314    public String qualifiedName() { return qualifiedTypeName(); }
315 
dimension()316    public String dimension() { return dimension; }
317 
toString()318    public String toString() { return "ClassDoc{"+qualifiedTypeName()+"}"; }
319 
asTypeVariable()320    public TypeVariable asTypeVariable() { return null; }
321 
createInstance(ClassDoc containingClass, PackageDoc containingPackage, ClassDoc[] importedClasses, PackageDoc[] importedPackages, char[] source, int startIndex, int endIndex, List<String> importStatementList)322    public static ClassDocImpl createInstance(ClassDoc containingClass,
323                                              PackageDoc containingPackage,
324                                              ClassDoc[] importedClasses,
325                                              PackageDoc[] importedPackages,
326                                              char[] source, int startIndex, int endIndex,
327                                              List<String> importStatementList) throws ParseException, IOException {
328 
329       String superclassName = "java.lang.Object";
330 
331       ClassDocImpl rc=new ClassDocImpl(containingClass,
332                                        containingPackage,
333                                        importedClasses,
334                                        importedPackages,
335                                        null);
336       rc.setImportStatementList(importStatementList);
337       List<String> implementedInterfaces = new ArrayList<String>();
338 
339       String word="";
340       int item=0;
341 
342       final int STATE_NORMAL = 1;
343       final int STATE_SLASHC = 2;
344       final int STATE_STARC  = 3;
345       final int STATE_ANNO   = 4;
346 
347       int state=STATE_NORMAL;
348       int varLevel=0;
349       int parLevel=0;
350       char prev=0;
351       for (int ndx=startIndex; ndx<=endIndex; ++ndx) {
352          char c=(ndx==endIndex)?10:source[ndx];
353          boolean processWord=false;
354          if (state==STATE_SLASHC) {
355             if (c=='\n') {
356                state=STATE_NORMAL;
357                c=0;
358             }
359          }
360          else if (state==STATE_STARC) {
361             if (c=='/' && prev=='*') {
362                state=STATE_NORMAL;
363                c=0;
364             }
365          }
366          else {
367             if (c=='/' && prev=='/') {
368                state=STATE_SLASHC;
369                c=0;
370                word=word.substring(0,word.length()-1);
371                processWord=true;
372             }
373             else if (c=='*' && prev=='/') {
374                state=STATE_STARC;
375                c=0;
376                word=word.substring(0,word.length()-1);
377                processWord=true;
378             }
379             else if (c=='@') {
380                state=STATE_ANNO;
381                word += c;
382             }
383             else if (c=='(' && state==STATE_ANNO) {
384                ++parLevel;
385                word += c;
386             }
387             else if (c==')' && state==STATE_ANNO) {
388                --parLevel;
389                word += c;
390                if (parLevel == 0)
391                    state=STATE_NORMAL;
392             }
393             else if (c=='<')
394               {
395                 ++varLevel;
396                 word += c;
397               }
398             else if (c=='>')
399               {
400                 --varLevel;
401                 word += c;
402               }
403             else if (c=='{' && parLevel == 0 ||
404                      c==',' && varLevel == 0 && parLevel == 0 ||
405                      Parser.WHITESPACE.indexOf(c)>=0 && parLevel == 0 && varLevel == 0) {
406                processWord=true;
407                state=STATE_NORMAL;
408             }
409             else {
410                word+=c;
411             }
412 
413             if (processWord && word.length()>0) {
414                if (item==0) {
415                   if (rc.processModifier(word)) {
416                   }
417                   else if (word.equals("abstract")) {
418                      rc.setIsAbstract(true);
419                   }
420                   else if (word.equals("class")) {
421                      rc.setIsInterface(false);
422                      item=1;
423                   }
424                   else if (word.equals("enum"))
425                     {
426                       rc.setIsEnum(true);
427                       item = 1;
428                     }
429                   else if (word.equals("interface")) {
430                      rc.setIsInterface(true);
431                      item=1;
432                   }
433                   else if (word.equals("@interface")) {
434                      rc.setIsInterface(true);
435                      rc.setIsAnnotation(true);
436                      item=1;
437                   }
438                   else if (word.equals("strictfp")) {
439                   }
440                   else {
441                      Main.getRootDoc().printWarning("unknown modifier '"+word+"'");
442                   }
443                }
444                else if (word.equals("extends") && !rc.isAnnotation()) {
445                   if (rc.isInterface()) {
446                      item=3;
447                   }
448                   else {
449                      item=2;
450                   }
451                }
452                else if (word.equals("implements") && !rc.isAnnotation()) {
453                   item=3;
454                }
455                else if (item==1) {
456                  int parameterIndex = word.indexOf("<");
457                  if (parameterIndex == -1)
458                    rc.setClass(word);
459                  else
460                    {
461                      rc.setClass(word.substring(0, parameterIndex));
462                      parseTypeVariables(rc,word.substring(parameterIndex,
463                                                           word.length()));
464                    }
465                }
466                else if (item==2) {
467                   //Debug.log(9,"setting baseclass of "+rc+" to "+word);
468                  int parameterIndex = word.indexOf("<");
469                  if (parameterIndex == -1)
470                    superclassName=word;
471                  else
472                    {
473                      /* FIXME: Parse type parameters */
474                      superclassName=word.substring(0,parameterIndex);
475                    }
476                }
477                else if (item==3) {
478                  int parameterIndex = word.indexOf("<");
479                  if (parameterIndex == -1)
480                    implementedInterfaces.add(word);
481                  else
482                    {
483                      /* FIXME: Parse type parameters */
484                      implementedInterfaces.add(word.substring(0,parameterIndex));
485                    }
486                }
487                word="";
488             }
489 
490             if (c=='{' && state==STATE_NORMAL) break;
491          }
492          prev=c;
493       }
494 
495       if (null != containingClass
496           && containingClass.isInterface()) {
497          rc.accessLevel = ACCESS_PUBLIC;
498       }
499 
500       if (rc.name()==null) {
501          throw new ParseException("No classdef found in expression \""+new String(source,startIndex,endIndex-startIndex)+"\"");
502       }
503 
504       rc.setPosition(ClassDocImpl.getPosition(rc, source, startIndex));
505 
506       ClassDoc superclassProxy=new ClassDocProxy(superclassName, rc);
507 
508       if (!rc.qualifiedName().equals("java.lang.Object")) {
509          rc.setSuperclass(superclassProxy);
510       }
511 
512       ClassDoc[] interfaces=new ClassDoc[implementedInterfaces.size()];
513       for (int i=0; i<interfaces.length; ++i) {
514          interfaces[i]=new ClassDocProxy(implementedInterfaces.get(i), rc);
515       }
516       rc.setInterfaces(interfaces);
517 
518       if (rc.isInterface() && rc.containingClass()!=null) {
519          rc.setIsStatic(true);
520       }
521       return rc;
522    }
523 
setFields(FieldDoc[] fields)524    public void setFields(FieldDoc[] fields) {
525       this.unfilteredFields=fields;
526    }
527 
setFilteredFields(FieldDoc[] fields)528    public void setFilteredFields(FieldDoc[] fields) {
529       this.filteredFields=fields;
530    }
531 
setSerializableFields(FieldDoc[] sfields)532    public void setSerializableFields(FieldDoc[] sfields) {
533       this.serializableFields=sfields;
534    }
535 
setMethods(MethodDoc[] methods)536    public void setMethods(MethodDoc[] methods) {
537       this.unfilteredMethods=methods;
538    }
539 
setFilteredMethods(MethodDoc[] methods)540    public void setFilteredMethods(MethodDoc[] methods) {
541       this.filteredMethods=methods;
542    }
543 
setConstructors(ConstructorDoc[] constructors)544    public void setConstructors(ConstructorDoc[] constructors) {
545       this.unfilteredConstructors=constructors;
546    }
547 
setFilteredConstructors(ConstructorDoc[] constructors)548    public void setFilteredConstructors(ConstructorDoc[] constructors) {
549       this.filteredConstructors=constructors;
550    }
551 
552    // Returns the name of this Doc item.
name()553    public String name() {
554       if (containingClass==null) {
555          return className;
556       }
557       else {
558          return containingClass.name()+"."+className;
559       }
560    }
561 
getClassName()562    public String getClassName() {
563       return className;
564    }
565 
setClass(String className)566    public void setClass(String className) {
567       this.className=className;
568    }
569 
setSuperclass(ClassDoc superclass)570    void setSuperclass(ClassDoc superclass) {
571       this.superclass=superclass;
572    }
573 
resolve()574    public void resolve() throws ParseException {
575       if (!resolved) {
576          resolved=true;
577 
578          if (containingClass!=null)
579             ((ClassDocImpl)containingClass).resolve();
580 
581          //Debug.log(9,"resolving class '"+qualifiedName()+"'");
582          /*
583          for (int i=0; i<importedPackages.length; ++i) {
584                Debug.log(9,"class "+qualifiedName()+" imports "+importedPackages[i].name());
585          }
586          */
587 
588          if (superclass instanceof ClassDocProxy) {
589 
590             ClassDoc realClassDoc=findClass(superclass.qualifiedName());
591 
592             if (realClassDoc==null) {
593                /*
594                if (true) { // Main.recursiveClasses) {
595                   throw new ParseException("In class '"+qualifiedName()+"': class '"+className+"' not found.");
596                }
597                */
598             }
599             else {
600                superclass=realClassDoc;
601             }
602          }
603 
604          if (null != interfaces) {
605             for (int i=0; i<interfaces.length; ++i) {
606                if (interfaces[i] instanceof ClassDocProxy) {
607                   //Debug.log(9,"class "+qualifiedName()+" implements "+interfaces[i].qualifiedName());
608                   ClassDoc realClassDoc=findClass(interfaces[i].qualifiedName());
609                   if (realClassDoc==null) {
610                      /*
611                        if (Main.recursiveClasses) {
612                        throw new ParseException("In class '"+qualifiedName()+"': class '"+className+"' not found.");
613                        }
614                      */
615                   }
616                   else {
617                      //Debug.log(9,"found class '"+className+"': "+interfaces[i]);
618                      interfaces[i]=realClassDoc;
619                   }
620                }
621             }
622          }
623 
624          if (unfilteredFields!=null) {
625             for (int i=0; i<unfilteredFields.length; ++i) {
626                ((FieldDocImpl)unfilteredFields[i]).resolve();
627                if (unfilteredFields[i].name().equals("serialPersistentField")) {
628                   serialPersistentField=new FieldDoc[]{unfilteredFields[i]};
629                   definesSerializableFields=true;
630                }
631             }
632          }
633 
634          if (unfilteredMethods!=null) {
635             for (int i=0; i<unfilteredMethods.length; ++i) {
636                ((MethodDocImpl)unfilteredMethods[i]).resolve();
637             }
638          }
639 
640          if (unfilteredConstructors!=null) {
641             for (int i=0; i<unfilteredConstructors.length; ++i) {
642                ((ConstructorDocImpl)unfilteredConstructors[i]).resolve();
643             }
644          }
645 
646          List<MethodDoc> isSerMethodList = new ArrayList<MethodDoc>();
647 
648          if (null != maybeSerMethodList) {
649             for (Iterator<MethodDoc> it = maybeSerMethodList.iterator(); it.hasNext(); ) {
650                MethodDocImpl method=(MethodDocImpl)it.next();
651                method.resolve();
652 
653                if (((method.name().equals("readObject")
654                      && method.signature().equals("(java.io.ObjectInputStream)"))
655                     || (method.name().equals("writeObject")
656                         && method.signature().equals("(java.io.ObjectOutputStream)"))
657                     || (method.name().equals("readExternal")
658                         && method.signature().equals("(java.io.ObjectInput)"))
659                     || (method.name().equals("writeExternal")
660                         && method.signature().equals("(java.io.ObjectOutput)"))
661                     || (method.name().equals("readResolve")
662                         && method.signature().equals("()")))) {
663 
664                   isSerMethodList.add(method);
665                }
666             }
667             this.serializationMethods = isSerMethodList.toArray(new MethodDoc[isSerMethodList.size()]);
668             maybeSerMethodList=null;
669          }
670       }
671    }
672 
findFieldRec(String name)673    public FieldDoc findFieldRec(String name) {
674       return findFieldRec(this, name);
675    }
676 
findFieldRec(ClassDoc classDoc, String name)677    private static FieldDoc findFieldRec(ClassDoc classDoc, String name)
678    {
679       FieldDoc field = findField(classDoc, name);
680       if (null!=field) {
681          return field;
682       }
683       else {
684          ClassDoc[] interfaces = classDoc.interfaces();
685          for (int i=0; i<interfaces.length; ++i) {
686             field = findFieldRec(interfaces[i], name);
687             if (null != field) {
688                return field;
689             }
690          }
691          if (null != classDoc.superclass()) {
692             return findFieldRec(classDoc.superclass(), name);
693          }
694          else {
695             return null;
696          }
697       }
698    }
699 
findField(ClassDoc classDoc, String name)700    private static FieldDoc findField(ClassDoc classDoc, String name)
701    {
702       FieldDoc[] fields = classDoc.fields(false);
703       for (int i=0; i<fields.length; ++i) {
704          if (fields[i].name().equals(name)) {
705             return fields[i];
706          }
707       }
708       return null;
709    }
710 
findField(String fieldName)711    public FieldDoc findField(String fieldName) {
712       for (int i=0; i<filteredFields.length; ++i) {
713          if (filteredFields[i].name().equals(fieldName)) {
714             return filteredFields[i];
715          }
716       }
717       return null;
718    }
719 
resolveComments()720    public void resolveComments() {
721 
722       super.resolveComments();
723 
724       if (null != unfilteredFields) {
725          for (int i=0; i<unfilteredFields.length; ++i) {
726             ((FieldDocImpl)unfilteredFields[i]).resolveComments();
727          }
728       }
729 
730       if (null != serializableFields) {
731          for (int i=0; i<serializableFields.length; ++i) {
732             ((FieldDocImpl)serializableFields[i]).resolveComments();
733          }
734       }
735       if (null != unfilteredMethods) {
736          for (int i=0; i<unfilteredMethods.length; ++i) {
737             ((MethodDocImpl)unfilteredMethods[i]).resolveComments();
738          }
739       }
740       if (null != unfilteredConstructors) {
741          for (int i=0; i<unfilteredConstructors.length; ++i) {
742             ((ConstructorDocImpl)unfilteredConstructors[i]).resolveComments();
743          }
744       }
745 
746       resolveTags();
747    }
748 
749 
750    private String className=null;
751 
752    private boolean isAbstract;
753    private boolean isInterface;
754    private boolean isAnnotation;
755    private boolean isEnum;
756    private ClassDoc[] interfaces;
757    private ClassDoc[] filteredInnerClasses;
758    private ClassDoc[] unfilteredInnerClasses;
759    private FieldDoc[] filteredFields;
760    private FieldDoc[] unfilteredFields;
761    private FieldDoc[] serializableFields;
762    private MethodDoc[] filteredMethods;
763    private MethodDoc[] unfilteredMethods;
764    private ConstructorDoc[] filteredConstructors;
765    private ConstructorDoc[] unfilteredConstructors;
766    private TypeVariable[] typeParameters;
767 
768    private boolean resolved=false;
769 
770    private ClassDoc superclass;
771 
772    // Is this Doc item a class.
isClass()773    public boolean isClass() {
774       return !isInterface;
775    }
776 
777    // return true if this Doc is include in the active set.
isIncluded()778    public boolean isIncluded() {
779       if (this == baseClassDoc) {
780          return isIncluded
781             || (null != containingClass && Main.getInstance().includeAccessLevel(accessLevel));
782       }
783       else {
784          return baseClassDoc.isIncluded();
785       }
786    }
787 
setIsIncluded(boolean b)788    void setIsIncluded(boolean b) {
789       this.isIncluded=b;
790    }
791 
792    private boolean isIncluded=false;
793 
setImportedClasses(ClassDoc[] importedClasses)794    void setImportedClasses(ClassDoc[] importedClasses) {
795       this.importedClasses=importedClasses;
796    }
797 
798    private static Map<String,Type> typeMap = new HashMap<String,Type>();
799 
typeForString(String typeName)800    Type typeForString(String typeName) throws ParseException {
801      //String orgTypename=typeName;
802       int ndx=typeName.indexOf('[');
803       String dim="";
804       if (ndx>=0) {
805          for (int i=ndx; i<typeName.length(); ++i) {
806             if ("[]".indexOf(typeName.charAt(i))>=0) {
807                dim+=typeName.charAt(i);
808             }
809          }
810          typeName=typeName.substring(0,ndx).trim();
811       }
812 
813       ClassDoc classDoc = findClass(typeName, dim);
814       if (null != classDoc) {
815          return classDoc;
816       }
817 
818       Type type = typeMap.get(typeName+dim);
819       if (null!=type) {
820          try {
821             if (type.dimension().equals(dim)) {
822                return type;
823             }
824             else {
825                Type rc = (Type) ((WritableType)type).clone();
826                ((WritableType)rc).setDimension(dim);
827                return rc;
828             }
829          }
830          catch (CloneNotSupportedException e) {
831             throw new ParseException(e.toString());
832          }
833       }
834 
835       if ("boolean".equals(typeName)
836           || "char".equals(typeName)
837           || "byte".equals(typeName)
838           || "short".equals(typeName)
839           || "int".equals(typeName)
840           || "long".equals(typeName)
841           || "void".equals(typeName)
842           || "float".equals(typeName)
843           || "double".equals(typeName)) {
844          Type rc=new TypeImpl(null, typeName, dim);
845          typeMap.put(typeName+dim, rc);
846          return rc;
847       }
848 
849       if (Main.getInstance().isDocletRunning()) {
850          //System.err.println(findClass("java.lang.String"));
851          //throw new ParseException("Doclet running, class not found: "+typeName+" ("+orgTypename+")");
852       }
853       Type rc=new ClassDocProxy(typeName, this);
854       ((WritableType)rc).setDimension(dim);
855       return rc;
856    }
857 
isException()858    public boolean isException() {
859       for (ClassDoc cdi=this;
860            cdi!=null;
861            cdi=cdi.superclass()) {
862 
863          if ("java.lang.Exception".equals(cdi.qualifiedName()))
864             return true;
865       }
866       return false;
867    }
868 
isError()869    public boolean isError() {
870       for (ClassDoc cdi=this; cdi!=null; cdi=cdi.superclass()) {
871          if ("java.lang.Error".equals(cdi.qualifiedName()))
872             return true;
873       }
874       return false;
875    }
876 
isOrdinaryClass()877    public boolean isOrdinaryClass() {
878       return !isException() && !isError() && !isInterface();
879    }
880 
setIsInterface(boolean b)881    public void setIsInterface(boolean b) {
882       this.isInterface=b;
883    }
884 
setIsAnnotation(boolean b)885    public void setIsAnnotation(boolean b) {
886       this.isAnnotation=b;
887    }
888 
setIsEnum(boolean b)889    public void setIsEnum(boolean b)
890    {
891      isEnum = b;
892    }
893 
findExecutableRec(String nameAndSignature)894    public ExecutableMemberDoc findExecutableRec(String nameAndSignature) {
895 
896       ExecutableMemberDoc rc;
897       for (ClassDoc cdi=this; cdi!=null; ) {
898          rc=findMethod(cdi, nameAndSignature);
899          if (rc!=null) return rc;
900          rc=findConstructor(cdi, nameAndSignature);
901          if (rc!=null) return rc;
902 
903          ClassDoc _superclass = cdi.superclass();
904          if (null == _superclass) {
905             break;
906          }
907          else {
908             cdi = _superclass;
909          }
910       }
911       return null;
912   }
913 
findConstructor(ClassDoc classDoc, String nameAndSignature)914    public static ConstructorDoc findConstructor(ClassDoc classDoc, String nameAndSignature) {
915       int ndx=nameAndSignature.indexOf('(');
916       if (ndx<=0)
917          return null;
918       else {
919          String fullSignature = resolveSignature(classDoc, nameAndSignature.substring(ndx));
920          return findConstructor(classDoc,
921                                 nameAndSignature.substring(0,ndx),
922                                 fullSignature);
923       }
924    }
925 
findConstructor(ClassDoc classDoc, String name, String signature)926    public static ConstructorDoc findConstructor(ClassDoc classDoc, String name, String signature) {
927       ConstructorDoc[] filteredConstructors = classDoc.constructors(true);
928       if (null != filteredConstructors) {
929          for (int i=0; i<filteredConstructors.length; ++i) {
930             ConstructorDoc constructor = filteredConstructors[i];
931             if (constructor.name().equals(name) && constructor.signature().equals(signature))
932                return constructor;
933          }
934       }
935       return null;
936    }
937 
findMethod(ClassDoc classDoc, String nameAndSignature)938    public static MethodDoc findMethod(ClassDoc classDoc, String nameAndSignature) {
939       int ndx=nameAndSignature.indexOf('(');
940       if (ndx<=0) {
941          return null;
942       }
943       else {
944          String name = nameAndSignature.substring(0,ndx);
945          String fullSignature = resolveSignature(classDoc, nameAndSignature.substring(ndx));
946          return findMethod(classDoc, name, fullSignature);
947       }
948    }
949 
resolveSignature(ClassDoc classDoc, String signature)950    private static String resolveSignature(ClassDoc classDoc, String signature)
951    {
952       signature = signature.substring(1, signature.length() - 1).trim();
953       if (0 == signature.length()) {
954          return "()";
955       }
956       StringTokenizer st = new StringTokenizer(signature, ",");
957       StringBuffer fullSignature = new StringBuffer("(");
958       while (st.hasMoreTokens()) {
959          String type = st.nextToken().trim();
960          int ndx = type.length();
961          while (ndx > 0 && type.charAt(ndx - 1) == '[' || type.charAt(ndx - 1) == ']') {
962             -- ndx;
963          }
964          String dim = type.substring(ndx);
965          type = type.substring(0, ndx);
966          ClassDoc typeClass = classDoc.findClass(type);
967          if (fullSignature.length() > 1) {
968             fullSignature.append(",");
969          }
970          if (null != typeClass) {
971             fullSignature.append(typeClass.qualifiedName());
972          }
973          else {
974             fullSignature.append(type);
975          }
976          fullSignature.append(dim);
977       }
978       fullSignature.append(')');
979       return fullSignature.toString();
980    }
981 
findMethod(ClassDoc classDoc, String name, String signature)982    public static MethodDoc findMethod(ClassDoc classDoc, String name, String signature) {
983       MethodDoc[] filteredMethods = classDoc.methods(true);
984       if (null != filteredMethods) {
985          for (int i=0; i<filteredMethods.length; ++i) {
986             MethodDoc method = filteredMethods[i];
987             if (method.name().equals(name) && method.signature().equals(signature))
988                return method;
989          }
990       }
991       return null;
992    }
993 
equals(Object o)994    public boolean equals(Object o) {
995       return (o!=null) && (o instanceof ClassDoc) && ((ClassDoc)o).qualifiedName().equals(qualifiedName());
996    }
997 
998    private List<MethodDoc> maybeSerMethodList;
999 
setMaybeSerMethodList(List<MethodDoc> maybeSerMethodList)1000    void setMaybeSerMethodList(List<MethodDoc> maybeSerMethodList) {
1001       this.maybeSerMethodList=maybeSerMethodList;
1002    }
1003 
setDimension(String dimension)1004    public void setDimension(String dimension) {
1005       this.dimension = dimension;
1006    }
1007 
clone()1008    public Object clone() throws CloneNotSupportedException {
1009       ClassDocImpl result = (ClassDocImpl)super.clone();
1010       result.baseClassDoc = baseClassDoc;
1011       return result;
1012    }
1013 
superHashCode()1014    public int superHashCode()
1015    {
1016       return super.hashCode();
1017    }
1018 
hashCode()1019    public int hashCode()
1020    {
1021       return qualifiedTypeName().hashCode();
1022    }
1023 
getBaseClassDoc()1024    public ClassDoc getBaseClassDoc()
1025    {
1026       return baseClassDoc;
1027    }
1028 
getFieldDoc(String name)1029    public FieldDoc getFieldDoc(String name)
1030    {
1031       for (int i=0; i<unfilteredFields.length; ++i) {
1032          if (name.equals(unfilteredFields[i].name())) {
1033             return unfilteredFields[i];
1034          }
1035       }
1036       return null;
1037    }
1038 
getMethodDoc(String name, String signature)1039    public MethodDoc getMethodDoc(String name, String signature)
1040    {
1041       for (int i=0; i<unfilteredMethods.length; ++i) {
1042          if (name.equals(unfilteredMethods[i].name())
1043              && signature.equals(unfilteredMethods[i].signature())) {
1044             return unfilteredMethods[i];
1045          }
1046       }
1047       return null;
1048    }
1049 
1050 
getConstructorDoc(String signature)1051    public ConstructorDoc getConstructorDoc(String signature)
1052    {
1053       for (int i=0; i<unfilteredConstructors.length; ++i) {
1054          if (signature.equals(unfilteredConstructors[i].signature())) {
1055             return unfilteredConstructors[i];
1056          }
1057       }
1058       return null;
1059    }
1060 
findFieldValue(String identifier, ClassDoc classDoc, String fieldName, Set<FieldDoc> visitedFields)1061    private Object findFieldValue(String identifier,
1062                                  ClassDoc classDoc,
1063                                  String fieldName,
1064                                  Set<FieldDoc> visitedFields)
1065       throws UnknownIdentifierException, IllegalExpressionException
1066    {
1067       while (classDoc != null) {
1068          if (classDoc instanceof ClassDocImpl) {
1069             FieldDocImpl fieldDoc
1070                = (FieldDocImpl)((ClassDocImpl)classDoc).getFieldDoc(fieldName);
1071             if (visitedFields.contains(fieldDoc)) {
1072                throw new CircularExpressionException("Circular reference detected");
1073             }
1074             else if (null != fieldDoc) {
1075                return fieldDoc.constantValue(visitedFields);
1076             }
1077          }
1078          else {
1079             ClassDoc[] _interfaces = classDoc.interfaces();
1080             if (null != _interfaces) {
1081                for (int i=0; i<_interfaces.length; ++i) {
1082                   if (_interfaces[i] instanceof ClassDocImpl) {
1083                      FieldDocImpl fieldDoc
1084                         = (FieldDocImpl)((ClassDocImpl)_interfaces[i]).getFieldDoc(fieldName);
1085                      if (visitedFields.contains(fieldDoc)) {
1086                         throw new CircularExpressionException("Circular reference detected");
1087                      }
1088                      else if (null != fieldDoc) {
1089                         return fieldDoc.constantValue(visitedFields);
1090                      }
1091                   }
1092                }
1093             }
1094          }
1095          classDoc = classDoc.superclass();
1096       }
1097       throw new UnknownIdentifierException(identifier);
1098    }
1099 
getValue(String identifier, Set<FieldDoc> visitedFields)1100    public Object getValue(String identifier, Set<FieldDoc> visitedFields)
1101       throws UnknownIdentifierException, IllegalExpressionException
1102    {
1103       int ndx = identifier.lastIndexOf('.');
1104       if (ndx >= 0) {
1105          String _className = identifier.substring(0, ndx);
1106          String _fieldName = identifier.substring(ndx + 1);
1107 
1108          ClassDoc _classDoc = findClass(_className);
1109          if (null != _classDoc) {
1110             return findFieldValue(identifier, _classDoc, _fieldName, visitedFields);
1111          }
1112          else {
1113             throw new UnknownIdentifierException(identifier);
1114          }
1115       }
1116       else {
1117          return findFieldValue(identifier, this, identifier, visitedFields);
1118       }
1119    }
1120 
isPrimitive()1121    public boolean isPrimitive()
1122    {
1123       return false;
1124    }
1125 
1126    // Compares this Object with the specified Object for order.
compareTo(Doc d)1127    public int compareTo(Doc d) {
1128       int rc;
1129 
1130       if (d instanceof ClassDocImpl) {
1131 
1132          ClassDocImpl c1 = this;
1133          ClassDocImpl c2 = (ClassDocImpl)d;
1134 
1135          if (null != c1.containingClass() && null == c2.containingClass()) {
1136             rc = c1.containingClass().compareTo(c2);
1137             if (0 == rc) {
1138                rc = 1;
1139             }
1140             return rc;
1141          }
1142          else if (null == c1.containingClass() && null != c2.containingClass()) {
1143             rc = c1.compareTo(c2.containingClass());
1144             if (0 == rc) {
1145                rc = -1;
1146             }
1147             return rc;
1148          }
1149          else if (null != c1.containingClass() && null != c2.containingClass()) {
1150             rc = c1.containingClass().compareTo(c2.containingClass());
1151             if (0 != rc) {
1152                return rc;
1153             }
1154          }
1155 
1156          rc = super.compareTo(d);
1157          if (0 == rc) {
1158             return Main.getInstance().getCollator().compare(containingPackage().name(),
1159                                                             c2.containingPackage().name());
1160          }
1161          else {
1162             return rc;
1163          }
1164       }
1165       else {
1166          return 1;
1167       }
1168    }
1169 
1170    private List<String> importStatementList;
1171 
setImportStatementList(List<String> importStatementList)1172    public void setImportStatementList(List<String> importStatementList)
1173    {
1174       this.importStatementList = new LinkedList<String>();
1175       this.importStatementList.addAll(importStatementList);
1176    }
1177 
getImportSpecifierList()1178    public List getImportSpecifierList()
1179    {
1180       return importStatementList;
1181    }
1182 
typeParameters()1183   public TypeVariable[] typeParameters()
1184   {
1185     return typeParameters;
1186   }
1187 
1188   /**
1189    * <p>
1190    * Parses the type variables declared in the class definition.
1191    * The syntax is:
1192    * </p>
1193    * <p>
1194    * <dl>
1195    * <dt>TypeParameters:</dt>
1196    * <dd><code>&lt; <em>TypeParameter</em> { <em>, TypeParameter }</code></dd>
1197    * <dt>TypeParameter:</dt>
1198    * <dd><code><em>Identifier</em> { <strong>extends</strong> <em>Bound</em>
1199    *     }</dd>
1200    * <dt>Bound:</dt>
1201    * <dd><code><em>Type</em>{<strong>&</strong> <em>Type</em> } </dd>
1202    * </dl>
1203    *
1204    * @param rc the owning class.
1205    * @param typeVariables the string to be parsed.
1206    * @throws ParseException if parsing fails.
1207    */
parseTypeVariables(ClassDocImpl rc, String typeVariables)1208   public static void parseTypeVariables(ClassDocImpl rc,
1209                                         String typeVariables)
1210     throws ParseException
1211   {
1212     List parsedBounds = null;
1213     StringTokenizer parameters = new StringTokenizer(typeVariables,
1214                                                      Parser.WHITESPACE +
1215                                                      "<>,");
1216     List variables = new ArrayList();
1217     while (parameters.hasMoreTokens())
1218       {
1219         String parameter = parameters.nextToken();
1220         StringTokenizer parts = new StringTokenizer(parameter,
1221                                                     Parser.WHITESPACE);
1222         TypeVariableImpl variable = new TypeVariableImpl(rc.qualifiedName(),
1223                                                          parts.nextToken(),"",
1224                                                          rc);
1225         if (parts.hasMoreTokens())
1226           {
1227             if (!parts.nextToken().equals("extends"))
1228               throw new ParseException("Invalid type parameter: " + parameter);
1229             StringTokenizer bounds = new StringTokenizer(parts.nextToken(),
1230                                                          Parser.WHITESPACE
1231                                                          + "&");
1232             parsedBounds = new ArrayList();
1233             while (bounds.hasMoreTokens())
1234               {
1235                 String bound = bounds.nextToken();
1236                 int nameSep = bound.lastIndexOf(".");
1237                 String packageName = bound.substring(0, nameSep);
1238                 String boundName = bound.substring(nameSep, bound.length());
1239                 parsedBounds.add(new TypeImpl(packageName,boundName,""));
1240               }
1241           }
1242         if (parsedBounds != null)
1243           variable.setBounds(parsedBounds);
1244         variables.add(variable);
1245       }
1246     rc.setTypeParameters(variables);
1247   }
1248 
1249   /**
1250    * Set the type parameters to the contents of the supplied list.
1251    *
1252    * @param variables a list of type parameters.
1253    */
setTypeParameters(List variables)1254   void setTypeParameters(List variables)
1255   {
1256     typeParameters =
1257       (TypeVariable[]) variables.toArray(new TypeVariable[variables.size()]);
1258   }
1259 
1260 }
1261