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;
 }
示例#5
0
  /**
   * 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;
  }