View Javadoc

1   /*
2    $Id: Verifier.java,v 1.41 2005/07/16 20:00:26 phk 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.GString;
50  import groovy.lang.GroovyObject;
51  import groovy.lang.MetaClass;
52  
53  import java.lang.reflect.Modifier;
54  import java.util.ArrayList;
55  import java.util.Iterator;
56  import java.util.List;
57  
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.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.Expression;
73  import org.codehaus.groovy.ast.expr.FieldExpression;
74  import org.codehaus.groovy.ast.expr.MethodCallExpression;
75  import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
76  import org.codehaus.groovy.ast.expr.VariableExpression;
77  import org.codehaus.groovy.ast.stmt.BlockStatement;
78  import org.codehaus.groovy.ast.stmt.EmptyStatement;
79  import org.codehaus.groovy.ast.stmt.ExpressionStatement;
80  import org.codehaus.groovy.ast.stmt.IfStatement;
81  import org.codehaus.groovy.ast.stmt.ReturnStatement;
82  import org.codehaus.groovy.ast.stmt.Statement;
83  import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
84  import org.codehaus.groovy.syntax.Types;
85  import org.codehaus.groovy.syntax.Token;
86  import org.codehaus.groovy.syntax.RuntimeParserException;
87  import org.objectweb.asm.Opcodes;
88  
89  /***
90   * Verifies the AST node and adds any defaulted AST code before
91   * bytecode generation occurs.
92   * 
93   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
94   * @version $Revision: 1.41 $
95   */
96  public class Verifier implements GroovyClassVisitor, Opcodes {
97  
98      public static final String __TIMESTAMP = "__timeStamp";
99  	private ClassNode classNode;
100     private MethodNode methodNode;
101 
102     public ClassNode getClassNode() {
103         return classNode;
104     }
105 
106     public MethodNode getMethodNode() {
107         return methodNode;
108     }
109 
110     /***
111      * add code to implement GroovyObject
112      * @param node
113      */
114     public void visitClass(ClassNode node) {
115         this.classNode = node;
116                 
117         if ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) >0) {
118             node.visitContents(this);
119             return;
120         }
121         
122         addDefaultParameterMethods(node);
123 
124         if (!node.isDerivedFromGroovyObject()) {
125             node.addInterface(GroovyObject.class.getName());
126 
127             // lets add a new field for the metaclass
128             StaticMethodCallExpression initMetaClassCall =
129                 new StaticMethodCallExpression(
130                     ScriptBytecodeAdapter.class.getName(),
131                     "getMetaClass",
132                     VariableExpression.THIS_EXPRESSION);
133 
134             PropertyNode metaClassProperty =
135                 node.addProperty("metaClass", ACC_PUBLIC, MetaClass.class.getName(), initMetaClassCall, null, null);
136             metaClassProperty.setSynthetic(true);
137             FieldNode metaClassField = metaClassProperty.getField();
138             metaClassField.setModifiers(metaClassField.getModifiers() | ACC_TRANSIENT);
139 
140             FieldExpression metaClassVar = new FieldExpression(metaClassField);
141             IfStatement initMetaClassField =
142                 new IfStatement(
143                     new BooleanExpression(
144                         new BinaryExpression(metaClassVar, Token.newSymbol( Types.COMPARE_EQUAL, -1, -1), ConstantExpression.NULL)),
145                     new ExpressionStatement(new BinaryExpression(metaClassVar, Token.newSymbol( Types.EQUAL, -1, -1), initMetaClassCall)),
146                     EmptyStatement.INSTANCE);
147 
148             node.addSyntheticMethod(
149                 "getMetaClass",
150                 ACC_PUBLIC,
151                 MetaClass.class.getName(),
152                 Parameter.EMPTY_ARRAY,
153                 new BlockStatement(new Statement[] { initMetaClassField, new ReturnStatement(metaClassVar)}));
154 
155             // @todo we should check if the base class implements the invokeMethod method
156 
157             // lets add the invokeMethod implementation
158             String superClass = node.getSuperClass();
159             boolean addDelegateObject =
160                 (node instanceof InnerClassNode && superClass.equals(Closure.class.getName()))
161                     || superClass.equals(GString.class.getName());
162 
163             // don't do anything as the base class implements the invokeMethod
164             if (!addDelegateObject) {
165                 node.addSyntheticMethod(
166                     "invokeMethod",
167                     ACC_PUBLIC,
168                     Object.class.getName(),
169                     new Parameter[] {
170                         new Parameter(String.class.getName(), "method"),
171                         new Parameter(Object.class.getName(), "arguments")},
172                     new BlockStatement(
173                         new Statement[] {
174                             initMetaClassField,
175                             new ReturnStatement(
176                                 new MethodCallExpression(
177                                     metaClassVar,
178                                     "invokeMethod",
179                                     new ArgumentListExpression(
180                                         new Expression[] {
181                                             VariableExpression.THIS_EXPRESSION,
182                                             new VariableExpression("method"),
183                                             new VariableExpression("arguments")})))
184                 }));
185 
186                 if (!node.isScript()) {
187                     node.addSyntheticMethod(
188                         "getProperty",
189                         ACC_PUBLIC,
190                         Object.class.getName(),
191                         new Parameter[] { new Parameter(String.class.getName(), "property")},
192                         new BlockStatement(
193                             new Statement[] {
194                                 initMetaClassField,
195                                 new ReturnStatement(
196                                     new MethodCallExpression(
197                                         metaClassVar,
198                                         "getProperty",
199                                         new ArgumentListExpression(
200                                             new Expression[] {
201                                                 VariableExpression.THIS_EXPRESSION,
202                                                 new VariableExpression("property")})))
203                     }));
204 
205                     node.addSyntheticMethod(
206                         "setProperty",
207                         ACC_PUBLIC,
208                         "void",
209                         new Parameter[] {
210                             new Parameter(String.class.getName(), "property"),
211                             new Parameter(Object.class.getName(), "value")},
212                         new BlockStatement(
213                             new Statement[] {
214                                 initMetaClassField,
215                                 new ExpressionStatement(
216                                     new MethodCallExpression(
217                                         metaClassVar,
218                                         "setProperty",
219                                         new ArgumentListExpression(
220                                             new Expression[] {
221                                                 VariableExpression.THIS_EXPRESSION,
222                                                 new VariableExpression("property"),
223                                                 new VariableExpression("value")})))
224                     }));
225                 }
226             }
227         }
228 
229         if (node.getDeclaredConstructors().isEmpty()) {
230             ConstructorNode constructor = new ConstructorNode(ACC_PUBLIC, null);
231             constructor.setSynthetic(true);
232             node.addConstructor(constructor);
233         }
234         
235         if (!(node instanceof InnerClassNode)) {// add a static timestamp field to the class
236             FieldNode timeTagField = new FieldNode(
237                     Verifier.__TIMESTAMP,
238                     Modifier.PUBLIC | Modifier.STATIC,
239                     "java.lang.Long",
240                     //"",
241                     node.getName(),
242                     new ConstantExpression(new Long(System.currentTimeMillis())));
243             // alternatively , FieldNode timeTagField = SourceUnit.createFieldNode("public static final long __timeStamp = " + System.currentTimeMillis() + "L");
244             timeTagField.setSynthetic(true);
245             node.addField(timeTagField);
246         }
247 
248         addFieldInitialization(node);
249 
250         node.visitContents(this);
251     }
252     public void visitConstructor(ConstructorNode node) {
253         CodeVisitorSupport checkSuper = new CodeVisitorSupport() {
254             boolean firstMethodCall = true;
255             String type=null;
256             public void visitMethodCallExpression(MethodCallExpression call) {
257                 if (!firstMethodCall) return;
258                 firstMethodCall = false;
259                 String name = call.getMethod();
260                 if (!name.equals("super") && !name.equals("this")) return;
261                 type=name;
262                 call.getArguments().visit(this);
263                 type=null;
264             }
265             public void visitVariableExpression(VariableExpression expression) {
266                 if (type==null) return;
267                 String name = expression.getVariable();
268                 if (!name.equals("this") && !name.equals("super")) return;
269                 throw new RuntimeParserException("cannot reference "+name+" inside of "+type+"(....) before supertype constructor has been called",expression);
270             }            
271         };
272         Statement s = node.getCode();
273         //todo why can a statement can be null?
274         if (s == null) return;
275         s.visit(checkSuper);
276     }
277 
278     public void visitMethod(MethodNode node) {
279         this.methodNode = node;
280         Statement statement = node.getCode();
281         if (!node.isVoidMethod()) {
282             if (statement instanceof ExpressionStatement) {
283                 ExpressionStatement expStmt = (ExpressionStatement) statement;
284                 node.setCode(new ReturnStatement(expStmt.getExpression()));
285             }
286             else if (statement instanceof BlockStatement) {
287                 BlockStatement block = (BlockStatement) statement;
288 
289                 // lets copy the list so we create a new block
290                 List list = new ArrayList(block.getStatements());
291                 if (!list.isEmpty()) {
292                     int idx = list.size() - 1;
293                     Statement last = (Statement) list.get(idx);
294                     if (last instanceof ExpressionStatement) {
295                         ExpressionStatement expStmt = (ExpressionStatement) last;
296                         list.set(idx, new ReturnStatement(expStmt.getExpression()));
297                     }
298                     else if (!(last instanceof ReturnStatement)) {
299                         list.add(new ReturnStatement(ConstantExpression.NULL));
300                     }
301                 }
302                 else {
303                     list.add(new ReturnStatement(ConstantExpression.NULL));
304                 }
305 
306                 node.setCode(new BlockStatement(filterStatements(list)));
307             }
308         }
309         else if (!node.isAbstract()) {
310         	BlockStatement newBlock = new BlockStatement();
311             if (statement instanceof BlockStatement) {
312                 newBlock.addStatements(filterStatements(((BlockStatement)statement).getStatements()));
313             }
314             else {
315                 newBlock.addStatement(filterStatement(statement));
316             }
317             newBlock.addStatement(ReturnStatement.RETURN_NULL_OR_VOID);
318             node.setCode(newBlock);
319         }
320         if (node.getName().equals("main") && node.isStatic()) {
321             Parameter[] params = node.getParameters();
322             if (params.length == 1) {
323                 Parameter param = params[0];
324                 if (param.getType() == null || param.getType().equals("java.lang.Object")) {
325                     param.setType("java.lang.String[]");
326                 }
327             }
328         }
329         statement = node.getCode();
330         if (statement!=null) statement.visit(new VerifierCodeVisitor(this));
331     }
332 
333     public void visitField(FieldNode node) {
334     }
335 
336     public void visitProperty(PropertyNode node) {
337         String name = node.getName();
338         FieldNode field = node.getField();
339 
340         
341         String getterPrefix = "get";
342         if ("boolean".equals(node.getType())) {
343             getterPrefix = "is";
344         }
345         String getterName = getterPrefix + capitalize(name);
346         String setterName = "set" + capitalize(name);
347 
348         Statement getterBlock = node.getGetterBlock();
349         if (getterBlock == null) {
350             if (!node.isPrivate() && classNode.getGetterMethod(getterName) == null) {
351                 getterBlock = createGetterBlock(node, field);
352             }
353         }
354         Statement setterBlock = node.getGetterBlock();
355         if (setterBlock == null) {
356             if (!node.isPrivate() && classNode.getSetterMethod(setterName) == null) {
357                 setterBlock = createSetterBlock(node, field);
358             }
359         }
360 
361         if (getterBlock != null) {
362             MethodNode getter =
363                 new MethodNode(getterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, getterBlock);
364             getter.setSynthetic(true);
365             classNode.addMethod(getter);
366             visitMethod(getter);
367 
368             if ("java.lang.Boolean".equals(node.getType())) {
369                 String secondGetterName = "is" + capitalize(name);
370                 MethodNode secondGetter =
371                     new MethodNode(secondGetterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, getterBlock);
372                 secondGetter.setSynthetic(true);
373                 classNode.addMethod(secondGetter);
374                 visitMethod(secondGetter);
375             }
376         }
377         if (setterBlock != null) {
378             Parameter[] setterParameterTypes = { new Parameter(node.getType(), "value")};
379             MethodNode setter =
380                 new MethodNode(setterName, node.getModifiers(), "void", setterParameterTypes, setterBlock);
381             setter.setSynthetic(true);
382             classNode.addMethod(setter);
383             visitMethod(setter);
384         }
385     }
386 
387     // Implementation methods
388     //-------------------------------------------------------------------------
389     
390     /***
391      * Creates a new helper method for each combination of default parameter expressions 
392      */
393     protected void addDefaultParameterMethods(ClassNode node) {
394         List methods = new ArrayList(node.getMethods());
395         for (Iterator iter = methods.iterator(); iter.hasNext();) {
396             MethodNode method = (MethodNode) iter.next();
397             if (method.hasDefaultValue()) {
398                 Parameter[] parameters = method.getParameters();
399                 int counter = 0;
400                 ArrayList paramValues = new ArrayList();
401                 int size = parameters.length;
402                 for (int i = size - 1; i >= 0; i--) {
403                     Parameter parameter = parameters[i];
404                     if (parameter != null && parameter.hasDefaultValue()) {
405                         paramValues.add(new Integer(i));
406                         paramValues.add(parameter.getDefaultValue());
407                         counter++;
408                     }
409                 }
410 
411                 for (int j = 1; j <= counter; j++) {
412                     Parameter[] newParams =  new Parameter[parameters.length - j];
413                     ArgumentListExpression arguments = new ArgumentListExpression();
414                     int index = 0;
415                     int k = 1;
416                     for (int i = 0; i < parameters.length; i++) {
417                         if (k > counter - j && parameters[i] != null && parameters[i].hasDefaultValue()) {
418                             arguments.addExpression(parameters[i].getDefaultValue());
419                             k++;
420                         }
421                         else if (parameters[i] != null && parameters[i].hasDefaultValue()) {
422                             newParams[index++] = parameters[i];
423                             arguments.addExpression(new VariableExpression(parameters[i].getName()));
424                             k++;
425                         }
426                         else {
427                             newParams[index++] = parameters[i];
428                             arguments.addExpression(new VariableExpression(parameters[i].getName()));
429                         }
430                     }
431 
432                     MethodCallExpression expression = new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
433                     Statement code = null;
434                     if (method.isVoidMethod()) {
435                         code = new ExpressionStatement(expression);
436                     }
437                     else {
438                         code = new ReturnStatement(expression);
439                     }
440                     node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, code);
441                 }
442             }
443         }
444     }
445 
446     /***
447      * Adds a new method which defaults the values for all the parameters starting 
448      * from and including the given index
449      * 
450      * @param node the class to add the method
451      * @param method the given method to add a helper of
452      * @param parameters the parameters of the method to add a helper for
453      * @param index the index of the first default value expression parameter to use
454      */
455     protected void addDefaultParameterMethod(ClassNode node, MethodNode method, Parameter[] parameters, int depth, ArrayList values) {
456         // lets create a method using this expression
457         Parameter[] newParams = new Parameter[parameters.length - depth];
458         int index = 0;
459         ArgumentListExpression arguments = new ArgumentListExpression();
460         for (int i = 0; i < parameters.length; i++) {
461             if (parameters[i] != null && parameters[i].hasDefaultValue()) {
462                 newParams[index++] = parameters[i];
463                 arguments.addExpression(new VariableExpression(parameters[i].getName()));
464             }
465             else {
466                 arguments.addExpression(parameters[i].getDefaultValue());
467             }
468         }
469 
470         MethodCallExpression expression =
471             new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
472         Statement code = null;
473         if (method.isVoidMethod()) {
474             code = new ExpressionStatement(expression);
475         }
476         else {
477             code = new ReturnStatement(expression);
478         }
479 
480         node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, code);
481     }
482 
483     /***
484      * Adds a new method which defaults the values for all the parameters starting 
485      * from and including the given index
486      * 
487      * @param node the class to add the method
488      * @param method the given method to add a helper of
489      * @param parameters the parameters of the method to add a helper for
490      * @param index the index of the first default value expression parameter to use
491      */
492     protected void addDefaultParameterMethod(ClassNode node, MethodNode method, Parameter[] parameters, int index) {
493         // lets create a method using this expression
494         Parameter[] newParams = new Parameter[index];
495         System.arraycopy(parameters, 0, newParams, 0, index);
496 
497         ArgumentListExpression arguments = new ArgumentListExpression();
498         int size = parameters.length;
499         for (int i = 0; i < size; i++) {
500             if (i < index) {
501                 arguments.addExpression(new VariableExpression(parameters[i].getName()));
502             }
503             else {
504                 Expression defaultValue = parameters[i].getDefaultValue();
505                 if (defaultValue == null) {
506                     throw new RuntimeParserException(
507                         "The " + parameters[i].getName() + " parameter must have a default value",
508                         method);
509                 }
510                 else {
511                     arguments.addExpression(defaultValue);
512                 }
513             }
514         }
515 
516         MethodCallExpression expression =
517             new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
518         Statement code = null;
519         if (method.isVoidMethod()) {
520             code = new ExpressionStatement(expression);
521             }
522         else {
523             code = new ReturnStatement(expression);
524         }
525 
526         node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, code);
527     }
528 
529     protected void addClosureCode(InnerClassNode node) {
530         // add a new invoke
531     }
532 
533     protected void addFieldInitialization(ClassNode node) {
534         for (Iterator iter = node.getDeclaredConstructors().iterator(); iter.hasNext();) {
535             addFieldInitialization(node, (ConstructorNode) iter.next());
536         }
537     }
538 
539     protected void addFieldInitialization(ClassNode node, ConstructorNode constructorNode) {
540         List statements = new ArrayList();
541         List staticStatements = new ArrayList();
542         for (Iterator iter = node.getFields().iterator(); iter.hasNext();) {
543             addFieldInitialization(statements, staticStatements, constructorNode, (FieldNode) iter.next());
544         }
545         if (!statements.isEmpty()) {
546             Statement code = constructorNode.getCode();
547             List otherStatements = new ArrayList();
548             if (code instanceof BlockStatement) {
549                 BlockStatement block = (BlockStatement) code;
550                 otherStatements.addAll(block.getStatements());
551             }
552             else if (code != null) {
553                 otherStatements.add(code);
554             }
555             if (!otherStatements.isEmpty()) {
556                 Statement first = (Statement) otherStatements.get(0);
557                 if (isSuperMethodCall(first)) {
558                     otherStatements.remove(0);
559                     statements.add(0, first);
560                 }
561                 statements.addAll(otherStatements);
562             }
563             constructorNode.setCode(new BlockStatement(statements));
564         }
565 
566         if (!staticStatements.isEmpty()) {
567             node.addStaticInitializerStatements(staticStatements);
568         }
569     }
570 
571     protected void addFieldInitialization(
572         List list,
573         List staticList,
574         ConstructorNode constructorNode,
575         FieldNode fieldNode) {
576         Expression expression = fieldNode.getInitialValueExpression();
577         if (expression != null) {
578             ExpressionStatement statement =
579                 new ExpressionStatement(
580                     new BinaryExpression(
581                         new FieldExpression(fieldNode),
582                         Token.newSymbol(Types.EQUAL, fieldNode.getLineNumber(), fieldNode.getColumnNumber()),
583                         expression));
584             if (fieldNode.isStatic()) {
585                 staticList.add(statement);
586             }
587             else {
588                 list.add(statement);
589             }
590         }
591     }
592 
593     protected boolean isSuperMethodCall(Statement first) {
594         if (first instanceof ExpressionStatement) {
595             ExpressionStatement exprStmt = (ExpressionStatement) first;
596             Expression expr = exprStmt.getExpression();
597             if (expr instanceof MethodCallExpression) {
598                 return MethodCallExpression.isSuperMethodCall((MethodCallExpression) expr);
599             }
600         }
601         return false;
602     }
603 
604     /***
605      * Capitalizes the start of the given bean property name
606      */
607     public static String capitalize(String name) {
608         return name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
609     }
610 
611     protected Statement createGetterBlock(PropertyNode propertyNode, FieldNode field) {
612         Expression expression = new FieldExpression(field);
613         return new ReturnStatement(expression);
614     }
615 
616     protected Statement createSetterBlock(PropertyNode propertyNode, FieldNode field) {
617         Expression expression = new FieldExpression(field);
618         return new ExpressionStatement(
619             new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("value")));
620     }
621 
622     /***
623      * Filters the given statements
624      */
625     protected List filterStatements(List list) {
626         List answer = new ArrayList(list.size());
627         for (Iterator iter = list.iterator(); iter.hasNext();) {
628             answer.add(filterStatement((Statement) iter.next()));
629         }
630         return answer;
631     }
632 
633     protected Statement filterStatement(Statement statement) {
634         if (statement instanceof ExpressionStatement) {
635             ExpressionStatement expStmt = (ExpressionStatement) statement;
636             Expression expression = expStmt.getExpression();
637             if (expression instanceof ClosureExpression) {
638                 ClosureExpression closureExp = (ClosureExpression) expression;
639                 if (!closureExp.isParameterSpecified()) {
640                     return closureExp.getCode();
641                 }
642             }
643         }
644         return statement;
645     }
646 }