public void visit(ASTNode[] nodes, SourceUnit source) {
    if (nodes.length != 2
        || !(nodes[0] instanceof AnnotationNode)
        || !(nodes[1] instanceof AnnotatedNode)) {
      throw new RuntimeException(
          "Internal error: expecting [AnnotationNode, AnnotatedNode] but got: "
              + Arrays.asList(nodes));
    }

    AnnotationNode annotationNode = (AnnotationNode) nodes[0];
    ASTNode node = nodes[1];

    if (!(node instanceof MethodNode)) {
      addError("@NotYetImplemented must only be applied on test methods!", node);
      return;
    }

    MethodNode methodNode = (MethodNode) node;

    ArrayList<Statement> statements = new ArrayList<Statement>();
    Statement statement = methodNode.getCode();
    if (statement instanceof BlockStatement) {
      statements.addAll(((BlockStatement) statement).getStatements());
    }

    if (statements.size() == 0) return;

    BlockStatement rewrittenMethodCode = new BlockStatement();

    rewrittenMethodCode.addStatement(
        tryCatchAssertionFailedError(annotationNode, methodNode, statements));
    rewrittenMethodCode.addStatement(throwAssertionFailedError(annotationNode));

    methodNode.setCode(rewrittenMethodCode);
  }
 private Statement getMethodBody(MethodNode methodNode) {
   Statement code = methodNode.getCode();
   if (!(code instanceof BlockStatement)) {
     BlockStatement body = new BlockStatement();
     body.addStatement(code);
     code = body;
   }
   return code;
 }
  private void validateFields(BlockStatement block) {
    Validation.Option mode =
        getEnumMemberValue(
            getAnnotation(annotatedClass, VALIDATION_ANNOTATION),
            "option",
            Validation.Option.class,
            Validation.Option.IGNORE_UNMARKED);
    for (FieldNode fieldNode : annotatedClass.getFields()) {
      if (shouldFieldBeIgnoredForValidation(fieldNode)) continue;

      ClosureExpression validationClosure =
          createGroovyTruthClosureExpression(block.getVariableScope());
      String message = null;

      AnnotationNode validateAnnotation = getAnnotation(fieldNode, VALIDATE_ANNOTATION);
      if (validateAnnotation != null) {
        message =
            getMemberStringValue(
                validateAnnotation, "message", "'" + fieldNode.getName() + "' must be set!");
        Expression member = validateAnnotation.getMember("value");
        if (member instanceof ClassExpression) {
          ClassNode memberType = member.getType();
          if (memberType.equals(ClassHelper.make(Validate.Ignore.class))) continue;
          else if (!memberType.equals(ClassHelper.make(Validate.GroovyTruth.class))) {
            addError(
                "value of Validate must be either Validate.GroovyTruth, Validate.Ignore or a closure.",
                fieldNode);
          }
        } else if (member instanceof ClosureExpression) {
          validationClosure = (ClosureExpression) member;
        }
      }

      if (validateAnnotation != null || mode == Validation.Option.VALIDATE_UNMARKED) {
        block.addStatement(
            new AssertStatement(
                new BooleanExpression(
                    callX(validationClosure, "call", args(varX(fieldNode.getName())))),
                message == null ? ConstantExpression.NULL : new ConstantExpression(message)));
      }
    }
  }
 protected void addMockCollaborator(
     String mockType, ClassExpression targetClass, BlockStatement methodBody) {
   ArgumentListExpression args = new ArgumentListExpression();
   args.addExpression(targetClass);
   methodBody
       .getStatements()
       .add(
           0,
           new ExpressionStatement(
               new MethodCallExpression(THIS_EXPRESSION, "mock" + mockType, args)));
 }
  private IfStatement getAutowiringIfStatement(
      ClassExpression targetClass,
      VariableExpression fieldExpression,
      BinaryExpression testTargetAssignment) {
    VariableExpression appCtxVar = new VariableExpression("applicationContext");

    BooleanExpression applicationContextCheck =
        new BooleanExpression(
            new BinaryExpression(
                new BinaryExpression(
                    fieldExpression,
                    GrailsASTUtils.EQUALS_OPERATOR,
                    GrailsASTUtils.NULL_EXPRESSION),
                Token.newSymbol("&&", 0, 0),
                new BinaryExpression(
                    appCtxVar,
                    GrailsASTUtils.NOT_EQUALS_OPERATOR,
                    GrailsASTUtils.NULL_EXPRESSION)));
    BlockStatement performAutowireBlock = new BlockStatement();
    ArgumentListExpression arguments = new ArgumentListExpression();
    arguments.addExpression(fieldExpression);
    arguments.addExpression(new ConstantExpression(1));
    arguments.addExpression(new ConstantExpression(false));
    BlockStatement assignFromApplicationContext = new BlockStatement();
    ArgumentListExpression argWithClassName = new ArgumentListExpression();
    MethodCallExpression getClassNameMethodCall =
        new MethodCallExpression(targetClass, "getName", new ArgumentListExpression());
    argWithClassName.addExpression(getClassNameMethodCall);

    assignFromApplicationContext.addStatement(
        new ExpressionStatement(
            new BinaryExpression(
                fieldExpression,
                ASSIGN,
                new MethodCallExpression(appCtxVar, "getBean", argWithClassName))));
    BlockStatement elseBlock = new BlockStatement();
    elseBlock.addStatement(new ExpressionStatement(testTargetAssignment));
    performAutowireBlock.addStatement(
        new IfStatement(
            new BooleanExpression(
                new MethodCallExpression(appCtxVar, "containsBean", argWithClassName)),
            assignFromApplicationContext,
            elseBlock));
    performAutowireBlock.addStatement(
        new ExpressionStatement(
            new MethodCallExpression(
                new PropertyExpression(appCtxVar, "autowireCapableBeanFactory"),
                "autowireBeanProperties",
                arguments)));
    return new IfStatement(applicationContextCheck, performAutowireBlock, new BlockStatement());
  }
  protected MethodNode addClassUnderTestMethod(
      ClassNode classNode, ClassExpression targetClass, String type) {

    String methodName = "setup" + type + "UnderTest";
    String fieldName = GrailsNameUtils.getPropertyName(type);
    String getterName = GrailsNameUtils.getGetterName(fieldName);
    fieldName = '$' + fieldName;

    if (classNode.getField(fieldName) == null) {
      classNode.addField(fieldName, Modifier.PRIVATE, targetClass.getType(), null);
    }

    MethodNode methodNode =
        classNode.getMethod(methodName, GrailsArtefactClassInjector.ZERO_PARAMETERS);

    VariableExpression fieldExpression = new VariableExpression(fieldName);
    if (methodNode == null) {
      BlockStatement setupMethodBody = new BlockStatement();
      addMockCollaborator(type, targetClass, setupMethodBody);

      methodNode =
          new MethodNode(
              methodName,
              Modifier.PUBLIC,
              ClassHelper.VOID_TYPE,
              GrailsArtefactClassInjector.ZERO_PARAMETERS,
              null,
              setupMethodBody);
      methodNode.addAnnotation(BEFORE_ANNOTATION);
      methodNode.addAnnotation(MIXIN_METHOD_ANNOTATION);
      classNode.addMethod(methodNode);
    }

    MethodNode getter =
        classNode.getMethod(getterName, GrailsArtefactClassInjector.ZERO_PARAMETERS);
    if (getter == null) {
      BlockStatement getterBody = new BlockStatement();
      getter =
          new MethodNode(
              getterName,
              Modifier.PUBLIC,
              targetClass.getType().getPlainNodeReference(),
              GrailsArtefactClassInjector.ZERO_PARAMETERS,
              null,
              getterBody);

      BinaryExpression testTargetAssignment =
          new BinaryExpression(
              fieldExpression,
              ASSIGN,
              new ConstructorCallExpression(
                  targetClass.getType(), GrailsArtefactClassInjector.ZERO_ARGS));

      IfStatement autowiringIfStatement =
          getAutowiringIfStatement(targetClass, fieldExpression, testTargetAssignment);
      getterBody.addStatement(autowiringIfStatement);

      getterBody.addStatement(new ReturnStatement(fieldExpression));
      classNode.addMethod(getter);
    }

    return methodNode;
  }
  private void validateCustomMethods(BlockStatement block) {
    if (!annotatedClass.hasMethod("doValidate", Parameter.EMPTY_ARRAY)) return;

    block.addStatement(stmt(callX(varX("this"), "doValidate")));
  }