1 35 package org.codehaus.groovy.ast; 36 37 import groovy.lang.GroovyObject; 38 import groovy.lang.MissingClassException; 39 import groovy.lang.Script; 40 import org.codehaus.groovy.ast.expr.Expression; 41 import org.codehaus.groovy.ast.stmt.BlockStatement; 42 import org.codehaus.groovy.ast.stmt.EmptyStatement; 43 import org.codehaus.groovy.ast.stmt.Statement; 44 import org.objectweb.asm.Constants; 45 46 import java.lang.reflect.Constructor ; 47 import java.lang.reflect.Method ; 48 import java.security.AccessControlException ; 49 import java.util.*; 50 import java.util.logging.Level ; 51 import java.util.logging.Logger ; 52 53 59 public class ClassNode extends MetadataNode implements Constants { 60 61 private static final String [] defaultImports = {"java.lang", "java.util", "groovy.lang", "groovy.util"}; 62 63 private Logger log = Logger.getLogger(getClass().getName()); 64 65 private String name; 66 private int modifiers; 67 private String superClass; 68 private String [] interfaces; 69 private MixinNode[] mixins; 70 private List constructors = new ArrayList(); 71 private List methods = new ArrayList(); 72 private List fields = new ArrayList(); 73 private List properties = new ArrayList(); 74 private Map fieldIndex = new HashMap(); 75 private ModuleNode module; 76 private CompileUnit compileUnit; 77 private boolean staticClass = false; 78 private boolean scriptBody = false; 79 private boolean script; 80 private ClassNode superClassNode; 81 82 83 private MethodNode enclosingMethod = null; 85 86 public MethodNode getEnclosingMethod() { 87 return enclosingMethod; 88 } 89 90 public void setEnclosingMethod(MethodNode enclosingMethod) { 91 this.enclosingMethod = enclosingMethod; 92 } 93 94 95 102 public ClassNode(String name, int modifiers, String superClass) { 103 this(name, modifiers, superClass, EMPTY_STRING_ARRAY, MixinNode.EMPTY_ARRAY); 104 } 105 106 113 public ClassNode(String name, int modifiers, String superClass, String [] interfaces, MixinNode[] mixins) { 114 this.name = name; 115 this.modifiers = modifiers; 116 this.superClass = superClass; 117 this.interfaces = interfaces; 118 this.mixins = mixins; 119 120 if ((modifiers & ACC_SUPER) == 0) { 122 this.modifiers += ACC_SUPER; 123 } 124 } 125 126 public String getSuperClass() { 127 return superClass; 128 } 129 130 public void setSuperClass(String superClass) { 131 this.superClass = superClass; 132 } 133 134 public List getFields() { 135 return fields; 136 } 137 138 public String [] getInterfaces() { 139 return interfaces; 140 } 141 142 public MixinNode[] getMixins() { 143 return mixins; 144 } 145 146 public List getMethods() { 147 return methods; 148 } 149 150 public List getAbstractMethods() { 151 152 List result = new ArrayList(); 153 for (Iterator methIt = getAllDeclaredMethods().iterator(); methIt.hasNext();) { 154 MethodNode method = (MethodNode) methIt.next(); 155 if (method.isAbstract()) result.add(method); 156 } 157 if (result.size() == 0) 158 return null; 159 else 160 return result; 161 } 162 163 public List getAllDeclaredMethods() { 164 return new ArrayList(getDeclaredMethodsMap().values()); 165 } 166 167 168 protected Map getDeclaredMethodsMap() { 169 ClassNode parent = getSuperClassNode(); 171 Map result = null; 172 if (parent != null) 173 result = parent.getDeclaredMethodsMap(); 174 else 175 result = new HashMap(); 176 177 for (int i = 0; i < interfaces.length; i++) { 179 String interfaceName = interfaces[i]; 180 ClassNode iface = findClassNode(interfaceName); 181 Map ifaceMethodsMap = iface.getDeclaredMethodsMap(); 182 for (Iterator iter = ifaceMethodsMap.keySet().iterator(); iter.hasNext();) { 183 String methSig = (String ) iter.next(); 184 if (!result.containsKey(methSig)) { 185 MethodNode methNode = (MethodNode) ifaceMethodsMap.get(methSig); 186 result.put(methSig, methNode); 187 } 188 } 189 } 190 191 for (Iterator iter = getMethods().iterator(); iter.hasNext();) { 193 MethodNode method = (MethodNode) iter.next(); 194 String sig = method.getTypeDescriptor(); 195 if (result.containsKey(sig)) { 196 MethodNode inheritedMethod = (MethodNode) result.get(sig); 197 if (inheritedMethod.isAbstract()) { 198 result.put(sig, method); 199 } 200 } else { 201 result.put(sig, method); 202 } 203 } 204 return result; 205 } 206 207 protected int findMatchingMethodInList(MethodNode method, List methods) { 208 for (int i = 0; i < methods.size(); i++) { 209 MethodNode someMeth = (MethodNode) methods.get(i); 210 if (someMeth.getName().equals(method.getName()) 211 && parametersEqual(someMeth.getParameters(), method.getParameters())) 212 return i; 213 } 214 return -1; 215 } 216 217 public String getName() { 218 return name; 219 } 220 221 public int getModifiers() { 222 return modifiers; 223 } 224 225 public List getProperties() { 226 return properties; 227 } 228 229 public List getDeclaredConstructors() { 230 return constructors; 231 } 232 233 public ModuleNode getModule() { 234 return module; 235 } 236 237 public void setModule(ModuleNode module) { 238 this.module = module; 239 if (module != null) { 240 this.compileUnit = module.getUnit(); 241 } 242 } 243 244 public void addField(FieldNode node) { 245 node.setOwner(getName()); 246 fields.add(node); 247 fieldIndex.put(node.getName(), node); 248 } 249 250 public void addProperty(PropertyNode node) { 251 FieldNode field = node.getField(); 252 addField(field); 253 254 properties.add(node); 255 } 256 257 public PropertyNode addProperty(String name, 258 int modifiers, 259 String type, 260 Expression initialValueExpression, 261 Statement getterBlock, 262 Statement setterBlock) { 263 PropertyNode node = 264 new PropertyNode(name, modifiers, type, getName(), initialValueExpression, getterBlock, setterBlock); 265 addProperty(node); 266 return node; 267 } 268 269 public void addConstructor(ConstructorNode node) { 270 constructors.add(node); 271 } 272 273 public ConstructorNode addConstructor(int modifiers, Parameter[] parameters, Statement code) { 274 ConstructorNode node = new ConstructorNode(modifiers, parameters, code); 275 addConstructor(node); 276 return node; 277 } 278 279 public void addMethod(MethodNode node) { 280 methods.add(node); 281 node.declaringClass = this; 282 } 283 284 291 public MethodNode addMethod(String name, 292 int modifiers, 293 String returnType, 294 Parameter[] parameters, 295 Statement code) { 296 MethodNode other = getDeclaredMethod(name, parameters); 297 if (other != null) { 299 return other; 300 } 301 MethodNode node = new MethodNode(name, modifiers, returnType, parameters, code); 302 addMethod(node); 303 return node; 304 } 305 306 309 public MethodNode addSyntheticMethod(String name, 310 int modifiers, 311 String returnType, 312 Parameter[] parameters, 313 Statement code) { 314 MethodNode answer = addMethod(name, modifiers, returnType, parameters, code); 315 answer.setSynthetic(true); 316 return answer; 317 } 318 319 public FieldNode addField(String name, int modifiers, String type, Expression initialValue) { 320 FieldNode node = new FieldNode(name, modifiers, type, getName(), initialValue); 321 addField(node); 322 return node; 323 } 324 325 public void addInterface(String name) { 326 boolean skip = false; 328 for (int i = 0; i < interfaces.length; i++) { 329 if (name.equals(interfaces[i])) { 330 skip = true; 331 } 332 } 333 if (!skip) { 334 String [] newInterfaces = new String [interfaces.length + 1]; 335 System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length); 336 newInterfaces[interfaces.length] = name; 337 interfaces = newInterfaces; 338 } 339 } 340 341 public void addMixin(MixinNode mixin) { 342 boolean skip = false; 344 String mixinName = mixin.getName(); 345 for (int i = 0; i < mixins.length; i++) { 346 if (mixinName.equals(mixins[i].getName())) { 347 skip = true; 348 } 349 } 350 if (!skip) { 351 MixinNode[] newMixins = new MixinNode[mixins.length + 1]; 352 System.arraycopy(mixins, 0, newMixins, 0, mixins.length); 353 newMixins[mixins.length] = mixin; 354 mixins = newMixins; 355 } 356 } 357 358 public FieldNode getField(String name) { 359 return (FieldNode) fieldIndex.get(name); 360 } 361 362 366 public FieldNode getOuterField(String name) { 367 return null; 368 } 369 370 375 public ClassNode getOuterClass() { 376 return null; 377 } 378 379 public void addStaticInitializerStatements(List staticStatements) { 380 MethodNode method = null; 381 List declaredMethods = getDeclaredMethods("<clinit>"); 382 if (declaredMethods.isEmpty()) { 383 method = 384 addMethod("<clinit>", ACC_PUBLIC | ACC_STATIC, "void", Parameter.EMPTY_ARRAY, new BlockStatement()); 385 } else { 386 method = (MethodNode) declaredMethods.get(0); 387 } 388 BlockStatement block = null; 389 Statement statement = method.getCode(); 390 if (statement == null) { 391 block = new BlockStatement(); 392 } else if (statement instanceof BlockStatement) { 393 block = (BlockStatement) statement; 394 } else { 395 block = new BlockStatement(); 396 block.addStatement(statement); 397 } 398 block.addStatements(staticStatements); 399 } 400 401 404 public List getDeclaredMethods(String name) { 405 List answer = new ArrayList(); 406 for (Iterator iter = methods.iterator(); iter.hasNext();) { 407 MethodNode method = (MethodNode) iter.next(); 408 if (name.equals(method.getName())) { 409 answer.add(method); 410 } 411 } 412 return answer; 413 } 414 415 418 public List getMethods(String name) { 419 List answer = new ArrayList(); 420 ClassNode node = this; 421 do { 422 for (Iterator iter = node.methods.iterator(); iter.hasNext();) { 423 MethodNode method = (MethodNode) iter.next(); 424 if (name.equals(method.getName())) { 425 answer.add(method); 426 } 427 } 428 node = node.getSuperClassNode(); 429 } while (node != null); 430 return answer; 431 } 432 433 436 public MethodNode getDeclaredMethod(String name, Parameter[] parameters) { 437 for (Iterator iter = methods.iterator(); iter.hasNext();) { 438 MethodNode method = (MethodNode) iter.next(); 439 if (name.equals(method.getName()) && parametersEqual(method.getParameters(), parameters)) { 440 return method; 441 } 442 } 443 return null; 444 } 445 446 449 public boolean isDerivedFrom(String name) { 450 ClassNode node = getSuperClassNode(); 451 while (node != null) { 452 if (name.equals(node.getName())) { 453 return true; 454 } 455 node = node.getSuperClassNode(); 456 } 457 return false; 458 } 459 460 464 public boolean isDerivedFromGroovyObject() { 465 return implementsInteface(GroovyObject.class.getName()); 466 } 467 468 472 public boolean implementsInteface(String name) { 473 ClassNode node = this; 474 do { 475 if (node.declaresInterface(name)) { 476 return true; 477 } 478 node = node.getSuperClassNode(); 479 } while (node != null); 480 return false; 481 } 482 483 487 public boolean declaresInterface(String name) { 488 int size = interfaces.length; 489 for (int i = 0; i < size; i++) { 490 if (name.equals(interfaces[i])) { 491 return true; 492 } 493 } 494 return false; 495 } 496 497 500 public ClassNode getSuperClassNode() { 501 if (superClass != null && superClass.length() > 0 && superClassNode == null && !name.equals("java.lang.Object")) { 502 String temp = resolveClassName(superClass); 504 if (temp == null) { 505 throw new MissingClassException(superClass, this, "No such superclass"); 506 } else { 507 superClass = temp; 508 } 509 superClassNode = findClassNode(superClass); 510 } 511 return superClassNode; 512 } 513 514 520 public ClassNode findClassNode(String type) { 521 ClassNode answer = null; 522 CompileUnit theCompileUnit = getCompileUnit(); 523 if (theCompileUnit != null) { 524 answer = theCompileUnit.getClass(type); 525 if (answer == null) { 526 Class theClass; 527 try { 528 theClass = theCompileUnit.loadClass(type); 529 answer = createClassNode(theClass); 530 } catch (ClassNotFoundException e) { 531 log.log(Level.WARNING, "Cannot find class: " + type, e); 533 } 534 } 535 } 536 return answer; 537 } 538 539 protected ClassNode createClassNode(Class theClass) { 540 Class [] classInterfaces = theClass.getInterfaces(); 541 int size = classInterfaces.length; 542 String [] interfaceNames = new String [size]; 543 for (int i = 0; i < size; i++) { 544 interfaceNames[i] = classInterfaces[i].getName(); 545 } 546 547 String className = null; 548 if (theClass.getSuperclass() != null) { 549 className = theClass.getSuperclass().getName(); 550 } 551 ClassNode answer = 552 new ClassNode(theClass.getName(), 553 theClass.getModifiers(), 554 className, 555 interfaceNames, 556 MixinNode.EMPTY_ARRAY); 557 answer.compileUnit = getCompileUnit(); 558 Method [] declaredMethods = theClass.getDeclaredMethods(); 559 for (int i = 0; i < declaredMethods.length; i++) { 560 answer.addMethod(createMethodNode(declaredMethods[i])); 561 } 562 Constructor [] declaredConstructors = theClass.getDeclaredConstructors(); 563 for (int i = 0; i < declaredConstructors.length; i++) { 564 answer.addConstructor(createConstructorNode(declaredConstructors[i])); 565 } 566 return answer; 567 } 568 569 570 573 private ConstructorNode createConstructorNode(Constructor constructor) { 574 Parameter[] parameters = createParameters(constructor.getParameterTypes()); 575 return new ConstructorNode(constructor.getModifiers(), parameters, EmptyStatement.INSTANCE); 576 } 577 578 581 protected MethodNode createMethodNode(Method method) { 582 Parameter[] parameters = createParameters(method.getParameterTypes()); 583 return new MethodNode(method.getName(), method.getModifiers(), method.getReturnType().getName(), parameters, EmptyStatement.INSTANCE); 584 } 585 586 590 protected Parameter[] createParameters(Class [] types) { 591 Parameter[] parameters = Parameter.EMPTY_ARRAY; 592 int size = types.length; 593 if (size > 0) { 594 parameters = new Parameter[size]; 595 for (int i = 0; i < size; i++) { 596 parameters[i] = createParameter(types[i], i); 597 } 598 } 599 return parameters; 600 } 601 602 protected Parameter createParameter(Class parameterType, int idx) { 603 return new Parameter(parameterType.getName(), "param" + idx); 604 } 605 606 607 public String resolveClassName(String type) { 608 String answer = null; 609 if (type != null) { 610 if (getName().equals(type) || getNameWithoutPackage().equals(type)) { 611 return getName(); 612 } 613 answer = tryResolveClassAndInnerClass(type); 615 616 String replacedPointType = type; 618 while (answer == null && replacedPointType.indexOf('.') > -1) { 619 int lastPoint = replacedPointType.lastIndexOf('.'); 620 replacedPointType = new StringBuffer () 621 .append(replacedPointType.substring(0, lastPoint)).append("$") 622 .append(replacedPointType.substring(lastPoint + 1)).toString(); 623 answer = tryResolveClassAndInnerClass(replacedPointType); 624 } 625 } 626 return answer; 627 } 628 629 private String tryResolveClassAndInnerClass(String type) { 630 String answer = tryResolveClassFromCompileUnit(type); 631 if (answer == null) { 632 String packageName = getPackageName(); 634 if (packageName != null && packageName.length() > 0) { 635 answer = tryResolveClassFromCompileUnit(packageName + "." + type); 636 } 637 } 638 if (answer == null) { 639 if (module != null) { 641 643 for (Iterator iter = module.getImportPackages().iterator(); iter.hasNext();) { 644 String packageName = (String ) iter.next(); 645 answer = tryResolveClassFromCompileUnit(packageName + type); 646 if (answer != null) { 647 return answer; 648 } 649 } 650 } 651 } 652 if (answer == null) { 653 for (int i = 0, size = defaultImports.length; i < size; i++) { 654 String packagePrefix = defaultImports[i]; 655 answer = tryResolveClassFromCompileUnit(packagePrefix + "." + type); 656 if (answer != null) { 657 return answer; 658 } 659 } 660 } 661 return answer; 662 } 663 664 668 protected String tryResolveClassFromCompileUnit(String type) { 669 CompileUnit theCompileUnit = getCompileUnit(); 670 if (theCompileUnit != null) { 671 if (theCompileUnit.getClass(type) != null) { 672 return type; 673 } 674 675 try { 676 theCompileUnit.loadClass(type); 677 return type; 678 } catch (AccessControlException ace) { 679 throw ace; 681 } catch (Throwable e) { 682 } 684 } 685 return null; 686 } 687 688 public CompileUnit getCompileUnit() { 689 if (compileUnit == null && module != null) { 690 compileUnit = module.getUnit(); 691 } 692 return compileUnit; 693 } 694 695 698 protected boolean parametersEqual(Parameter[] a, Parameter[] b) { 699 if (a.length == b.length) { 700 boolean answer = true; 701 for (int i = 0; i < a.length; i++) { 702 if (!a[i].getType().equals(b[i].getType())) { 703 answer = false; 704 break; 705 } 706 } 707 return answer; 708 } 709 return false; 710 } 711 712 716 public String getClassNameForExpression(String identifier) { 717 String className = null; 719 if (module != null) { 720 className = module.getImport(identifier); 721 if (className == null) { 722 if (module.getUnit().getClass(identifier) != null) { 723 className = identifier; 724 } else { 725 String packageName = getPackageName(); 728 if (packageName != null) { 729 String guessName = packageName + "." + identifier; 730 if (module.getUnit().getClass(guessName) != null) { 731 className = guessName; 732 } else if (guessName.equals(name)) { 733 className = name; 734 } 735 } 736 } 737 } 738 } else { 739 System.out.println("No module for class: " + getName()); 740 } 741 return className; 742 } 743 744 747 public String getPackageName() { 748 int idx = name.lastIndexOf('.'); 749 if (idx > 0) { 750 return name.substring(0, idx); 751 } 752 return null; 753 } 754 755 public String getNameWithoutPackage() { 756 int idx = name.lastIndexOf('.'); 757 if (idx > 0) { 758 return name.substring(idx + 1); 759 } 760 return name; 761 } 762 763 public void visitContents(GroovyClassVisitor visitor) { 764 for (Iterator iter = getProperties().iterator(); iter.hasNext();) { 766 visitor.visitProperty((PropertyNode) iter.next()); 767 } 768 769 for (Iterator iter = getFields().iterator(); iter.hasNext();) { 770 visitor.visitField((FieldNode) iter.next()); 771 } 772 773 for (Iterator iter = getDeclaredConstructors().iterator(); iter.hasNext();) { 774 visitor.visitConstructor((ConstructorNode) iter.next()); 775 } 776 777 for (Iterator iter = getMethods().iterator(); iter.hasNext();) { 778 visitor.visitMethod((MethodNode) iter.next()); 779 } 780 } 781 782 public MethodNode getGetterMethod(String getterName) { 783 for (Iterator iter = methods.iterator(); iter.hasNext();) { 784 MethodNode method = (MethodNode) iter.next(); 785 if (getterName.equals(method.getName()) 786 && !"void".equals(method.getReturnType()) 787 && method.getParameters().length == 0) { 788 return method; 789 } 790 } 791 return null; 792 } 793 794 public MethodNode getSetterMethod(String getterName) { 795 for (Iterator iter = methods.iterator(); iter.hasNext();) { 796 MethodNode method = (MethodNode) iter.next(); 797 if (getterName.equals(method.getName()) 798 && "void".equals(method.getReturnType()) 799 && method.getParameters().length == 1) { 800 return method; 801 } 802 } 803 return null; 804 } 805 806 811 public boolean isStaticClass() { 812 return staticClass; 813 } 814 815 public void setStaticClass(boolean staticClass) { 816 this.staticClass = staticClass; 817 } 818 819 822 public boolean isScriptBody() { 823 return scriptBody; 824 } 825 826 public void setScriptBody(boolean scriptBody) { 827 this.scriptBody = scriptBody; 828 } 829 830 public boolean isScript() { 831 return script | isDerivedFrom(Script.class.getName()); 832 } 833 834 public void setScript(boolean script) { 835 this.script = script; 836 } 837 838 public String toString() { 839 return super.toString() + "[name: " + name + "]"; 840 } 841 842 } 843 | Popular Tags |