View Javadoc

    1   /*
    2    $Id: Verifier.java,v 1.55 2006/06/25 19:58:43 blackdrag 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
    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.Closure;
    49  import groovy.lang.GroovyObject;
    50  import groovy.lang.MetaClass;
    51
    52  import java.lang.reflect.Modifier;
    53  import java.util.ArrayList;
    54  import java.util.Iterator;
    55  import java.util.List;
    56
    57  import org.codehaus.groovy.ast.ClassHelper;
    58  import org.codehaus.groovy.ast.ClassNode;
    59  import org.codehaus.groovy.ast.CodeVisitorSupport;
    60  import org.codehaus.groovy.ast.ConstructorNode;
    61  import org.codehaus.groovy.ast.FieldNode;
    62  import org.codehaus.groovy.ast.GroovyClassVisitor;
    63  import org.codehaus.groovy.ast.InnerClassNode;
    64  import org.codehaus.groovy.ast.MethodNode;
    65  import org.codehaus.groovy.ast.Parameter;
    66  import org.codehaus.groovy.ast.PropertyNode;
    67  import org.codehaus.groovy.ast.VariableScope;
    68  import org.codehaus.groovy.ast.expr.ArgumentListExpression;
    69  import org.codehaus.groovy.ast.expr.BinaryExpression;
    70  import org.codehaus.groovy.ast.expr.BooleanExpression;
    71  import org.codehaus.groovy.ast.expr.ClosureExpression;
    72  import org.codehaus.groovy.ast.expr.ConstantExpression;
    73  import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
    74  import org.codehaus.groovy.ast.expr.Expression;
    75  import org.codehaus.groovy.ast.expr.FieldExpression;
    76  import org.codehaus.groovy.ast.expr.MethodCallExpression;
    77  import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
    78  import org.codehaus.groovy.ast.expr.VariableExpression;
    79  import org.codehaus.groovy.ast.stmt.BlockStatement;
    80  import org.codehaus.groovy.ast.stmt.EmptyStatement;
    81  import org.codehaus.groovy.ast.stmt.ExpressionStatement;
    82  import org.codehaus.groovy.ast.stmt.IfStatement;
    83  import org.codehaus.groovy.ast.stmt.ReturnStatement;
    84  import org.codehaus.groovy.ast.stmt.Statement;
    85  import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
    86  import org.codehaus.groovy.syntax.Types;
    87  import org.codehaus.groovy.syntax.Token;
    88  import org.codehaus.groovy.syntax.RuntimeParserException;
    89  import org.objectweb.asm.Opcodes;
    90
    91  /***
    92   * Verifies the AST node and adds any defaulted AST code before
    93   * bytecode generation occurs.
    94   *
    95   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
    96   * @version $Revision: 1.55 $
    97   */
    98  public class Verifier implements GroovyClassVisitor, Opcodes {
    99
    100     public static final String __TIMESTAMP = "__timeStamp";
    101 	private ClassNode classNode;
    102     private MethodNode methodNode;
    103
    104     public ClassNode getClassNode() {
    105         return classNode;
    106     }
    107
    108     public MethodNode getMethodNode() {
    109         return methodNode;
    110     }
    111
    112     /***
    113      * add code to implement GroovyObject
    114      * @param node
    115      */
    116     public void visitClass(ClassNode node) {
    117         this.classNode = node;
    118
    119         if ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) >0) {
    120             //interfaces have no construcotrs, but this code expects one,
    121             //so creta a dummy and don't add it to the class node
    122             ConstructorNode dummy = new ConstructorNode(0,null);
    123             addInitialization(node, dummy);
    124             node.visitContents(this);
    125             return;
    126         }
    127
    128         addDefaultParameterMethods(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                     "getMetaClass",
    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(Closure.class.getName()))
    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.getMethod();
    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     /***
    422      * Creates a new helper method for each combination of default parameter expressions
    423      */
    424     protected void addDefaultParameterMethods(ClassNode node) {
    425         List methods = new ArrayList(node.getMethods());
    426         for (Iterator iter = methods.iterator(); iter.hasNext();) {
    427             MethodNode method = (MethodNode) iter.next();
    428             if (method.hasDefaultValue()) {
    429                 Parameter[] parameters = method.getParameters();
    430                 int counter = 0;
    431                 ArrayList paramValues = new ArrayList();
    432                 int size = parameters.length;
    433                 for (int i = size - 1; i >= 0; i--) {
    434                     Parameter parameter = parameters[i];
    435                     if (parameter != null && parameter.hasInitialExpression()) {
    436                         paramValues.add(new Integer(i));
    437                         paramValues.add(parameter.getInitialExpression());
    438                         counter++;
    439                     }
    440                 }
    441
    442                 for (int j = 1; j <= counter; j++) {
    443                     Parameter[] newParams =  new Parameter[parameters.length - j];
    444                     ArgumentListExpression arguments = new ArgumentListExpression();
    445                     int index = 0;
    446                     int k = 1;
    447                     for (int i = 0; i < parameters.length; i++) {
    448                         if (k > counter - j && parameters[i] != null && parameters[i].hasInitialExpression()) {
    449                             arguments.addExpression(parameters[i].getInitialExpression());
    450                             k++;
    451                         }
    452                         else if (parameters[i] != null && parameters[i].hasInitialExpression()) {
    453                             newParams[index++] = parameters[i];
    454                             arguments.addExpression(new VariableExpression(parameters[i].getName()));
    455                             k++;
    456                         }
    457                         else {
    458                             newParams[index++] = parameters[i];
    459                             arguments.addExpression(new VariableExpression(parameters[i].getName()));
    460                         }
    461                     }
    462
    463                     MethodCallExpression expression = new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
    464                     Statement code = null;
    465                     if (method.isVoidMethod()) {
    466                         code = new ExpressionStatement(expression);
    467                     }
    468                     else {
    469                         code = new ReturnStatement(expression);
    470                     }
    471                     node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, method.getExceptions(), code);
    472                 }
    473             }
    474         }
    475     }
    476
    477     /***
    478      * Adds a new method which defaults the values for all the parameters starting
    479      * from and including the given index
    480      *
    481      * @param node the class to add the method
    482      * @param method the given method to add a helper of
    483      * @param parameters the parameters of the method to add a helper for
    484      * @param index the index of the first default value expression parameter to use
    485      */
    486     protected void addDefaultParameterMethod(ClassNode node, MethodNode method, Parameter[] parameters, int depth, ArrayList values) {
    487         // lets create a method using this expression
    488         Parameter[] newParams = new Parameter[parameters.length - depth];
    489         int index = 0;
    490         ArgumentListExpression arguments = new ArgumentListExpression();
    491         for (int i = 0; i < parameters.length; i++) {
    492             if (parameters[i] != null && parameters[i].hasInitialExpression()) {
    493                 newParams[index++] = parameters[i];
    494                 arguments.addExpression(new VariableExpression(parameters[i].getName()));
    495             }
    496             else {
    497                 arguments.addExpression(parameters[i].getInitialExpression());
    498             }
    499         }
    500
    501         MethodCallExpression expression =
    502             new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
    503         Statement code = null;
    504         if (method.isVoidMethod()) {
    505             code = new ExpressionStatement(expression);
    506         }
    507         else {
    508             code = new ReturnStatement(expression);
    509         }
    510
    511         node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, method.getExceptions(), code);
    512     }
    513
    514     /***
    515      * Adds a new method which defaults the values for all the parameters starting
    516      * from and including the given index
    517      *
    518      * @param node the class to add the method
    519      * @param method the given method to add a helper of
    520      * @param parameters the parameters of the method to add a helper for
    521      * @param index the index of the first default value expression parameter to use
    522      */
    523     protected void addDefaultParameterMethod(ClassNode node, MethodNode method, Parameter[] parameters, int index) {
    524         // lets create a method using this expression
    525         Parameter[] newParams = new Parameter[index];
    526         System.arraycopy(parameters, 0, newParams, 0, index);
    527
    528         ArgumentListExpression arguments = new ArgumentListExpression();
    529         int size = parameters.length;
    530         for (int i = 0; i < size; i++) {
    531             if (i < index) {
    532                 arguments.addExpression(new VariableExpression(parameters[i].getName()));
    533             }
    534             else {
    535                 Expression defaultValue = parameters[i].getInitialExpression();
    536                 if (defaultValue == null) {
    537                     throw new RuntimeParserException(
    538                         "The " + parameters[i].getName() + " parameter must have a default value",
    539                         method);
    540                 }
    541                 else {
    542                     arguments.addExpression(defaultValue);
    543                 }
    544             }
    545         }
    546
    547         MethodCallExpression expression =
    548             new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
    549         Statement code = null;
    550         if (method.isVoidMethod()) {
    551             code = new ExpressionStatement(expression);
    552             }
    553         else {
    554             code = new ReturnStatement(expression);
    555         }
    556
    557         node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, method.getExceptions(), code);
    558     }
    559
    560     protected void addClosureCode(InnerClassNode node) {
    561         // add a new invoke
    562     }
    563
    564     protected void addInitialization(ClassNode node) {
    565         for (Iterator iter = node.getDeclaredConstructors().iterator(); iter.hasNext();) {
    566             addInitialization(node, (ConstructorNode) iter.next());
    567         }
    568     }
    569
    570     protected void addInitialization(ClassNode node, ConstructorNode constructorNode) {
    571         Statement firstStatement = constructorNode.getFirstStatement();
    572         ConstructorCallExpression first = getFirstIfSpecialConstructorCall(firstStatement);
    573
    574         // in case of this(...) let the other constructor do the intit
    575         if (first!=null && first.isThisCall()) return;
    576
    577         List statements = new ArrayList();
    578         List staticStatements = new ArrayList();
    579         for (Iterator iter = node.getFields().iterator(); iter.hasNext();) {
    580             addFieldInitialization(statements, staticStatements, (FieldNode) iter.next());
    581         }
    582         statements.addAll(node.getObjectInitializerStatements());
    583         if (!statements.isEmpty()) {
    584             Statement code = constructorNode.getCode();
    585             BlockStatement block = new BlockStatement();
    586             List otherStatements = block.getStatements();
    587             if (code instanceof BlockStatement) {
    588                 block = (BlockStatement) code;
    589                 otherStatements=block.getStatements();
    590             }
    591             else if (code != null) {
    592                 otherStatements.add(code);
    593             }
    594             if (!otherStatements.isEmpty()) {
    595                 if (first!=null) {
    596                     // it is super(..) since this(..) is already covered
    597                     otherStatements.remove(0);
    598                     statements.add(0, firstStatement);
    599                 }
    600                 statements.addAll(otherStatements);
    601             }
    602             constructorNode.setCode(new BlockStatement(statements, block.getVariableScope()));
    603         }
    604
    605         if (!staticStatements.isEmpty()) {
    606             node.addStaticInitializerStatements(staticStatements,true);
    607         }
    608     }
    609
    610     private ConstructorCallExpression getFirstIfSpecialConstructorCall(Statement code) {
    611         if (code == null || !(code instanceof ExpressionStatement)) return null;
    612
    613         Expression expression = ((ExpressionStatement)code).getExpression();
    614         if (!(expression instanceof ConstructorCallExpression)) return null;
    615         ConstructorCallExpression cce = (ConstructorCallExpression) expression;
    616         if (cce.isSpecialCall()) return cce;
    617         return null;
    618     }
    619
    620     protected void addFieldInitialization(
    621         List list,
    622         List staticList,
    623         FieldNode fieldNode) {
    624         Expression expression = fieldNode.getInitialExpression();
    625         if (expression != null) {
    626             ExpressionStatement statement =
    627                 new ExpressionStatement(
    628                     new BinaryExpression(
    629                         new FieldExpression(fieldNode),
    630                         Token.newSymbol(Types.EQUAL, fieldNode.getLineNumber(), fieldNode.getColumnNumber()),
    631                         expression));
    632             if (fieldNode.isStatic()) {
    633                 staticList.add(statement);
    634             }
    635             else {
    636                 list.add(statement);
    637             }
    638         }
    639     }
    640
    641     /***
    642      * Capitalizes the start of the given bean property name
    643      */
    644     public static String capitalize(String name) {
    645         return name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
    646     }
    647
    648     protected Statement createGetterBlock(PropertyNode propertyNode, FieldNode field) {
    649         Expression expression = new FieldExpression(field);
    650         return new ReturnStatement(expression);
    651     }
    652
    653     protected Statement createSetterBlock(PropertyNode propertyNode, FieldNode field) {
    654         Expression expression = new FieldExpression(field);
    655         return new ExpressionStatement(
    656             new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("value")));
    657     }
    658
    659     /***
    660      * Filters the given statements
    661      */
    662     protected List filterStatements(List list) {
    663         List answer = new ArrayList(list.size());
    664         for (Iterator iter = list.iterator(); iter.hasNext();) {
    665             answer.add(filterStatement((Statement) iter.next()));
    666         }
    667         return answer;
    668     }
    669
    670     protected Statement filterStatement(Statement statement) {
    671         if (statement instanceof ExpressionStatement) {
    672             ExpressionStatement expStmt = (ExpressionStatement) statement;
    673             Expression expression = expStmt.getExpression();
    674             if (expression instanceof ClosureExpression) {
    675                 ClosureExpression closureExp = (ClosureExpression) expression;
    676                 if (!closureExp.isParameterSpecified()) {
    677                     return closureExp.getCode();
    678                 }
    679             }
    680         }
    681         return statement;
    682     }
    683
    684 }