View Javadoc

    1   /*
    2    $Id: Verifier.java 4598 2006-12-22 20:21:21Z blackdrag $
    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
    8    that the following conditions are met:
    9
    10   1. Redistributions of source code must retain copyright
    11      statements and notices.  Redistributions must also contain a
    12      copy of this document.
    13
    14   2. Redistributions in binary form must reproduce the
    15      above copyright notice, this list of conditions and the
    16      following disclaimer in the documentation and/or other
    17      materials provided with the distribution.
    18
    19   3. The name "groovy" must not be used to endorse or promote
    20      products derived from this Software without prior written
    21      permission of The Codehaus.  For written permission,
    22      please contact info@codehaus.org.
    23
    24   4. Products derived from this Software may not be called "groovy"
    25      nor may "groovy" appear in their names without prior written
    26      permission of The Codehaus. "groovy" is a registered
    27      trademark of The Codehaus.
    28
    29   5. Due credit should be given to The Codehaus -
    30      http://groovy.codehaus.org/
    31
    32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
    33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
    34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
    36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
    43   OF THE POSSIBILITY OF SUCH DAMAGE.
    44
    45   */
    46  package org.codehaus.groovy.classgen;
    47
    48  import groovy.lang.GroovyObject;
    49  import groovy.lang.MetaClass;
    50
    51  import java.lang.reflect.Modifier;
    52  import java.util.ArrayList;
    53  import java.util.Iterator;
    54  import java.util.List;
    55
    56  import org.codehaus.groovy.ast.ClassHelper;
    57  import org.codehaus.groovy.ast.ClassNode;
    58  import org.codehaus.groovy.ast.CodeVisitorSupport;
    59  import org.codehaus.groovy.ast.ConstructorNode;
    60  import org.codehaus.groovy.ast.FieldNode;
    61  import org.codehaus.groovy.ast.GroovyClassVisitor;
    62  import org.codehaus.groovy.ast.InnerClassNode;
    63  import org.codehaus.groovy.ast.MethodNode;
    64  import org.codehaus.groovy.ast.Parameter;
    65  import org.codehaus.groovy.ast.PropertyNode;
    66  import org.codehaus.groovy.ast.VariableScope;
    67  import org.codehaus.groovy.ast.expr.ArgumentListExpression;
    68  import org.codehaus.groovy.ast.expr.BinaryExpression;
    69  import org.codehaus.groovy.ast.expr.BooleanExpression;
    70  import org.codehaus.groovy.ast.expr.ClosureExpression;
    71  import org.codehaus.groovy.ast.expr.ConstantExpression;
    72  import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
    73  import org.codehaus.groovy.ast.expr.Expression;
    74  import org.codehaus.groovy.ast.expr.FieldExpression;
    75  import org.codehaus.groovy.ast.expr.MethodCallExpression;
    76  import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
    77  import org.codehaus.groovy.ast.expr.VariableExpression;
    78  import org.codehaus.groovy.ast.stmt.BlockStatement;
    79  import org.codehaus.groovy.ast.stmt.EmptyStatement;
    80  import org.codehaus.groovy.ast.stmt.ExpressionStatement;
    81  import org.codehaus.groovy.ast.stmt.IfStatement;
    82  import org.codehaus.groovy.ast.stmt.ReturnStatement;
    83  import org.codehaus.groovy.ast.stmt.Statement;
    84  import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
    85  import org.codehaus.groovy.syntax.Types;
    86  import org.codehaus.groovy.syntax.Token;
    87  import org.codehaus.groovy.syntax.RuntimeParserException;
    88  import org.objectweb.asm.Opcodes;
    89
    90  /***
    91   * Verifies the AST node and adds any defaulted AST code before
    92   * bytecode generation occurs.
    93   *
    94   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
    95   * @version $Revision: 4598 $
    96   */
    97  public class Verifier implements GroovyClassVisitor, Opcodes {
    98
    99      public static final String __TIMESTAMP = "__timeStamp";
    100 	private ClassNode classNode;
    101     private MethodNode methodNode;
    102
    103     public ClassNode getClassNode() {
    104         return classNode;
    105     }
    106
    107     public MethodNode getMethodNode() {
    108         return methodNode;
    109     }
    110
    111     /***
    112      * add code to implement GroovyObject
    113      * @param node
    114      */
    115     public void visitClass(ClassNode node) {
    116         this.classNode = node;
    117
    118         if ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) >0) {
    119             //interfaces have no construcotrs, but this code expects one,
    120             //so creta a dummy and don't add it to the class node
    121             ConstructorNode dummy = new ConstructorNode(0,null);
    122             addInitialization(node, dummy);
    123             node.visitContents(this);
    124             return;
    125         }
    126
    127         addDefaultParameterMethods(node);
    128         addDefaultParameterConstructors(node);
    129
    130         if (!node.isDerivedFromGroovyObject()) {
    131             node.addInterface(ClassHelper.make(GroovyObject.class));
    132
    133             // lets add a new field for the metaclass
    134             StaticMethodCallExpression initMetaClassCall =
    135                 new StaticMethodCallExpression(
    136                     ClassHelper.make(ScriptBytecodeAdapter.class),
    137                     "initMetaClass",
    138                     VariableExpression.THIS_EXPRESSION);
    139
    140             PropertyNode metaClassProperty =
    141                 node.addProperty("metaClass", ACC_PUBLIC, ClassHelper.make(MetaClass.class), initMetaClassCall, null, null);
    142             metaClassProperty.setSynthetic(true);
    143             FieldNode metaClassField = metaClassProperty.getField();
    144             metaClassField.setModifiers(metaClassField.getModifiers() | ACC_TRANSIENT);
    145
    146             FieldExpression metaClassVar = new FieldExpression(metaClassField);
    147             IfStatement initMetaClassField =
    148                 new IfStatement(
    149                     new BooleanExpression(
    150                         new BinaryExpression(metaClassVar, Token.newSymbol( Types.COMPARE_EQUAL, -1, -1), ConstantExpression.NULL)),
    151                     new ExpressionStatement(new BinaryExpression(metaClassVar, Token.newSymbol( Types.EQUAL, -1, -1), initMetaClassCall)),
    152                     EmptyStatement.INSTANCE);
    153
    154             node.addSyntheticMethod(
    155                 "getMetaClass",
    156                 ACC_PUBLIC,
    157                 ClassHelper.make(MetaClass.class),
    158                 Parameter.EMPTY_ARRAY,
    159                 ClassNode.EMPTY_ARRAY,
    160                 new BlockStatement(new Statement[] { initMetaClassField, new ReturnStatement(metaClassVar)}, new VariableScope())
    161             );
    162
    163             // @todo we should check if the base class implements the invokeMethod method
    164
    165             // lets add the invokeMethod implementation
    166             ClassNode superClass = node.getSuperClass();
    167             boolean addDelegateObject =
    168                 (node instanceof InnerClassNode && superClass.equals(ClassHelper.CLOSURE_TYPE))
    169                     || superClass.equals(ClassHelper.GSTRING_TYPE);
    170
    171             // don't do anything as the base class implements the invokeMethod
    172             if (!addDelegateObject) {
    173
    174                 VariableExpression vMethods = new VariableExpression("method");
    175                 VariableExpression vArguments = new VariableExpression("arguments");
    176                 VariableScope blockScope = new VariableScope();
    177                 blockScope.getReferencedLocalVariables().put("method",vMethods);
    178                 blockScope.getReferencedLocalVariables().put("arguments",vArguments);
    179
    180                 node.addSyntheticMethod(
    181                     "invokeMethod",
    182                     ACC_PUBLIC,
    183                     ClassHelper.OBJECT_TYPE,
    184                     new Parameter[] {
    185                         new Parameter(ClassHelper.STRING_TYPE, "method"),
    186                         new Parameter(ClassHelper.OBJECT_TYPE, "arguments")
    187                     },
    188                     ClassNode.EMPTY_ARRAY,
    189                     new BlockStatement(
    190                         new Statement[] {
    191                             initMetaClassField,
    192                             new ReturnStatement(
    193                                 new MethodCallExpression(
    194                                     metaClassVar,
    195                                     "invokeMethod",
    196                                     new ArgumentListExpression(
    197                                         new Expression[] {
    198                                             VariableExpression.THIS_EXPRESSION,
    199                                             vMethods,
    200                                             vArguments}
    201                                         )
    202                                     )
    203                                 )
    204                         },
    205                         blockScope
    206                     )
    207                 );
    208
    209
    210                 if (!node.isScript()) {
    211                     node.addSyntheticMethod(
    212                         "getProperty",
    213                         ACC_PUBLIC,
    214                         ClassHelper.OBJECT_TYPE,
    215                         new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "property")},
    216                         ClassNode.EMPTY_ARRAY,
    217                         new BlockStatement(
    218                             new Statement[] {
    219                                 initMetaClassField,
    220                                 new ReturnStatement(
    221                                     new MethodCallExpression(
    222                                         metaClassVar,
    223                                         "getProperty",
    224                                         new ArgumentListExpression(
    225                                             new Expression[] {
    226                                                 VariableExpression.THIS_EXPRESSION,
    227                                                 new VariableExpression("property")})))
    228                             },
    229                             new VariableScope()
    230                         ));
    231                     VariableExpression vProp = new VariableExpression("property");
    232                     VariableExpression vValue = new VariableExpression("value");
    233                     blockScope = new VariableScope();
    234                     blockScope.getReferencedLocalVariables().put("property",vProp);
    235                     blockScope.getReferencedLocalVariables().put("value",vValue);
    236
    237                     node.addSyntheticMethod(
    238                         "setProperty",
    239                         ACC_PUBLIC,
    240                         ClassHelper.VOID_TYPE,
    241                         new Parameter[] {
    242                             new Parameter(ClassHelper.STRING_TYPE, "property"),
    243                             new Parameter(ClassHelper.OBJECT_TYPE, "value")
    244                         },
    245                         ClassNode.EMPTY_ARRAY,
    246                         new BlockStatement(
    247                             new Statement[] {
    248                                 initMetaClassField,
    249                                 new ExpressionStatement(
    250                                     new MethodCallExpression(
    251                                         metaClassVar,
    252                                         "setProperty",
    253                                         new ArgumentListExpression(
    254                                             new Expression[] {
    255                                                 VariableExpression.THIS_EXPRESSION,
    256                                                 vProp,
    257                                                 vValue})))
    258                             },
    259                             blockScope
    260                     ));
    261                 }
    262             }
    263         }
    264
    265         if (node.getDeclaredConstructors().isEmpty()) {
    266             ConstructorNode constructor = new ConstructorNode(ACC_PUBLIC, null);
    267             constructor.setSynthetic(true);
    268             node.addConstructor(constructor);
    269         }
    270
    271         if (!(node instanceof InnerClassNode)) {// add a static timestamp field to the class
    272             FieldNode timeTagField = new FieldNode(
    273                     Verifier.__TIMESTAMP,
    274                     Modifier.PUBLIC | Modifier.STATIC,
    275                     ClassHelper.Long_TYPE,
    276                     //"",
    277                     node,
    278                     new ConstantExpression(new Long(System.currentTimeMillis())));
    279             // alternatively , FieldNode timeTagField = SourceUnit.createFieldNode("public static final long __timeStamp = " + System.currentTimeMillis() + "L");
    280             timeTagField.setSynthetic(true);
    281             node.addField(timeTagField);
    282         }
    283
    284         addInitialization(node);
    285         node.getObjectInitializerStatements().clear();
    286         node.visitContents(this);
    287     }
    288     public void visitConstructor(ConstructorNode node) {
    289         CodeVisitorSupport checkSuper = new CodeVisitorSupport() {
    290             boolean firstMethodCall = true;
    291             String type=null;
    292             public void visitMethodCallExpression(MethodCallExpression call) {
    293                 if (!firstMethodCall) return;
    294                 firstMethodCall = false;
    295                 String name = call.getMethodAsString();
    296                 if (!name.equals("super") && !name.equals("this")) return;
    297                 type=name;
    298                 call.getArguments().visit(this);
    299                 type=null;
    300             }
    301             public void visitVariableExpression(VariableExpression expression) {
    302                 if (type==null) return;
    303                 String name = expression.getName();
    304                 if (!name.equals("this") && !name.equals("super")) return;
    305                 throw new RuntimeParserException("cannot reference "+name+" inside of "+type+"(....) before supertype constructor has been called",expression);
    306             }
    307         };
    308         Statement s = node.getCode();
    309         //todo why can a statement can be null?
    310         if (s == null) return;
    311         s.visit(checkSuper);
    312     }
    313
    314     public void visitMethod(MethodNode node) {
    315         this.methodNode = node;
    316         Statement statement = node.getCode();
    317         if (!node.isVoidMethod()) {
    318             if (statement instanceof ExpressionStatement) {
    319                 ExpressionStatement expStmt = (ExpressionStatement) statement;
    320                 node.setCode(new ReturnStatement(expStmt.getExpression()));
    321             }
    322             else if (statement instanceof BlockStatement) {
    323                 BlockStatement block = (BlockStatement) statement;
    324
    325                 // lets copy the list so we create a new block
    326                 List list = new ArrayList(block.getStatements());
    327                 if (!list.isEmpty()) {
    328                     int idx = list.size() - 1;
    329                     Statement last = (Statement) list.get(idx);
    330                     if (last instanceof ExpressionStatement) {
    331                         ExpressionStatement expStmt = (ExpressionStatement) last;
    332                         list.set(idx, new ReturnStatement(expStmt));
    333                     }
    334                     else if (!(last instanceof ReturnStatement)) {
    335                         list.add(new ReturnStatement(ConstantExpression.NULL));
    336                     }
    337                 }
    338                 else {
    339                     list.add(new ReturnStatement(ConstantExpression.NULL));
    340                 }
    341
    342                 node.setCode(new BlockStatement(filterStatements(list),block.getVariableScope()));
    343             }
    344         }
    345         else if (!node.isAbstract()) {
    346         	BlockStatement newBlock = new BlockStatement();
    347             if (statement instanceof BlockStatement) {
    348                 newBlock.addStatements(filterStatements(((BlockStatement)statement).getStatements()));
    349             }
    350             else {
    351                 newBlock.addStatement(filterStatement(statement));
    352             }
    353             newBlock.addStatement(ReturnStatement.RETURN_NULL_OR_VOID);
    354             node.setCode(newBlock);
    355         }
    356         if (node.getName().equals("main") && node.isStatic()) {
    357             Parameter[] params = node.getParameters();
    358             if (params.length == 1) {
    359                 Parameter param = params[0];
    360                 if (param.getType() == null || param.getType()==ClassHelper.OBJECT_TYPE) {
    361                     param.setType(ClassHelper.STRING_TYPE.makeArray());
    362                 }
    363             }
    364         }
    365         statement = node.getCode();
    366         if (statement!=null) statement.visit(new VerifierCodeVisitor(this));
    367     }
    368
    369     public void visitField(FieldNode node) {
    370     }
    371
    372     public void visitProperty(PropertyNode node) {
    373         String name = node.getName();
    374         FieldNode field = node.getField();
    375
    376         String getterName = "get" + capitalize(name);
    377         String setterName = "set" + capitalize(name);
    378
    379         Statement getterBlock = node.getGetterBlock();
    380         if (getterBlock == null) {
    381             if (!node.isPrivate() && classNode.getGetterMethod(getterName) == null) {
    382                 getterBlock = createGetterBlock(node, field);
    383             }
    384         }
    385         Statement setterBlock = node.getSetterBlock();
    386         if (setterBlock == null) {
    387             if (!node.isPrivate() && (node.getModifiers()&ACC_FINAL)==0 && classNode.getSetterMethod(setterName) == null) {
    388                 setterBlock = createSetterBlock(node, field);
    389             }
    390         }
    391
    392         if (getterBlock != null) {
    393             MethodNode getter =
    394                 new MethodNode(getterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getterBlock);
    395             getter.setSynthetic(true);
    396             classNode.addMethod(getter);
    397             visitMethod(getter);
    398
    399             if (ClassHelper.boolean_TYPE==node.getType() || ClassHelper.Boolean_TYPE==node.getType()) {
    400                 String secondGetterName = "is" + capitalize(name);
    401                 MethodNode secondGetter =
    402                     new MethodNode(secondGetterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getterBlock);
    403                 secondGetter.setSynthetic(true);
    404                 classNode.addMethod(secondGetter);
    405                 visitMethod(secondGetter);
    406             }
    407         }
    408         if (setterBlock != null) {
    409             Parameter[] setterParameterTypes = { new Parameter(node.getType(), "value")};
    410             MethodNode setter =
    411                 new MethodNode(setterName, node.getModifiers(), ClassHelper.VOID_TYPE, setterParameterTypes, ClassNode.EMPTY_ARRAY, setterBlock);
    412             setter.setSynthetic(true);
    413             classNode.addMethod(setter);
    414             visitMethod(setter);
    415         }
    416     }
    417
    418     // Implementation methods
    419     //-------------------------------------------------------------------------
    420
    421     private interface DefaultArgsAction {
    422         public void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method);
    423     }
    424
    425     /***
    426      * Creates a new helper method for each combination of default parameter expressions
    427      */
    428     protected void addDefaultParameterMethods(final ClassNode node) {
    429         List methods = new ArrayList(node.getMethods());
    430         addDefaultParameters(methods, new DefaultArgsAction(){
    431             public void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method) {
    432                 MethodCallExpression expression = new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
    433                 expression.setImplicitThis(true);
    434                 Statement code = null;
    435                 if (method.isVoidMethod()) {
    436                     code = new ExpressionStatement(expression);
    437                 } else {
    438                     code = new ReturnStatement(expression);
    439                 }
    440                 node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, method.getExceptions(), code);
    441             }
    442         });
    443     }
    444
    445     protected void addDefaultParameterConstructors(final ClassNode node) {
    446         List methods = new ArrayList(node.getDeclaredConstructors());
    447         addDefaultParameters(methods, new DefaultArgsAction(){
    448             public void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method) {
    449                 ConstructorNode ctor = (ConstructorNode) method;
    450                 ConstructorCallExpression expression = new ConstructorCallExpression(ClassNode.THIS, arguments);
    451                 Statement code = new ExpressionStatement(expression);
    452                 node.addConstructor(ctor.getModifiers(), newParams, ctor.getExceptions(), code);
    453             }
    454         });
    455     }
    456
    457     /***
    458      * Creates a new helper method for each combination of default parameter expressions
    459      */
    460     protected void addDefaultParameters(List methods, DefaultArgsAction action) {
    461         for (Iterator iter = methods.iterator(); iter.hasNext();) {
    462             MethodNode method = (MethodNode) iter.next();
    463             if (method.hasDefaultValue()) {
    464                 Parameter[] parameters = method.getParameters();
    465                 int counter = 0;
    466                 ArrayList paramValues = new ArrayList();
    467                 int size = parameters.length;
    468                 for (int i = size - 1; i >= 0; i--) {
    469                     Parameter parameter = parameters[i];
    470                     if (parameter != null && parameter.hasInitialExpression()) {
    471                         paramValues.add(new Integer(i));
    472                         paramValues.add(parameter.getInitialExpression());
    473                         counter++;
    474                     }
    475                 }
    476
    477                 for (int j = 1; j <= counter; j++) {
    478                     Parameter[] newParams =  new Parameter[parameters.length - j];
    479                     ArgumentListExpression arguments = new ArgumentListExpression();
    480                     int index = 0;
    481                     int k = 1;
    482                     for (int i = 0; i < parameters.length; i++) {
    483                         if (k > counter - j && parameters[i] != null && parameters[i].hasInitialExpression()) {
    484                             arguments.addExpression(parameters[i].getInitialExpression());
    485                             k++;
    486                         }
    487                         else if (parameters[i] != null && parameters[i].hasInitialExpression()) {
    488                             newParams[index++] = parameters[i];
    489                             arguments.addExpression(new VariableExpression(parameters[i].getName()));
    490                             k++;
    491                         }
    492                         else {
    493                             newParams[index++] = parameters[i];
    494                             arguments.addExpression(new VariableExpression(parameters[i].getName()));
    495                         }
    496                     }
    497                     action.call(arguments,newParams,method);
    498                 }
    499             }
    500         }
    501     }
    502
    503     protected void addClosureCode(InnerClassNode node) {
    504         // add a new invoke
    505     }
    506
    507     protected void addInitialization(ClassNode node) {
    508         for (Iterator iter = node.getDeclaredConstructors().iterator(); iter.hasNext();) {
    509             addInitialization(node, (ConstructorNode) iter.next());
    510         }
    511     }
    512
    513     protected void addInitialization(ClassNode node, ConstructorNode constructorNode) {
    514         Statement firstStatement = constructorNode.getFirstStatement();
    515         ConstructorCallExpression first = getFirstIfSpecialConstructorCall(firstStatement);
    516
    517         // in case of this(...) let the other constructor do the intit
    518         if (first!=null && first.isThisCall()) return;
    519
    520         List statements = new ArrayList();
    521         List staticStatements = new ArrayList();
    522         for (Iterator iter = node.getFields().iterator(); iter.hasNext();) {
    523             addFieldInitialization(statements, staticStatements, (FieldNode) iter.next());
    524         }
    525         statements.addAll(node.getObjectInitializerStatements());
    526         if (!statements.isEmpty()) {
    527             Statement code = constructorNode.getCode();
    528             BlockStatement block = new BlockStatement();
    529             List otherStatements = block.getStatements();
    530             if (code instanceof BlockStatement) {
    531                 block = (BlockStatement) code;
    532                 otherStatements=block.getStatements();
    533             }
    534             else if (code != null) {
    535                 otherStatements.add(code);
    536             }
    537             if (!otherStatements.isEmpty()) {
    538                 if (first!=null) {
    539                     // it is super(..) since this(..) is already covered
    540                     otherStatements.remove(0);
    541                     statements.add(0, firstStatement);
    542                 }
    543                 statements.addAll(otherStatements);
    544             }
    545             constructorNode.setCode(new BlockStatement(statements, block.getVariableScope()));
    546         }
    547
    548         if (!staticStatements.isEmpty()) {
    549             node.addStaticInitializerStatements(staticStatements,true);
    550         }
    551     }
    552
    553     private ConstructorCallExpression getFirstIfSpecialConstructorCall(Statement code) {
    554         if (code == null || !(code instanceof ExpressionStatement)) return null;
    555
    556         Expression expression = ((ExpressionStatement)code).getExpression();
    557         if (!(expression instanceof ConstructorCallExpression)) return null;
    558         ConstructorCallExpression cce = (ConstructorCallExpression) expression;
    559         if (cce.isSpecialCall()) return cce;
    560         return null;
    561     }
    562
    563     protected void addFieldInitialization(
    564         List list,
    565         List staticList,
    566         FieldNode fieldNode) {
    567         Expression expression = fieldNode.getInitialExpression();
    568         if (expression != null) {
    569             ExpressionStatement statement =
    570                 new ExpressionStatement(
    571                     new BinaryExpression(
    572                         new FieldExpression(fieldNode),
    573                         Token.newSymbol(Types.EQUAL, fieldNode.getLineNumber(), fieldNode.getColumnNumber()),
    574                         expression));
    575             if (fieldNode.isStatic()) {
    576                 staticList.add(statement);
    577             }
    578             else {
    579                 list.add(statement);
    580             }
    581         }
    582     }
    583
    584     /***
    585      * Capitalizes the start of the given bean property name
    586      */
    587     public static String capitalize(String name) {
    588         return name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
    589     }
    590
    591     protected Statement createGetterBlock(PropertyNode propertyNode, FieldNode field) {
    592         Expression expression = new FieldExpression(field);
    593         return new ReturnStatement(expression);
    594     }
    595
    596     protected Statement createSetterBlock(PropertyNode propertyNode, FieldNode field) {
    597         Expression expression = new FieldExpression(field);
    598         return new ExpressionStatement(
    599             new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("value")));
    600     }
    601
    602     /***
    603      * Filters the given statements
    604      */
    605     protected List filterStatements(List list) {
    606         List answer = new ArrayList(list.size());
    607         for (Iterator iter = list.iterator(); iter.hasNext();) {
    608             answer.add(filterStatement((Statement) iter.next()));
    609         }
    610         return answer;
    611     }
    612
    613     protected Statement filterStatement(Statement statement) {
    614         if (statement instanceof ExpressionStatement) {
    615             ExpressionStatement expStmt = (ExpressionStatement) statement;
    616             Expression expression = expStmt.getExpression();
    617             if (expression instanceof ClosureExpression) {
    618                 ClosureExpression closureExp = (ClosureExpression) expression;
    619                 if (!closureExp.isParameterSpecified()) {
    620                     return closureExp.getCode();
    621                 }
    622             }
    623         }
    624         return statement;
    625     }
    626
    627 }