public void visitClosureExpression(ClosureExpression expression) { pushState(); expression.setVariableScope(currentScope); if (expression.isParameterSpecified()) { Parameter[] parameters = expression.getParameters(); for (Parameter parameter : parameters) { parameter.setInStaticContext(currentScope.isInStaticContext()); if (parameter.hasInitialExpression()) { parameter.getInitialExpression().visit(this); } declare(parameter, expression); } } else if (expression.getParameters() != null) { Parameter var = new Parameter(ClassHelper.OBJECT_TYPE, "it"); var.setInStaticContext(currentScope.isInStaticContext()); currentScope.putDeclaredVariable(var); } super.visitClosureExpression(expression); markClosureSharedVariables(); popState(); }
@NotNull private ClosureExpression createGroovyTruthClosureExpression(VariableScope scope) { ClosureExpression result = new ClosureExpression(params(param(OBJECT_TYPE, "it")), returnS(varX("it"))); result.setVariableScope(scope.copy()); return result; }
private List<PropertyNode> findTags(ClassNode classNode) { List<PropertyNode> tags = new ArrayList<PropertyNode>(); List<PropertyNode> properties = classNode.getProperties(); List<PropertyNode> potentialAliases = new ArrayList<PropertyNode>(); for (PropertyNode property : properties) { if (property.isPublic()) { Expression initialExpression = property.getInitialExpression(); if (initialExpression instanceof ClosureExpression) { ClosureExpression ce = (ClosureExpression) initialExpression; Parameter[] parameters = ce.getParameters(); if (parameters.length <= 2) { tags.add(property); // force Closure type for DefaultGrailsTagLibClass property.setType(CLOSURE_CLASS_NODE); } } else if (initialExpression instanceof VariableExpression) { potentialAliases.add(property); } } } for (PropertyNode potentialAlias : potentialAliases) { VariableExpression pe = (VariableExpression) potentialAlias.getInitialExpression(); String propertyName = pe.getName(); PropertyNode property = classNode.getProperty(propertyName); if (property != null && tags.contains(property)) { potentialAlias.setType(CLOSURE_CLASS_NODE); tags.add(potentialAlias); } } return tags; }
@Override protected ClassNode createClosureClass(final ClosureExpression expression, final int mods) { ClassNode closureClass = super.createClosureClass(expression, mods); List<MethodNode> methods = closureClass.getDeclaredMethods("call"); List<MethodNode> doCall = closureClass.getMethods("doCall"); if (doCall.size() != 1) { throw new GroovyBugError( "Expected to find one (1) doCall method on generated closure, but found " + doCall.size()); } MethodNode doCallMethod = doCall.get(0); if (methods.isEmpty() && doCallMethod.getParameters().length == 1) { createDirectCallMethod(closureClass, doCallMethod); } MethodTargetCompletionVisitor visitor = new MethodTargetCompletionVisitor(doCallMethod); Object dynamic = expression.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION); if (dynamic != null) { doCallMethod.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, dynamic); } for (MethodNode method : methods) { visitor.visitMethod(method); } closureClass.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.TRUE); return closureClass; }
/** * Evaluates a constraints closure and returns metadata about the constraints configured in the * closure. The Map returned has property names as keys and the value associated with each of * those property names is a Map<String, Expression> which has constraint names as keys and the * Expression associated with that constraint as values * * @param closureExpression the closure expression to evaluate * @return the Map as described above */ public static Map<String, Map<String, Expression>> getConstraintMetadata( final ClosureExpression closureExpression) { final List<MethodCallExpression> methodExpressions = new ArrayList<MethodCallExpression>(); final Map<String, Map<String, Expression>> results = new LinkedHashMap<String, Map<String, Expression>>(); final Statement closureCode = closureExpression.getCode(); if (closureCode instanceof BlockStatement) { final List<Statement> closureStatements = ((BlockStatement) closureCode).getStatements(); for (final Statement closureStatement : closureStatements) { if (closureStatement instanceof ExpressionStatement) { final Expression expression = ((ExpressionStatement) closureStatement).getExpression(); if (expression instanceof MethodCallExpression) { methodExpressions.add((MethodCallExpression) expression); } } else if (closureStatement instanceof ReturnStatement) { final ReturnStatement returnStatement = (ReturnStatement) closureStatement; Expression expression = returnStatement.getExpression(); if (expression instanceof MethodCallExpression) { methodExpressions.add((MethodCallExpression) expression); } } for (final MethodCallExpression methodCallExpression : methodExpressions) { final Expression objectExpression = methodCallExpression.getObjectExpression(); if (objectExpression instanceof VariableExpression && "this".equals(((VariableExpression) objectExpression).getName())) { final Expression methodCallArguments = methodCallExpression.getArguments(); if (methodCallArguments instanceof TupleExpression) { final List<Expression> methodCallArgumentExpressions = ((TupleExpression) methodCallArguments).getExpressions(); if (methodCallArgumentExpressions != null && methodCallArgumentExpressions.size() == 1 && methodCallArgumentExpressions.get(0) instanceof NamedArgumentListExpression) { final Map<String, Expression> constraintNameToExpression = new LinkedHashMap<String, Expression>(); final List<MapEntryExpression> mapEntryExpressions = ((NamedArgumentListExpression) methodCallArgumentExpressions.get(0)) .getMapEntryExpressions(); for (final MapEntryExpression mapEntryExpression : mapEntryExpressions) { final Expression keyExpression = mapEntryExpression.getKeyExpression(); if (keyExpression instanceof ConstantExpression) { final Object value = ((ConstantExpression) keyExpression).getValue(); if (value instanceof String) { constraintNameToExpression.put( (String) value, mapEntryExpression.getValueExpression()); } } } results.put(methodCallExpression.getMethodAsString(), constraintNameToExpression); } } } } } } return results; }
protected Expression transformClosureExpression(ClosureExpression ce) { boolean oldInClosure = inClosure; inClosure = true; Statement code = ce.getCode(); if (code != null) code.visit(this); inClosure = oldInClosure; return ce; }
protected Parameter[] getClosureSharedVariables(ClosureExpression ce) { VariableScope scope = ce.getVariableScope(); Parameter[] ret = new Parameter[scope.getReferencedLocalVariablesCount()]; int index = 0; for (Iterator iter = scope.getReferencedLocalVariablesIterator(); iter.hasNext(); ) { Variable element = (org.codehaus.groovy.ast.Variable) iter.next(); Parameter p = new Parameter(element.getType(), element.getName()); p.setOriginType(element.getOriginType()); p.setClosureSharedVariable(element.isClosureSharedVariable()); ret[index] = p; index++; } return ret; }
@Override public void visitClosureExpression(ClosureExpression expression) { // LOG.debug "Transforming expression '${expression}':" if (expression.getLineNumber() >= 0 && expression.getLineNumber() < lineNumbers.length) { // LOG.debug " start from ${expression.lineNumber} to ${lineNumbers[expression.lineNumber // - 1]}" expression.setLineNumber(lineNumbers[expression.getLineNumber() - 1]); } if (expression.getLastLineNumber() > 0 && expression.getLastLineNumber() < lineNumbers.length) { // LOG.debug " end from ${expression.lastLineNumber} to // ${lineNumbers[expression.lastLineNumber - 1]}" expression.setLastLineNumber(lineNumbers[expression.getLastLineNumber() - 1]); } super.visitClosureExpression(expression); }
public void visitClosureExpression(ClosureExpression expression) { expression.getCode().visit(this); }
protected ClassNode createClosureClass(ClosureExpression expression, int mods) { ClassNode classNode = controller.getClassNode(); ClassNode outerClass = controller.getOutermostClass(); MethodNode methodNode = controller.getMethodNode(); String name = classNode.getName() + "$" + controller .getContext() .getNextClosureInnerName( outerClass, classNode, methodNode); // add a more informative name boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass(); Parameter[] parameters = expression.getParameters(); if (parameters == null) { parameters = Parameter.EMPTY_ARRAY; } else if (parameters.length == 0) { // let's create a default 'it' parameter Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL); parameters = new Parameter[] {it}; Variable ref = expression.getVariableScope().getDeclaredVariable("it"); if (ref != null) it.setClosureSharedVariable(ref.isClosureSharedVariable()); } Parameter[] localVariableParams = getClosureSharedVariables(expression); removeInitialValues(localVariableParams); InnerClassNode answer = new InnerClassNode(classNode, name, mods, ClassHelper.CLOSURE_TYPE.getPlainNodeReference()); answer.setEnclosingMethod(controller.getMethodNode()); answer.setSynthetic(true); answer.setUsingGenerics(outerClass.isUsingGenerics()); answer.setSourcePosition(expression); if (staticMethodOrInStaticClass) { answer.setStaticClass(true); } if (controller.isInScriptBody()) { answer.setScriptBody(true); } MethodNode method = answer.addMethod( "doCall", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, expression.getCode()); method.setSourcePosition(expression); VariableScope varScope = expression.getVariableScope(); if (varScope == null) { throw new RuntimeException( "Must have a VariableScope by now! for expression: " + expression + " class: " + name); } else { method.setVariableScope(varScope.copy()); } if (parameters.length > 1 || (parameters.length == 1 && parameters[0].getType() != null && parameters[0].getType() != ClassHelper.OBJECT_TYPE && !ClassHelper.OBJECT_TYPE.equals(parameters[0].getType().getComponentType()))) { // let's add a typesafe call method MethodNode call = answer.addMethod( "call", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, new ReturnStatement( new MethodCallExpression( VariableExpression.THIS_EXPRESSION, "doCall", new ArgumentListExpression(parameters)))); call.setSourcePosition(expression); } // let's make the constructor BlockStatement block = new BlockStatement(); // this block does not get a source position, because we don't // want this synthetic constructor to show up in corbertura reports VariableExpression outer = new VariableExpression("_outerInstance"); outer.setSourcePosition(expression); block.getVariableScope().putReferencedLocalVariable(outer); VariableExpression thisObject = new VariableExpression("_thisObject"); thisObject.setSourcePosition(expression); block.getVariableScope().putReferencedLocalVariable(thisObject); TupleExpression conArgs = new TupleExpression(outer, thisObject); block.addStatement( new ExpressionStatement(new ConstructorCallExpression(ClassNode.SUPER, conArgs))); // let's assign all the parameter fields from the outer context for (Parameter param : localVariableParams) { String paramName = param.getName(); ClassNode type = param.getType(); if (true) { VariableExpression initialValue = new VariableExpression(paramName); initialValue.setAccessedVariable(param); initialValue.setUseReferenceDirectly(true); ClassNode realType = type; type = ClassHelper.makeReference(); param.setType(ClassHelper.makeReference()); FieldNode paramField = answer.addField(paramName, ACC_PRIVATE | ACC_SYNTHETIC, type, initialValue); paramField.setOriginType(ClassHelper.getWrapper(param.getOriginType())); paramField.setHolder(true); String methodName = Verifier.capitalize(paramName); // let's add a getter & setter Expression fieldExp = new FieldExpression(paramField); answer.addMethod( "get" + methodName, ACC_PUBLIC, realType.getPlainNodeReference(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new ReturnStatement(fieldExp)); } } Parameter[] params = new Parameter[2 + localVariableParams.length]; params[0] = new Parameter(ClassHelper.OBJECT_TYPE, "_outerInstance"); params[1] = new Parameter(ClassHelper.OBJECT_TYPE, "_thisObject"); System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length); ASTNode sn = answer.addConstructor(ACC_PUBLIC, params, ClassNode.EMPTY_ARRAY, block); sn.setSourcePosition(expression); correctAccessedVariable(answer, expression); return answer; }