1 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.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.expr.ArgumentListExpression; 67 import org.codehaus.groovy.ast.expr.BinaryExpression; 68 import org.codehaus.groovy.ast.expr.BooleanExpression; 69 import org.codehaus.groovy.ast.expr.ClosureExpression; 70 import org.codehaus.groovy.ast.expr.ConstantExpression; 71 import org.codehaus.groovy.ast.expr.Expression; 72 import org.codehaus.groovy.ast.expr.FieldExpression; 73 import org.codehaus.groovy.ast.expr.MethodCallExpression; 74 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression; 75 import org.codehaus.groovy.ast.expr.VariableExpression; 76 import org.codehaus.groovy.ast.stmt.BlockStatement; 77 import org.codehaus.groovy.ast.stmt.EmptyStatement; 78 import org.codehaus.groovy.ast.stmt.ExpressionStatement; 79 import org.codehaus.groovy.ast.stmt.IfStatement; 80 import org.codehaus.groovy.ast.stmt.ReturnStatement; 81 import org.codehaus.groovy.ast.stmt.Statement; 82 import org.codehaus.groovy.runtime.InvokerHelper; 83 import org.codehaus.groovy.syntax.Types; 84 import org.codehaus.groovy.syntax.Token; 85 import org.codehaus.groovy.syntax.parser.RuntimeParserException; 86 import org.objectweb.asm.Constants; 87 88 95 public class Verifier implements GroovyClassVisitor, Constants { 96 97 public static final String __TIMESTAMP = "__timeStamp"; 98 private ClassNode classNode; 99 private MethodNode methodNode; 100 101 public ClassNode getClassNode() { 102 return classNode; 103 } 104 105 public MethodNode getMethodNode() { 106 return methodNode; 107 } 108 109 113 public void visitClass(ClassNode node) { 114 this.classNode = node; 115 116 addDefaultParameterMethods(node); 117 118 if (!node.isDerivedFromGroovyObject()) { 119 node.addInterface(GroovyObject.class.getName()); 120 121 StaticMethodCallExpression initMetaClassCall = 123 new StaticMethodCallExpression( 124 InvokerHelper.class.getName(), 125 "getMetaClass", 126 VariableExpression.THIS_EXPRESSION); 127 128 PropertyNode metaClassProperty = 129 node.addProperty("metaClass", ACC_PUBLIC, MetaClass.class.getName(), initMetaClassCall, null, null); 130 metaClassProperty.setSynthetic(true); 131 FieldNode metaClassField = metaClassProperty.getField(); 132 metaClassField.setModifiers(metaClassField.getModifiers() | ACC_TRANSIENT); 133 134 FieldExpression metaClassVar = new FieldExpression(metaClassField); 135 IfStatement initMetaClassField = 136 new IfStatement( 137 new BooleanExpression( 138 new BinaryExpression(metaClassVar, Token.newSymbol( Types.COMPARE_EQUAL, -1, -1), ConstantExpression.NULL)), 139 new ExpressionStatement(new BinaryExpression(metaClassVar, Token.newSymbol( Types.EQUAL, -1, -1), initMetaClassCall)), 140 EmptyStatement.INSTANCE); 141 142 node.addSyntheticMethod( 143 "getMetaClass", 144 ACC_PUBLIC, 145 MetaClass.class.getName(), 146 Parameter.EMPTY_ARRAY, 147 new BlockStatement(new Statement[] { initMetaClassField, new ReturnStatement(metaClassVar)})); 148 149 151 String superClass = node.getSuperClass(); 153 boolean addDelegateObject = 154 (node instanceof InnerClassNode && superClass.equals(Closure.class.getName())) 155 || superClass.equals(GString.class.getName()); 156 157 if (!addDelegateObject) { 159 node.addSyntheticMethod( 160 "invokeMethod", 161 ACC_PUBLIC, 162 Object .class.getName(), 163 new Parameter[] { 164 new Parameter(String .class.getName(), "method"), 165 new Parameter(Object .class.getName(), "arguments")}, 166 new BlockStatement( 167 new Statement[] { 168 initMetaClassField, 169 new ReturnStatement( 170 new MethodCallExpression( 171 metaClassVar, 172 "invokeMethod", 173 new ArgumentListExpression( 174 new Expression[] { 175 VariableExpression.THIS_EXPRESSION, 176 new VariableExpression("method"), 177 new VariableExpression("arguments")}))) 178 })); 179 180 if (!node.isScript()) { 181 node.addSyntheticMethod( 182 "getProperty", 183 ACC_PUBLIC, 184 Object .class.getName(), 185 new Parameter[] { new Parameter(String .class.getName(), "property")}, 186 new BlockStatement( 187 new Statement[] { 188 initMetaClassField, 189 new ReturnStatement( 190 new MethodCallExpression( 191 metaClassVar, 192 "getProperty", 193 new ArgumentListExpression( 194 new Expression[] { 195 VariableExpression.THIS_EXPRESSION, 196 new VariableExpression("property")}))) 197 })); 198 199 node.addSyntheticMethod( 200 "setProperty", 201 ACC_PUBLIC, 202 "void", 203 new Parameter[] { 204 new Parameter(String .class.getName(), "property"), 205 new Parameter(Object .class.getName(), "value")}, 206 new BlockStatement( 207 new Statement[] { 208 initMetaClassField, 209 new ExpressionStatement( 210 new MethodCallExpression( 211 metaClassVar, 212 "setProperty", 213 new ArgumentListExpression( 214 new Expression[] { 215 VariableExpression.THIS_EXPRESSION, 216 new VariableExpression("property"), 217 new VariableExpression("value")}))) 218 })); 219 } 220 } 221 } 222 223 if (node.getDeclaredConstructors().isEmpty()) { 224 ConstructorNode constructor = new ConstructorNode(ACC_PUBLIC, null); 225 constructor.setSynthetic(true); 226 node.addConstructor(constructor); 227 } 228 229 if (!(node instanceof InnerClassNode)) { FieldNode timeTagField = new FieldNode( 231 Verifier.__TIMESTAMP, 232 Modifier.PUBLIC | Modifier.STATIC, 233 "java.lang.Long", 234 node.getName(), 236 new ConstantExpression(new Long (System.currentTimeMillis()))); 237 timeTagField.setSynthetic(true); 239 node.addField(timeTagField); 240 } 241 242 addFieldInitialization(node); 243 244 node.visitContents(this); 245 } 246 247 public void visitConstructor(ConstructorNode node) { 248 } 249 250 public void visitMethod(MethodNode node) { 251 this.methodNode = node; 252 253 Statement statement = node.getCode(); 254 if (!node.isVoidMethod()) { 255 if (statement instanceof ExpressionStatement) { 256 ExpressionStatement expStmt = (ExpressionStatement) statement; 257 node.setCode(new ReturnStatement(expStmt.getExpression())); 258 } 259 else if (statement instanceof BlockStatement) { 260 BlockStatement block = (BlockStatement) statement; 261 262 List list = new ArrayList (block.getStatements()); 264 if (!list.isEmpty()) { 265 int idx = list.size() - 1; 266 Statement last = (Statement) list.get(idx); 267 if (last instanceof ExpressionStatement) { 268 ExpressionStatement expStmt = (ExpressionStatement) last; 269 list.set(idx, new ReturnStatement(expStmt.getExpression())); 270 } 271 else if (!(last instanceof ReturnStatement)) { 272 list.add(new ReturnStatement(ConstantExpression.NULL)); 273 } 274 } 275 else { 276 list.add(new ReturnStatement(ConstantExpression.NULL)); 277 } 278 279 node.setCode(new BlockStatement(filterStatements(list))); 280 } 281 } 282 else { 283 BlockStatement newBlock = new BlockStatement(); 284 if (statement instanceof BlockStatement) { 285 newBlock.addStatements(filterStatements(((BlockStatement)statement).getStatements())); 286 } 287 else { 288 newBlock.addStatement(filterStatement(statement)); 289 } 290 newBlock.addStatement(ReturnStatement.RETURN_NULL_OR_VOID); 291 node.setCode(newBlock); 292 } 293 if (node.getName().equals("main") && node.isStatic()) { 294 Parameter[] params = node.getParameters(); 295 if (params.length == 1) { 296 Parameter param = params[0]; 297 if (param.getType() == null || param.getType().equals("java.lang.Object")) { 298 param.setType("java.lang.String[]"); 299 } 300 } 301 } 302 node.getCode().visit(new VerifierCodeVisitor(this)); 303 } 304 305 public void visitField(FieldNode node) { 306 } 307 308 public void visitProperty(PropertyNode node) { 309 String name = node.getName(); 310 FieldNode field = node.getField(); 311 312 313 String getterPrefix = "get"; 314 if ("boolean".equals(node.getType())) { 315 getterPrefix = "is"; 316 } 317 String getterName = getterPrefix + capitalize(name); 318 String setterName = "set" + capitalize(name); 319 320 Statement getterBlock = node.getGetterBlock(); 321 if (getterBlock == null) { 322 if (!node.isPrivate() && classNode.getGetterMethod(getterName) == null) { 323 getterBlock = createGetterBlock(node, field); 324 } 325 } 326 Statement setterBlock = node.getGetterBlock(); 327 if (setterBlock == null) { 328 if (!node.isPrivate() && classNode.getSetterMethod(setterName) == null) { 329 setterBlock = createSetterBlock(node, field); 330 } 331 } 332 333 if (getterBlock != null) { 334 MethodNode getter = 335 new MethodNode(getterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, getterBlock); 336 getter.setSynthetic(true); 337 classNode.addMethod(getter); 338 visitMethod(getter); 339 340 if ("java.lang.Boolean".equals(node.getType())) { 341 String secondGetterName = "is" + capitalize(name); 342 MethodNode secondGetter = 343 new MethodNode(secondGetterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, getterBlock); 344 secondGetter.setSynthetic(true); 345 classNode.addMethod(secondGetter); 346 visitMethod(secondGetter); 347 } 348 } 349 if (setterBlock != null) { 350 Parameter[] setterParameterTypes = { new Parameter(node.getType(), "value")}; 351 MethodNode setter = 352 new MethodNode(setterName, node.getModifiers(), "void", setterParameterTypes, setterBlock); 353 setter.setSynthetic(true); 354 classNode.addMethod(setter); 355 visitMethod(setter); 356 } 357 } 358 359 362 365 protected void addDefaultParameterMethods(ClassNode node) { 366 List methods = new ArrayList (node.getMethods()); 367 for (Iterator iter = methods.iterator(); iter.hasNext();) { 368 MethodNode method = (MethodNode) iter.next(); 369 Parameter[] parameters = method.getParameters(); 370 int size = parameters.length; 371 for (int i = 0; i < size; i++) { 372 Parameter parameter = parameters[i]; 373 Expression exp = parameter.getDefaultValue(); 374 if (exp != null) { 375 addDefaultParameterMethod(node, method, parameters, i); 376 } 377 } 378 } 379 } 380 381 390 protected void addDefaultParameterMethod(ClassNode node, MethodNode method, Parameter[] parameters, int index) { 391 Parameter[] newParams = new Parameter[index]; 393 System.arraycopy(parameters, 0, newParams, 0, index); 394 395 ArgumentListExpression arguments = new ArgumentListExpression(); 396 int size = parameters.length; 397 for (int i = 0; i < size; i++) { 398 if (i < index) { 399 arguments.addExpression(new VariableExpression(parameters[i].getName())); 400 } 401 else { 402 Expression defaultValue = parameters[i].getDefaultValue(); 403 if (defaultValue == null) { 404 throw new RuntimeParserException( 405 "The " + parameters[i].getName() + " parameter must have a default value", 406 method); 407 } 408 else { 409 arguments.addExpression(defaultValue); 410 } 411 } 412 } 413 414 MethodCallExpression expression = 415 new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments); 416 Statement code = null; 417 if (method.isVoidMethod()) { 418 code = new ExpressionStatement(expression); 419 } 420 else { 421 code = new ReturnStatement(expression); 422 } 423 424 node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, code); 425 } 426 427 protected void addClosureCode(InnerClassNode node) { 428 } 430 431 protected void addFieldInitialization(ClassNode node) { 432 for (Iterator iter = node.getDeclaredConstructors().iterator(); iter.hasNext();) { 433 addFieldInitialization(node, (ConstructorNode) iter.next()); 434 } 435 } 436 437 protected void addFieldInitialization(ClassNode node, ConstructorNode constructorNode) { 438 List statements = new ArrayList (); 439 List staticStatements = new ArrayList (); 440 for (Iterator iter = node.getFields().iterator(); iter.hasNext();) { 441 addFieldInitialization(statements, staticStatements, constructorNode, (FieldNode) iter.next()); 442 } 443 if (!statements.isEmpty()) { 444 Statement code = constructorNode.getCode(); 445 List otherStatements = new ArrayList (); 446 if (code instanceof BlockStatement) { 447 BlockStatement block = (BlockStatement) code; 448 otherStatements.addAll(block.getStatements()); 449 } 450 else if (code != null) { 451 otherStatements.add(code); 452 } 453 if (!otherStatements.isEmpty()) { 454 Statement first = (Statement) otherStatements.get(0); 455 if (isSuperMethodCall(first)) { 456 otherStatements.remove(0); 457 statements.add(0, first); 458 } 459 statements.addAll(otherStatements); 460 } 461 constructorNode.setCode(new BlockStatement(statements)); 462 } 463 464 if (!staticStatements.isEmpty()) { 465 node.addStaticInitializerStatements(staticStatements); 466 } 467 } 468 469 protected void addFieldInitialization( 470 List list, 471 List staticList, 472 ConstructorNode constructorNode, 473 FieldNode fieldNode) { 474 Expression expression = fieldNode.getInitialValueExpression(); 475 if (expression != null) { 476 ExpressionStatement statement = 477 new ExpressionStatement( 478 new BinaryExpression( 479 new FieldExpression(fieldNode), 480 Token.newSymbol(Types.EQUAL, fieldNode.getLineNumber(), fieldNode.getColumnNumber()), 481 expression)); 482 if (fieldNode.isStatic()) { 483 staticList.add(statement); 484 } 485 else { 486 list.add(statement); 487 } 488 } 489 } 490 491 protected boolean isSuperMethodCall(Statement first) { 492 if (first instanceof ExpressionStatement) { 493 ExpressionStatement exprStmt = (ExpressionStatement) first; 494 Expression expr = exprStmt.getExpression(); 495 if (expr instanceof MethodCallExpression) { 496 return MethodCallExpression.isSuperMethodCall((MethodCallExpression) expr); 497 } 498 } 499 return false; 500 } 501 502 505 public static String capitalize(String name) { 506 return name.substring(0, 1).toUpperCase() + name.substring(1, name.length()); 507 } 508 509 protected Statement createGetterBlock(PropertyNode propertyNode, FieldNode field) { 510 Expression expression = new FieldExpression(field); 511 return new ReturnStatement(expression); 512 } 513 514 protected Statement createSetterBlock(PropertyNode propertyNode, FieldNode field) { 515 Expression expression = new FieldExpression(field); 516 return new ExpressionStatement( 517 new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("value"))); 518 } 519 520 523 protected List filterStatements(List list) { 524 List answer = new ArrayList (list.size()); 525 for (Iterator iter = list.iterator(); iter.hasNext();) { 526 answer.add(filterStatement((Statement) iter.next())); 527 } 528 return answer; 529 } 530 531 protected Statement filterStatement(Statement statement) { 532 if (statement instanceof ExpressionStatement) { 533 ExpressionStatement expStmt = (ExpressionStatement) statement; 534 Expression expression = expStmt.getExpression(); 535 if (expression instanceof ClosureExpression) { 536 ClosureExpression closureExp = (ClosureExpression) expression; 537 if (!closureExp.isParameterSpecified()) { 538 return closureExp.getCode(); 539 } 540 } 541 } 542 return statement; 543 } 544 } 545 | Popular Tags |