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();
  }
  private void checkVariableContextAccess(Variable v, Expression expr) {
    if (inPropertyExpression || v.isInStaticContext() || !currentScope.isInStaticContext()) return;

    String msg =
        v.getName()
            + " is declared in a dynamic context, but you tried to"
            + " access it from a static context.";
    addError(msg, expr);

    // declare a static variable to be able to continue the check
    DynamicVariable v2 = new DynamicVariable(v.getName(), currentScope.isInStaticContext());
    currentScope.putDeclaredVariable(v2);
  }
 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;
 }
 @NotNull
 private ClosureExpression createGroovyTruthClosureExpression(VariableScope scope) {
   ClosureExpression result =
       new ClosureExpression(params(param(OBJECT_TYPE, "it")), returnS(varX("it")));
   result.setVariableScope(scope.copy());
   return result;
 }
 public void visitCatchStatement(CatchStatement statement) {
   pushState();
   Parameter p = statement.getVariable();
   p.setInStaticContext(currentScope.isInStaticContext());
   declare(p, statement);
   super.visitCatchStatement(statement);
   popState();
 }
 public void visitForLoop(ForStatement forLoop) {
   pushState();
   forLoop.setVariableScope(currentScope);
   Parameter p = forLoop.getVariable();
   p.setInStaticContext(currentScope.isInStaticContext());
   if (p != ForStatement.FOR_LOOP_DUMMY) declare(p, forLoop);
   super.visitForLoop(forLoop);
   popState();
 }
 /**
  * a property on "this", like this.x is transformed to a direct field access, so we need to check
  * the static context here
  *
  * @param pe the property expression to check
  */
 private void checkPropertyOnExplicitThis(PropertyExpression pe) {
   if (!currentScope.isInStaticContext()) return;
   Expression object = pe.getObjectExpression();
   if (!(object instanceof VariableExpression)) return;
   VariableExpression ve = (VariableExpression) object;
   if (!ve.getName().equals("this")) return;
   String name = pe.getPropertyAsString();
   if (name == null || name.equals("class")) return;
   Variable member = findClassMember(currentClass, name);
   if (member == null) return;
   checkVariableContextAccess(member, pe);
 }
  private void declare(Variable var, ASTNode expr) {
    String scopeType = "scope";
    String variableType = "variable";

    if (expr.getClass() == FieldNode.class) {
      scopeType = "class";
      variableType = "field";
    } else if (expr.getClass() == PropertyNode.class) {
      scopeType = "class";
      variableType = "property";
    }

    StringBuilder msg = new StringBuilder();
    msg.append("The current ").append(scopeType);
    msg.append(" already contains a ").append(variableType);
    msg.append(" of the name ").append(var.getName());

    if (currentScope.getDeclaredVariable(var.getName()) != null) {
      addError(msg.toString(), expr);
      return;
    }

    for (VariableScope scope = currentScope.getParent(); scope != null; scope = scope.getParent()) {
      // if we are in a class and no variable is declared until
      // now, then we can break the loop, because we are allowed
      // to declare a variable of the same name as a class member
      if (scope.getClassScope() != null) break;

      if (scope.getDeclaredVariable(var.getName()) != null) {
        // variable already declared
        addError(msg.toString(), expr);
        break;
      }
    }
    // declare the variable even if there was an error to allow more checks
    currentScope.putDeclaredVariable(var);
  }
  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;
  }
 private void declare(VariableExpression vex) {
   vex.setInStaticContext(currentScope.isInStaticContext());
   declare(vex, vex);
   vex.setAccessedVariable(vex);
 }
 private void pushState() {
   pushState(currentScope.isInStaticContext());
 }
 private void pushState(boolean isStatic) {
   stateStack.add(new StateStackElement());
   currentScope = new VariableScope(currentScope);
   currentScope.setInStaticContext(isStatic);
 }
 /**
  * Setup the current class node context.
  *
  * @param node
  */
 public void prepareVisit(ClassNode node) {
   currentClass = node;
   currentScope.setClassScope(node);
 }
 private void markClosureSharedVariables() {
   VariableScope scope = currentScope;
   for (Iterator<Variable> it = scope.getReferencedLocalVariablesIterator(); it.hasNext(); ) {
     it.next().setClosureSharedVariable(true);
   }
 }
  private Variable checkVariableNameForDeclaration(String name, Expression expression) {
    if ("super".equals(name) || "this".equals(name)) return null;

    VariableScope scope = currentScope;
    Variable var = new DynamicVariable(name, currentScope.isInStaticContext());
    // try to find a declaration of a variable
    while (true) {
      Variable var1;
      var1 = scope.getDeclaredVariable(var.getName());

      if (var1 != null) {
        var = var1;
        break;
      }

      var1 = scope.getReferencedLocalVariable(var.getName());
      if (var1 != null) {
        var = var1;
        break;
      }

      var1 = scope.getReferencedClassVariable(var.getName());
      if (var1 != null) {
        var = var1;
        break;
      }

      ClassNode classScope = scope.getClassScope();
      if (classScope != null) {
        Variable member = findClassMember(classScope, var.getName());
        if (member != null) {
          boolean staticScope = currentScope.isInStaticContext() || isSpecialConstructorCall;
          boolean staticMember = member.isInStaticContext();
          // We don't allow a static context (e.g. a static method) to access
          // a non-static variable (e.g. a non-static field).
          if (!(staticScope && !staticMember)) var = member;
        }
        break;
      }
      scope = scope.getParent();
    }

    VariableScope end = scope;

    scope = currentScope;
    while (scope != end) {
      if (end.isClassScope()
          || (end.isReferencedClassVariable(name) && end.getDeclaredVariable(name) == null)) {
        scope.putReferencedClassVariable(var);
      } else {
        // var.setClosureSharedVariable(var.isClosureSharedVariable() || inClosure);
        scope.putReferencedLocalVariable(var);
      }
      scope = scope.getParent();
    }

    return var;
  }