Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libjava / classpath / tools / gnu / classpath / tools / gjdoc / ClassDocImpl.java
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
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
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.
84    public ConstructorDoc[] constructors() {
85       return constructors(true);
86    }
87
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.
93    public boolean definesSerializableFields() {
94       return definesSerializableFields;
95    }
96
97    // Return fields in class.
98    public FieldDoc[] fields() {
99       return fields(true);
100    }
101
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
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
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.
176    public ClassDoc[] importedClasses() {
177       return importedClasses;
178    }
179
180    // Get the list of packages declared as imported.
181    public PackageDoc[] importedPackages() {
182       return importedPackages;
183    }
184
185    // Return inner classes within this class.
186    public ClassDoc[] innerClasses() {
187       return innerClasses(true);
188    }
189
190    public ClassDoc[] innerClasses(boolean filtered) {
191       return filtered ? filteredInnerClasses : unfilteredInnerClasses;
192    }
193
194    void setFilteredInnerClasses(ClassDoc[] filteredInnerClasses) {
195       this.filteredInnerClasses=filteredInnerClasses;
196    }
197
198    void setInnerClasses(ClassDoc[] unfilteredInnerClasses) {
199       this.unfilteredInnerClasses=unfilteredInnerClasses;
200    }
201
202    // Return interfaces implemented by this class or interfaces extended by this interface.
203    public ClassDoc[] interfaces() {
204       return interfaces;
205    }
206
207    public void setInterfaces(ClassDoc[] interfaces) {
208       this.interfaces=interfaces;
209    }
210
211    // Return true if this class is abstract
212    public boolean isAbstract() {
213       return isAbstract || isInterface();
214    }
215
216    public boolean isInterface() {
217       return isInterface;
218    }
219
220    public boolean isAnnotation() {
221       return isAnnotation;
222    }
223
224   public boolean isEnum()
225   {
226     return isEnum;
227   }
228
229    // Return true if this class is abstract
230    public void setIsAbstract(boolean b) {
231       this.isAbstract=b;
232    }
233
234    // Return true if this class implements java.io.Externalizable.
235    public boolean isExternalizable() {
236       return implementsInterface("java.io.Externalizable");
237    }
238
239    // Return true if this class implements java.io.Serializable.
240    public boolean isSerializable() {
241       return implementsInterface("java.io.Serializable");
242    }
243
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.
263    public MethodDoc[] methods() {
264       return methods(true);
265    }
266
267    // Return methods in class.
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.
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.
283    public MethodDoc[] serializationMethods() {
284       return serializationMethods;
285    }
286
287    // Test whether this class is a subclass of the specified class.
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
297    public ClassDoc superclass() {
298       return superclass;
299    }
300
301    // Implementation of Interface Type
302
303    public ClassDoc asClassDoc() {
304
305       return (ClassDoc)this;
306    }
307
308    public String typeName() { return name(); }
309
310    public String qualifiedTypeName() {
311       return (containingPackage()!=null && !containingPackage().equals(PackageDocImpl.DEFAULT_PACKAGE))?(containingPackage().name()+"."+name()):(name());
312    }
313
314    public String qualifiedName() { return qualifiedTypeName(); }
315
316    public String dimension() { return dimension; }
317
318    public String toString() { return "ClassDoc{"+qualifiedTypeName()+"}"; }
319
320    public TypeVariable asTypeVariable() { return null; }
321
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
524    public void setFields(FieldDoc[] fields) {
525       this.unfilteredFields=fields;
526    }
527
528    public void setFilteredFields(FieldDoc[] fields) {
529       this.filteredFields=fields;
530    }
531
532    public void setSerializableFields(FieldDoc[] sfields) {
533       this.serializableFields=sfields;
534    }
535
536    public void setMethods(MethodDoc[] methods) {
537       this.unfilteredMethods=methods;
538    }
539
540    public void setFilteredMethods(MethodDoc[] methods) {
541       this.filteredMethods=methods;
542    }
543
544    public void setConstructors(ConstructorDoc[] constructors) {
545       this.unfilteredConstructors=constructors;
546    }
547
548    public void setFilteredConstructors(ConstructorDoc[] constructors) {
549       this.filteredConstructors=constructors;
550    }
551
552    // Returns the name of this Doc item.
553    public String name() {
554       if (containingClass==null) {
555          return className;
556       }
557       else {
558          return containingClass.name()+"."+className;
559       }
560    }
561
562    public String getClassName() {
563       return className;
564    }
565
566    public void setClass(String className) {
567       this.className=className;
568    }
569
570    void setSuperclass(ClassDoc superclass) {
571       this.superclass=superclass;
572    }
573
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
673    public FieldDoc findFieldRec(String name) {
674       return findFieldRec(this, name);
675    }
676
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
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
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
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.
773    public boolean isClass() {
774       return !isInterface;
775    }
776
777    // return true if this Doc is include in the active set.
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
788    void setIsIncluded(boolean b) {
789       this.isIncluded=b;
790    }
791
792    private boolean isIncluded=false;
793
794    void setImportedClasses(ClassDoc[] importedClasses) {
795       this.importedClasses=importedClasses;
796    }
797
798    private static Map<String,Type> typeMap = new HashMap<String,Type>();
799
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
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
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
877    public boolean isOrdinaryClass() {
878       return !isException() && !isError() && !isInterface();
879    }
880
881    public void setIsInterface(boolean b) {
882       this.isInterface=b;
883    }
884
885    public void setIsAnnotation(boolean b) {
886       this.isAnnotation=b;
887    }
888
889    public void setIsEnum(boolean b)
890    {
891      isEnum = b;
892    }
893
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
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
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
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
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
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
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
1000    void setMaybeSerMethodList(List<MethodDoc> maybeSerMethodList) {
1001       this.maybeSerMethodList=maybeSerMethodList;
1002    }
1003
1004    public void setDimension(String dimension) {
1005       this.dimension = dimension;
1006    }
1007
1008    public Object clone() throws CloneNotSupportedException {
1009       ClassDocImpl result = (ClassDocImpl)super.clone();
1010       result.baseClassDoc = baseClassDoc;
1011       return result;
1012    }
1013
1014    public int superHashCode()
1015    {
1016       return super.hashCode();
1017    }
1018
1019    public int hashCode()
1020    {
1021       return qualifiedTypeName().hashCode();
1022    }
1023
1024    public ClassDoc getBaseClassDoc()
1025    {
1026       return baseClassDoc;
1027    }
1028
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
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
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
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
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
1121    public boolean isPrimitive()
1122    {
1123       return false;
1124    }
1125
1126    // Compares this Object with the specified Object for order.
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
1172    public void setImportStatementList(List<String> importStatementList)
1173    {
1174       this.importStatementList = new LinkedList<String>();
1175       this.importStatementList.addAll(importStatementList);
1176    }
1177
1178    public List getImportSpecifierList()
1179    {
1180       return importStatementList;
1181    }
1182
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    */
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    */
1254   void setTypeParameters(List variables)
1255   {
1256     typeParameters =
1257       (TypeVariable[]) variables.toArray(new TypeVariable[variables.size()]);
1258   }
1259
1260 }