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>< <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