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