protected MethodNode weaveMock(
      ClassNode classNode, ClassExpression value, boolean isClassUnderTest) {

    ClassNode testTarget = value.getType();
    String className = testTarget.getName();
    MethodNode testForMethod = null;
    for (String artefactType : artefactTypeToTestMap.keySet()) {
      if (className.endsWith(artefactType)) {
        Class mixinClass = artefactTypeToTestMap.get(artefactType);
        if (!isAlreadyWoven(classNode, mixinClass)) {
          weaveMixinClass(classNode, mixinClass);
          if (isClassUnderTest) {
            testForMethod = addClassUnderTestMethod(classNode, value, artefactType);
          } else {
            addMockCollaboratorToSetup(classNode, value, artefactType);
          }
          return testForMethod;
        }

        addMockCollaboratorToSetup(classNode, value, artefactType);
        return null;
      }
    }

    // must be a domain class
    weaveMixinClass(classNode, DomainClassUnitTestMixin.class);
    if (isClassUnderTest) {
      testForMethod = addClassUnderTestMethod(classNode, value, DOMAIN_TYPE);
    } else {
      addMockCollaboratorToSetup(classNode, value, DOMAIN_TYPE);
    }

    return testForMethod;
  }
  private Expression transformInlineConstants(Expression exp) {
    if (exp instanceof PropertyExpression) {
      PropertyExpression pe = (PropertyExpression) exp;
      if (pe.getObjectExpression() instanceof ClassExpression) {
        ClassExpression ce = (ClassExpression) pe.getObjectExpression();
        ClassNode type = ce.getType();
        if (type.isEnum()) return exp;
        Expression constant = findConstant(type.getField(pe.getPropertyAsString()));
        // GRECLIPSE edit
        // if (constant != null) return constant;
        if (constant != null) {
          String name = pe.getText().replace('$', '.');
          Object alias = pe.getNodeMetaData("static.import.alias");
          if (alias != null && !alias.equals(pe.getPropertyAsString())) {
            name += " as " + alias;
          }
          // store the qualified name to facilitate organizing static imports
          constant.setNodeMetaData("static.import", name);

          return constant;
        }
        // GRECLIPSE end
      }
    } else if (exp instanceof ListExpression) {
      ListExpression le = (ListExpression) exp;
      ListExpression result = new ListExpression();
      for (Expression e : le.getExpressions()) {
        result.addExpression(transformInlineConstants(e));
      }
      return result;
    }

    return exp;
  }
  private static boolean hasClosureMember(AnnotationNode annotation) {

    Map<String, Expression> members = annotation.getMembers();
    for (Map.Entry<String, Expression> member : members.entrySet()) {
      if (member.getValue() instanceof ClosureExpression) return true;

      if (member.getValue() instanceof ClassExpression) {
        ClassExpression classExpression = (ClassExpression) member.getValue();
        Class<?> typeClass =
            classExpression.getType().isResolved()
                ? classExpression.getType().redirect().getTypeClass()
                : null;
        if (typeClass != null && GeneratedClosure.class.isAssignableFrom(typeClass)) return true;
      }
    }

    return false;
  }
  private void evaluateInstanceof(BinaryExpression expression) {
    OperandStack operandStack = controller.getOperandStack();

    expression.getLeftExpression().visit(controller.getAcg());
    operandStack.box();
    Expression rightExp = expression.getRightExpression();
    ClassNode classType;
    if (rightExp instanceof ClassExpression) {
      ClassExpression classExp = (ClassExpression) rightExp;
      classType = classExp.getType();
    } else {
      throw new RuntimeException(
          "Right hand side of the instanceof keyword must be a class name, not: " + rightExp);
    }
    String classInternalName = BytecodeHelper.getClassInternalName(classType);
    controller.getMethodVisitor().visitTypeInsn(INSTANCEOF, classInternalName);
    operandStack.replace(ClassHelper.boolean_TYPE);
  }
  private Expression transformInlineConstants(Expression exp) {
    if (exp instanceof PropertyExpression) {
      PropertyExpression pe = (PropertyExpression) exp;
      if (pe.getObjectExpression() instanceof ClassExpression) {
        ClassExpression ce = (ClassExpression) pe.getObjectExpression();
        ClassNode type = ce.getType();
        if (type.isEnum()) return exp;
        Expression constant = findConstant(type.getField(pe.getPropertyAsString()));
        if (constant != null) return constant;
      }
    } else if (exp instanceof ListExpression) {
      ListExpression le = (ListExpression) exp;
      ListExpression result = new ListExpression();
      for (Expression e : le.getExpressions()) {
        result.addExpression(transformInlineConstants(e));
      }
      return result;
    }

    return exp;
  }
 private groovy.transform.PackageScopeTarget extractTarget(PropertyExpression expr) {
   Expression oe = expr.getObjectExpression();
   if (oe instanceof ClassExpression) {
     ClassExpression ce = (ClassExpression) oe;
     if (ce.getType().getName().equals("groovy.transform.PackageScopeTarget")) {
       Expression prop = expr.getProperty();
       if (prop instanceof ConstantExpression) {
         String propName = (String) ((ConstantExpression) prop).getValue();
         try {
           return PackageScopeTarget.valueOf(propName);
         } catch (IllegalArgumentException iae) {
           /* ignore */
         }
       }
     }
   }
   throw new RuntimeException(
       "Internal error during "
           + MY_TYPE_NAME
           + " processing. Annotation parameters must be of type: "
           + TARGET_CLASS_NAME
           + ".");
 }
  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;
  }