Clover coverage report - groovy - 1.0-beta-6
Coverage timestamp: Thu Jul 15 2004 13:18:22 BST
file stats: LOC: 850   Methods: 66
NCLOC: 598   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
ClassNode.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  * $Id: ClassNode.java,v 1.40 2004/07/10 03:31:38 bran Exp $
 3   
  * 
 4   
  * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 5   
  * 
 6   
  * Redistribution and use of this software and associated documentation
 7   
  * ("Software"), with or without modification, are permitted provided that the
 8   
  * following conditions are met:
 9   
  *  1. Redistributions of source code must retain copyright statements and
 10   
  * notices. Redistributions must also contain a copy of this document.
 11   
  *  2. Redistributions in binary form must reproduce the above copyright
 12   
  * notice, this list of conditions and the following disclaimer in the
 13   
  * documentation and/or other materials provided with the distribution.
 14   
  *  3. The name "groovy" must not be used to endorse or promote products
 15   
  * derived from this Software without prior written permission of The Codehaus.
 16   
  * For written permission, please contact info@codehaus.org.
 17   
  *  4. Products derived from this Software may not be called "groovy" nor may
 18   
  * "groovy" appear in their names without prior written permission of The
 19   
  * Codehaus. "groovy" is a registered trademark of The Codehaus.
 20   
  *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
 21   
  * 
 22   
  * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
 23   
  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 24   
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 25   
  * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
 26   
  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 27   
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 28   
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 29   
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 30   
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 31   
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 32   
  * DAMAGE.
 33   
  *  
 34   
  */
 35   
 package org.codehaus.groovy.ast;
 36   
 
 37   
 import groovy.lang.GroovyObject;
 38   
 import groovy.lang.MissingClassException;
 39   
 import groovy.lang.Script;
 40   
 
 41   
 import java.lang.reflect.Constructor;
 42   
 import java.lang.reflect.Method;
 43   
 import java.security.AccessControlException;
 44   
 import java.util.ArrayList;
 45   
 import java.util.HashMap;
 46   
 import java.util.Iterator;
 47   
 import java.util.List;
 48   
 import java.util.Map;
 49   
 import java.util.logging.Logger;
 50   
 
 51   
 import org.codehaus.groovy.ast.expr.Expression;
 52   
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 53   
 import org.codehaus.groovy.ast.stmt.EmptyStatement;
 54   
 import org.codehaus.groovy.ast.stmt.Statement;
 55   
 import org.objectweb.asm.Constants;
 56   
 
 57   
 /**
 58   
  * Represents a class declaration
 59   
  * 
 60   
  * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
 61   
  * @version $Revision: 1.40 $
 62   
  */
 63   
 public class ClassNode extends MetadataNode implements Constants {
 64   
 
 65   
     private static final String[] defaultImports = { "java.lang", "java.util", "groovy.lang", "groovy.util" };
 66   
 
 67   
     private Logger log = Logger.getLogger(getClass().getName());
 68   
 
 69   
     private String name;
 70   
     private int modifiers;
 71   
     private String superClass;
 72   
     private String[] interfaces;
 73   
     private MixinNode[] mixins;
 74   
     private List constructors = new ArrayList();
 75   
     private List methods = new ArrayList();
 76   
     private List fields = new ArrayList();
 77   
     private List properties = new ArrayList();
 78   
     private Map fieldIndex = new HashMap();
 79   
     private ModuleNode module;
 80   
     private CompileUnit compileUnit;
 81   
     private boolean staticClass = false;
 82   
     private boolean scriptBody = false;
 83   
     private boolean script;
 84   
     private ClassNode superClassNode;
 85   
 
 86   
 
 87   
     //br added to track the enclosing method for local inner classes
 88   
     private MethodNode enclosingMethod = null;
 89  0
     public MethodNode getEnclosingMethod() {
 90  0
         return enclosingMethod;
 91   
     }
 92  0
     public void setEnclosingMethod(MethodNode enclosingMethod) {
 93  0
         this.enclosingMethod = enclosingMethod;
 94   
     }
 95   
 
 96   
 
 97   
     /**
 98   
      * @param name
 99   
      *            is the full name of the class
 100   
      * @param modifiers
 101   
      *            the modifiers,
 102   
      * @see org.objectweb.asm.Constants
 103   
      * @param superClass
 104   
      *            the base class name - use "java.lang.Object" if no direct
 105   
      *            base class
 106   
      */
 107  0
     public ClassNode(String name, int modifiers, String superClass) {
 108  0
         this(name, modifiers, superClass, EMPTY_STRING_ARRAY, MixinNode.EMPTY_ARRAY);
 109   
     }
 110   
 
 111   
     /**
 112   
      * @param name
 113   
      *            is the full name of the class
 114   
      * @param modifiers
 115   
      *            the modifiers,
 116   
      * @see org.objectweb.asm.Constants
 117   
      * @param superClass
 118   
      *            the base class name - use "java.lang.Object" if no direct
 119   
      *            base class
 120   
      */
 121  0
     public ClassNode(String name, int modifiers, String superClass, String[] interfaces, MixinNode[] mixins) {
 122  0
         this.name = name;
 123  0
         this.modifiers = modifiers;
 124  0
         this.superClass = superClass;
 125  0
         this.interfaces = interfaces;
 126  0
         this.mixins = mixins;
 127   
 
 128   
         //br for better JVM comformance
 129  0
         if ((modifiers & ACC_SUPER ) == 0) {
 130  0
             this.modifiers += ACC_SUPER;
 131   
         }
 132   
     }
 133   
 
 134  0
     public String getSuperClass() {
 135  0
         return superClass;
 136   
     }
 137   
 
 138  0
     public void setSuperClass(String superClass) {
 139  0
         this.superClass = superClass;
 140   
     }
 141   
     
 142  0
     public List getFields() {
 143  0
         return fields;
 144   
     }
 145   
 
 146  0
     public String[] getInterfaces() {
 147  0
         return interfaces;
 148   
     }
 149   
 
 150  0
     public MixinNode[] getMixins() {
 151  0
         return mixins;
 152   
     }
 153   
 
 154  0
     public List getMethods() {
 155  0
         return methods;
 156   
     }
 157   
 
 158  0
     public List getAbstractMethods() {
 159   
 
 160  0
         List result = new ArrayList();
 161  0
         for (Iterator methIt = getAllDeclaredMethods().iterator(); methIt.hasNext();) {
 162  0
             MethodNode method = (MethodNode) methIt.next();
 163  0
             if (method.isAbstract()) result.add(method);
 164   
         }
 165  0
         if (result.size() == 0)
 166  0
             return null;
 167   
         else
 168  0
             return result;
 169   
     }
 170   
 
 171  0
     public List getAllDeclaredMethods() {
 172  0
         return new ArrayList(getDeclaredMethodsMap().values());
 173   
     }
 174   
 
 175   
 
 176  0
     protected Map getDeclaredMethodsMap() {
 177   
         // Start off with the methods from the superclass.
 178  0
         ClassNode parent = getSuperClassNode();
 179  0
         Map result = null;
 180  0
         if (parent != null)
 181  0
             result = parent.getDeclaredMethodsMap();
 182   
         else
 183  0
             result = new HashMap();
 184   
 
 185   
         // add in unimplemented abstract methods from the interfaces
 186  0
         for (int i = 0; i < interfaces.length; i++) {
 187  0
             String interfaceName = interfaces[i];
 188  0
             ClassNode iface = findClassNode(interfaceName);
 189  0
             Map ifaceMethodsMap = iface.getDeclaredMethodsMap();
 190  0
             for (Iterator iter = ifaceMethodsMap.keySet().iterator(); iter.hasNext();) {
 191  0
                 String methSig = (String) iter.next();
 192  0
                 if (!result.containsKey(methSig)) {
 193  0
                     MethodNode methNode = (MethodNode) ifaceMethodsMap.get(methSig);
 194  0
                     result.put(methSig, methNode);
 195   
                 }
 196   
             }
 197   
         }
 198   
 
 199   
         // And add in the methods implemented in this class.
 200  0
         for (Iterator iter = getMethods().iterator(); iter.hasNext();) {
 201  0
             MethodNode method = (MethodNode) iter.next();
 202  0
             String sig = method.getTypeDescriptor();
 203  0
             if (result.containsKey(sig)) {
 204  0
                 MethodNode inheritedMethod = (MethodNode) result.get(sig);
 205  0
                 if (inheritedMethod.isAbstract()) {
 206  0
                     result.put(sig, method);
 207   
                 }                
 208   
             } else {
 209  0
                 result.put(sig, method);
 210   
             }
 211   
         }
 212  0
         return result;
 213   
     }
 214   
 
 215  0
     protected int findMatchingMethodInList(MethodNode method, List methods) {
 216  0
         for (int i = 0; i < methods.size(); i++) {
 217  0
             MethodNode someMeth = (MethodNode) methods.get(i);
 218  0
             if (someMeth.getName().equals(method.getName())
 219  0
                     && parametersEqual(someMeth.getParameters(), method.getParameters())) return i;
 220   
         }
 221  0
         return -1;
 222   
     }
 223   
 
 224  0
     public String getName() {
 225  0
         return name;
 226   
     }
 227   
 
 228  0
     public int getModifiers() {
 229  0
         return modifiers;
 230   
     }
 231   
 
 232  0
     public List getProperties() {
 233  0
         return properties;
 234   
     }
 235   
 
 236  0
     public List getDeclaredConstructors() {
 237  0
         return constructors;
 238   
     }
 239   
 
 240  0
     public ModuleNode getModule() {
 241  0
         return module;
 242   
     }
 243   
 
 244  0
     public void setModule(ModuleNode module) {
 245  0
         this.module = module;
 246  0
         if (module != null) {
 247  0
             this.compileUnit = module.getUnit();
 248   
         }
 249   
     }
 250   
 
 251  0
     public void addField(FieldNode node) {
 252  0
         node.setOwner(getName());
 253  0
         fields.add(node);
 254  0
         fieldIndex.put(node.getName(), node);
 255   
     }
 256   
 
 257  0
     public void addProperty(PropertyNode node) {
 258  0
         FieldNode field = node.getField();
 259  0
         addField(field);
 260   
 
 261  0
         properties.add(node);
 262   
     }
 263   
 
 264  0
     public PropertyNode addProperty(
 265   
         String name,
 266   
         int modifiers,
 267   
         String type,
 268   
         Expression initialValueExpression,
 269   
         Statement getterBlock,
 270   
         Statement setterBlock) {
 271  0
         PropertyNode node =
 272   
             new PropertyNode(name, modifiers, type, getName(), initialValueExpression, getterBlock, setterBlock);
 273  0
         addProperty(node);
 274  0
         return node;
 275   
     }
 276   
 
 277  0
     public void addConstructor(ConstructorNode node) {
 278  0
         constructors.add(node);
 279   
     }
 280   
 
 281  0
     public ConstructorNode addConstructor(int modifiers, Parameter[] parameters, Statement code) {
 282  0
         ConstructorNode node = new ConstructorNode(modifiers, parameters, code);
 283  0
         addConstructor(node);
 284  0
         return node;
 285   
     }
 286   
 
 287  0
     public void addMethod(MethodNode node) {
 288  0
         methods.add(node);
 289  0
         node.declaringClass = this;
 290   
     }
 291   
 
 292   
     /**
 293   
      * IF a method with the given name and parameters is already defined then it is returned
 294   
      * otherwise the given method is added to this node. This method is useful for
 295   
      * default method adding like getProperty() or invokeMethod() where there may already
 296   
      * be a method defined in a class and  so the default implementations should not be added
 297   
      * if already present.
 298   
      */
 299  0
     public MethodNode addMethod(
 300   
         String name,
 301   
         int modifiers,
 302   
         String returnType,
 303   
         Parameter[] parameters,
 304   
         Statement code) {
 305  0
         MethodNode other = getDeclaredMethod(name, parameters);
 306   
         // lets not add duplicate methods
 307  0
         if (other != null) {
 308  0
             return other;
 309   
         }
 310  0
         MethodNode node = new MethodNode(name, modifiers, returnType, parameters, code);
 311  0
         addMethod(node);
 312  0
         return node;
 313   
     }
 314   
 
 315   
     /** 
 316   
      * Adds a synthetic method as part of the compilation process
 317   
      */
 318  0
     public MethodNode addSyntheticMethod(
 319   
         String name,
 320   
         int modifiers,
 321   
         String returnType,
 322   
         Parameter[] parameters,
 323   
         Statement code) {
 324  0
         MethodNode answer = addMethod(name, modifiers, returnType, parameters, code);
 325  0
         answer.setSynthetic(true);
 326  0
         return answer;
 327   
     }
 328   
 
 329  0
     public FieldNode addField(String name, int modifiers, String type, Expression initialValue) {
 330  0
         FieldNode node = new FieldNode(name, modifiers, type, getName(), initialValue);
 331  0
         addField(node);
 332  0
         return node;
 333   
     }
 334   
 
 335  0
     public void addInterface(String name) {
 336   
         // lets check if it already implements an interface
 337  0
         boolean skip = false;
 338  0
         for (int i = 0; i < interfaces.length; i++) {
 339  0
             if (name.equals(interfaces[i])) {
 340  0
                 skip = true;
 341   
             }
 342   
         }
 343  0
         if (!skip) {
 344  0
             String[] newInterfaces = new String[interfaces.length + 1];
 345  0
             System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length);
 346  0
             newInterfaces[interfaces.length] = name;
 347  0
             interfaces = newInterfaces;
 348   
         }
 349   
     }
 350   
 
 351  0
     public void addMixin(MixinNode mixin) {
 352   
         // lets check if it already uses a mixin
 353  0
         boolean skip = false;
 354  0
         String mixinName = mixin.getName();
 355  0
         for (int i = 0; i < mixins.length; i++) {
 356  0
             if (mixinName.equals(mixins[i].getName())) {
 357  0
                 skip = true;
 358   
             }
 359   
         }
 360  0
         if (!skip) {
 361  0
             MixinNode[] newMixins = new MixinNode[mixins.length + 1];
 362  0
             System.arraycopy(mixins, 0, newMixins, 0, mixins.length);
 363  0
             newMixins[mixins.length] = mixin;
 364  0
             mixins = newMixins;
 365   
         }
 366   
     }
 367   
 
 368  0
     public FieldNode getField(String name) {
 369  0
         return (FieldNode) fieldIndex.get(name);
 370   
     }
 371   
 
 372   
     /**
 373   
      * @return the field node on the outer class or null if this is not an
 374   
      *         inner class
 375   
      */
 376  0
     public FieldNode getOuterField(String name) {
 377  0
         return null;
 378   
     }
 379   
 
 380   
     /**
 381   
      * Helper method to avoid casting to inner class
 382   
      * 
 383   
      * @return
 384   
      */
 385  0
     public ClassNode getOuterClass() {
 386  0
         return null;
 387   
     }
 388   
 
 389  0
     public void addStaticInitializerStatements(List staticStatements) {
 390  0
         MethodNode method = null;
 391  0
         List declaredMethods = getDeclaredMethods("<clinit>");
 392  0
         if (declaredMethods.isEmpty()) {
 393  0
             method =
 394   
                 addMethod("<clinit>", ACC_PUBLIC | ACC_STATIC, "void", Parameter.EMPTY_ARRAY, new BlockStatement());
 395   
         }
 396   
         else {
 397  0
             method = (MethodNode) declaredMethods.get(0);
 398   
         }
 399  0
         BlockStatement block = null;
 400  0
         Statement statement = method.getCode();
 401  0
         if (statement == null) {
 402  0
             block = new BlockStatement();
 403   
         }
 404  0
         else if (statement instanceof BlockStatement) {
 405  0
             block = (BlockStatement) statement;
 406   
         }
 407   
         else {
 408  0
             block = new BlockStatement();
 409  0
             block.addStatement(statement);
 410   
         }
 411  0
         block.addStatements(staticStatements);
 412   
     }
 413   
 
 414   
     /**
 415   
      * @return a list of methods which match the given name
 416   
      */
 417  0
     public List getDeclaredMethods(String name) {
 418  0
         List answer = new ArrayList();
 419  0
         for (Iterator iter = methods.iterator(); iter.hasNext();) {
 420  0
             MethodNode method = (MethodNode) iter.next();
 421  0
             if (name.equals(method.getName())) {
 422  0
                 answer.add(method);
 423   
             }
 424   
         }
 425  0
         return answer;
 426   
     }
 427   
 
 428   
     /**
 429   
      * @return a list of methods which match the given name
 430   
      */
 431  0
     public List getMethods(String name) {
 432  0
         List answer = new ArrayList();
 433  0
         ClassNode node = this;
 434  0
         do {
 435  0
             for (Iterator iter = node.methods.iterator(); iter.hasNext();) {
 436  0
                 MethodNode method = (MethodNode) iter.next();
 437  0
                 if (name.equals(method.getName())) {
 438  0
                     answer.add(method);
 439   
                 }
 440   
             }
 441  0
             node = node.getSuperClassNode();
 442   
         }
 443  0
         while (node != null);
 444  0
         return answer;
 445   
     }
 446   
 
 447   
     /**
 448   
      * @return the method matching the given name and parameters or null
 449   
      */
 450  0
     public MethodNode getDeclaredMethod(String name, Parameter[] parameters) {
 451  0
         for (Iterator iter = methods.iterator(); iter.hasNext();) {
 452  0
             MethodNode method = (MethodNode) iter.next();
 453  0
             if (name.equals(method.getName()) && parametersEqual(method.getParameters(), parameters)) {
 454  0
                 return method;
 455   
             }
 456   
         }
 457  0
         return null;
 458   
     }
 459   
 
 460   
     /**
 461   
      * @return true if this node is derived from the given class node
 462   
      */
 463  0
     public boolean isDerivedFrom(String name) {
 464  0
         ClassNode node = getSuperClassNode();
 465  0
         while (node != null) {
 466  0
             if (name.equals(node.getName())) {
 467  0
                 return true;
 468   
             }
 469  0
             node = node.getSuperClassNode();
 470   
         }
 471  0
         return false;
 472   
     }
 473   
 
 474   
     /**
 475   
      * @return true if this class is derived from a groovy object
 476   
      * i.e. it implements GroovyObject
 477   
      */
 478  0
     public boolean isDerivedFromGroovyObject() {
 479  0
         return implementsInteface(GroovyObject.class.getName());
 480   
     }
 481   
 
 482   
     /**
 483   
      * @param name the fully qualified name of the interface
 484   
      * @return true if this class or any base class implements the given interface
 485   
      */
 486  0
     public boolean implementsInteface(String name) {
 487  0
         ClassNode node = this;
 488  0
         do {
 489  0
             if (node.declaresInterface(name)) {
 490  0
                 return true;
 491   
             }
 492  0
             node = node.getSuperClassNode();
 493   
         }
 494  0
         while (node != null);
 495  0
         return false;
 496   
     }
 497   
 
 498   
     /**
 499   
      * @param name the fully qualified name of the interface
 500   
      * @return true if this class declares that it implements the given interface
 501   
      */
 502  0
     public boolean declaresInterface(String name) {
 503  0
         int size = interfaces.length;
 504  0
         for (int i = 0; i < size; i++ ) {
 505  0
             if (name.equals(interfaces[i])) {
 506  0
                 return true;
 507   
             }
 508   
         }
 509  0
         return false;
 510   
     }
 511   
 
 512   
     /**
 513   
      * @return the ClassNode of the super class of this type
 514   
      */
 515  0
     public ClassNode getSuperClassNode() {
 516  0
         if (superClass != null &&  superClass.length() > 0 && superClassNode == null && !name.equals("java.lang.Object")) {
 517   
             // lets try find the class in the compile unit
 518  0
             String temp = resolveClassName(superClass);
 519  0
             if (temp == null) {
 520  0
                 throw new MissingClassException(superClass, this, "No such superclass");
 521   
             }
 522   
             else {
 523  0
                 superClass = temp;
 524   
             }
 525  0
             superClassNode = findClassNode(superClass);
 526   
         }
 527  0
         return superClassNode;
 528   
     }
 529   
 
 530   
     /**
 531   
      * Attempts to lookup the fully qualified class name in the compile unit or classpath
 532   
      * 
 533   
      * @param type fully qulified type name
 534   
      * @return the ClassNode for this type or null if it could not be found
 535   
      */
 536  0
     public ClassNode findClassNode(String type) {
 537  0
         ClassNode answer = null;
 538  0
         CompileUnit theCompileUnit = getCompileUnit();
 539  0
         if (theCompileUnit != null) {
 540  0
             answer = theCompileUnit.getClass(type);
 541  0
             if (answer == null) {
 542  0
                 Class theClass;
 543  0
                 try {
 544  0
                     theClass = theCompileUnit.loadClass(type);
 545  0
                     answer = createClassNode(theClass);
 546   
                 }
 547   
                 catch (ClassNotFoundException e) {
 548   
                     // lets ignore class not found exceptions
 549  0
                     log.warning("Cannot find class: " + type + " due to: " + e);
 550  0
                     e.printStackTrace();
 551   
                 }
 552   
             }
 553   
         }
 554  0
         return answer;
 555   
     }
 556   
 
 557  0
     protected ClassNode createClassNode(Class theClass) {
 558  0
         Class[] classInterfaces = theClass.getInterfaces();
 559  0
         int size = classInterfaces.length;
 560  0
         String[] interfaceNames = new String[size];
 561  0
         for (int i = 0; i < size; i++) {
 562  0
             interfaceNames[i] = classInterfaces[i].getName();
 563   
         }
 564   
         
 565  0
         String className = null;
 566  0
         if (theClass.getSuperclass() != null) {
 567  0
             className = theClass.getSuperclass().getName();
 568   
         }
 569  0
         ClassNode answer =
 570   
             new ClassNode(
 571   
                 theClass.getName(),
 572   
                 theClass.getModifiers(),
 573   
                 className,
 574   
                 interfaceNames,
 575   
                 MixinNode.EMPTY_ARRAY);
 576  0
         answer.compileUnit = getCompileUnit();
 577  0
         Method[] declaredMethods = theClass.getDeclaredMethods();
 578  0
         for (int i = 0; i < declaredMethods.length; i++ ) {
 579  0
             answer.addMethod(createMethodNode(declaredMethods[i]));
 580   
         }
 581  0
         Constructor[] declaredConstructors = theClass.getDeclaredConstructors();
 582  0
         for (int i = 0; i < declaredConstructors.length; i++ ) {
 583  0
             answer.addConstructor(createConstructorNode(declaredConstructors[i]));
 584   
         }
 585  0
         return answer;
 586   
     }
 587   
 
 588   
 
 589   
     /**
 590   
      * Factory method to create a new ConstructorNode via reflection
 591   
      */
 592  0
     private ConstructorNode createConstructorNode(Constructor constructor) {
 593  0
         Parameter[] parameters = createParameters(constructor.getParameterTypes());
 594  0
         return new ConstructorNode(constructor.getModifiers(), parameters, EmptyStatement.INSTANCE);
 595   
     }
 596   
 
 597   
     /**
 598   
      * Factory method to create a new MethodNode via reflection
 599   
      */
 600  0
     protected MethodNode createMethodNode(Method method) {
 601  0
         Parameter[] parameters = createParameters(method.getParameterTypes());
 602  0
         return new MethodNode(method.getName(), method.getModifiers(), method.getReturnType().getName(), parameters, EmptyStatement.INSTANCE);
 603   
     }
 604   
 
 605   
     /**
 606   
      * @param types
 607   
      * @return
 608   
      */
 609  0
     protected Parameter[] createParameters(Class[] types) {
 610  0
         Parameter[] parameters = Parameter.EMPTY_ARRAY;
 611  0
         int size = types.length;
 612  0
         if (size > 0) {
 613  0
             parameters = new Parameter[size];
 614  0
             for (int i = 0; i < size; i++) {
 615  0
                 parameters[i] = createParameter(types[i], i);
 616   
             }
 617   
         }
 618  0
         return parameters;
 619   
     }
 620   
 
 621  0
     protected Parameter createParameter(Class parameterType, int idx) {
 622  0
         return new Parameter(parameterType.getName(), "param" + idx);
 623   
     }
 624   
 
 625   
   
 626  0
     public String resolveClassName(String type) {
 627  0
         String answer = null;
 628  0
         if (type != null) {
 629  0
             if (getName().equals(type) || getNameWithoutPackage().equals(type)) {
 630  0
                 return getName();
 631   
             }
 632  0
             answer = tryResolveClassFromCompileUnit(type);
 633  0
             if (answer == null) {
 634   
                 // lets try class in same package
 635  0
                 String packageName = getPackageName();
 636  0
                 if (packageName != null && packageName.length() > 0) {
 637  0
                     answer = tryResolveClassFromCompileUnit(packageName + "." + type);
 638   
                 }
 639   
             }
 640  0
             if (answer == null) {
 641   
                 // lets try use the packages imported in the module
 642  0
                 if (module != null) {
 643   
                     //System.out.println("Looking up inside the imported packages: " + module.getImportPackages());
 644   
                     
 645  0
                     for (Iterator iter = module.getImportPackages().iterator(); iter.hasNext(); ) {
 646  0
                         String packageName = (String) iter.next();
 647  0
                         answer = tryResolveClassFromCompileUnit(packageName + type);
 648  0
                         if (answer != null) {
 649  0
                             return answer;
 650   
                         }
 651   
                     }
 652   
                 }
 653   
             }
 654  0
             if (answer == null) {
 655  0
                 for (int i = 0, size = defaultImports.length; i < size; i++ ) {
 656  0
                     String packagePrefix = defaultImports[i];
 657  0
                     answer = tryResolveClassFromCompileUnit(packagePrefix + "." + type);
 658  0
                     if (answer != null) {
 659  0
                         return answer;
 660   
                     }
 661   
                 }
 662   
             }
 663   
         }
 664  0
         return answer;
 665   
     }
 666   
 
 667   
     /**
 668   
      * @param type
 669   
      * @return
 670   
      */
 671  0
     protected String tryResolveClassFromCompileUnit(String type) {
 672  0
         CompileUnit theCompileUnit = getCompileUnit();
 673  0
         if (theCompileUnit != null) {
 674  0
             if (theCompileUnit.getClass(type) != null) {
 675  0
                 return type;
 676   
             }
 677   
 
 678  0
             try {
 679  0
                 theCompileUnit.loadClass(type);
 680  0
                 return type;
 681   
             }
 682   
             catch (AccessControlException ace) {
 683   
                 //Percolate this for better diagnostic info
 684  0
                 throw ace;
 685   
             }
 686   
             catch (Throwable e) {
 687   
                 // fall through
 688   
             }
 689   
         }
 690  0
         return null;
 691   
     }
 692   
 
 693  0
     public CompileUnit getCompileUnit() {
 694  0
         if (compileUnit == null && module != null) {
 695  0
             compileUnit = module.getUnit();
 696   
         }
 697  0
         return compileUnit;
 698   
     }
 699   
 
 700   
     /**
 701   
      * @return true if the two arrays are of the same size and have the same contents
 702   
      */
 703  0
     protected boolean parametersEqual(Parameter[] a, Parameter[] b) {
 704  0
         if (a.length == b.length) {
 705  0
             boolean answer = true;
 706  0
             for (int i = 0; i < a.length; i++) {
 707  0
                 if (!a[i].getType().equals(b[i].getType())) {
 708  0
                     answer = false;
 709  0
                     break;
 710   
                 }
 711   
             }
 712  0
             return answer;
 713   
         }
 714  0
         return false;
 715   
     }
 716   
 
 717   
     /**
 718   
      * @return the name of the class for the given identifier if it is a class
 719   
      * otherwise return null
 720   
      */
 721  0
     public String getClassNameForExpression(String identifier) {
 722   
         // lets see if it really is a class name
 723  0
         String className = null;
 724  0
         if (module != null) {
 725  0
             className = module.getImport(identifier);
 726  0
             if (className == null) {
 727  0
                 if (module.getUnit().getClass(identifier) != null) {
 728  0
                     className = identifier;
 729   
                 }
 730   
                 else {
 731   
                     // lets prepend the package name to see if its in our
 732   
                     // package
 733  0
                     String packageName = getPackageName();
 734  0
                     if (packageName != null) {
 735  0
                         String guessName = packageName + "." + identifier;
 736  0
                         if (module.getUnit().getClass(guessName) != null) {
 737  0
                             className = guessName;
 738   
                         }
 739  0
                         else if (guessName.equals(name)) {
 740  0
                             className = name;
 741   
                         }
 742   
                     }
 743   
                 }
 744   
             }
 745   
         }
 746   
         else {
 747  0
             System.out.println("No module for class: " + getName());
 748   
         }
 749  0
         return className;
 750   
     }
 751   
 
 752   
     /**
 753   
      * @return the package name of this class
 754   
      */
 755  0
     public String getPackageName() {
 756  0
         int idx = name.lastIndexOf('.');
 757  0
         if (idx > 0) {
 758  0
             return name.substring(0, idx);
 759   
         }
 760  0
         return null;
 761   
     }
 762   
 
 763  0
     public String getNameWithoutPackage() {
 764  0
         int idx = name.lastIndexOf('.');
 765  0
         if (idx > 0) {
 766  0
             return name.substring(idx + 1);
 767   
         }
 768  0
         return name;
 769   
     }
 770   
 
 771  0
     public void visitContents(GroovyClassVisitor visitor) {
 772   
         // now lets visit the contents of the class
 773  0
         for (Iterator iter = getProperties().iterator(); iter.hasNext();) {
 774  0
             visitor.visitProperty((PropertyNode) iter.next());
 775   
         }
 776   
 
 777  0
         for (Iterator iter = getFields().iterator(); iter.hasNext();) {
 778  0
             visitor.visitField((FieldNode) iter.next());
 779   
         }
 780   
 
 781  0
         for (Iterator iter = getDeclaredConstructors().iterator(); iter.hasNext();) {
 782  0
             visitor.visitConstructor((ConstructorNode) iter.next());
 783   
         }
 784   
 
 785  0
         for (Iterator iter = getMethods().iterator(); iter.hasNext();) {
 786  0
             visitor.visitMethod((MethodNode) iter.next());
 787   
         }
 788   
     }
 789   
 
 790  0
     public MethodNode getGetterMethod(String getterName) {
 791  0
         for (Iterator iter = methods.iterator(); iter.hasNext();) {
 792  0
             MethodNode method = (MethodNode) iter.next();
 793  0
             if (getterName.equals(method.getName())
 794   
                 && !"void".equals(method.getReturnType())
 795   
                 && method.getParameters().length == 0) {
 796  0
                 return method;
 797   
             }
 798   
         }
 799  0
         return null;
 800   
     }
 801   
 
 802  0
     public MethodNode getSetterMethod(String getterName) {
 803  0
         for (Iterator iter = methods.iterator(); iter.hasNext();) {
 804  0
             MethodNode method = (MethodNode) iter.next();
 805  0
             if (getterName.equals(method.getName())
 806   
                 && "void".equals(method.getReturnType())
 807   
                 && method.getParameters().length == 1) {
 808  0
                 return method;
 809   
             }
 810   
         }
 811  0
         return null;
 812   
     }
 813   
 
 814   
     /**
 815   
      * Is this class delcared in a static method (such as a closure / inner class declared in a static method)
 816   
      * @return
 817   
      */
 818  0
     public boolean isStaticClass() {
 819  0
         return staticClass;
 820   
     }
 821   
 
 822  0
     public void setStaticClass(boolean staticClass) {
 823  0
         this.staticClass = staticClass;
 824   
     }
 825   
 
 826   
     /**
 827   
      * @return Returns true if this inner class or closure was declared inside a script body
 828   
      */
 829  0
     public boolean isScriptBody() {
 830  0
         return scriptBody;
 831   
     }
 832   
 
 833  0
     public void setScriptBody(boolean scriptBody) {
 834  0
         this.scriptBody = scriptBody;
 835   
     }
 836   
 
 837  0
     public boolean isScript() {
 838  0
         return script | isDerivedFrom(Script.class.getName());
 839   
     }
 840   
 
 841  0
     public void setScript(boolean script) {
 842  0
         this.script = script;
 843   
     }
 844   
 
 845  0
     public String toString() {
 846  0
         return super.toString() + "[name: " + name + "]";
 847   
     }
 848   
 
 849   
    }
 850