Пример #1
0
  /**
   * Main entry point for the calling the TestForTransformation programmatically.
   *
   * @param classNode The class node that represents th test
   * @param ce The class expression that represents the class to test
   */
  public void testFor(ClassNode classNode, ClassExpression ce) {
    boolean junit3Test = isJunit3Test(classNode);

    // make sure the 'log' property is not the one from GroovyTestCase
    FieldNode log = classNode.getField("log");
    if (log == null || log.getDeclaringClass().equals(GROOVY_TEST_CASE_CLASS)) {
      LoggingTransformer.addLogField(classNode, classNode.getName());
    }
    boolean isSpockTest = isSpockTest(classNode);

    if (!isSpockTest && !junit3Test) {
      // assume JUnit 4
      Map<String, MethodNode> declaredMethodsMap = classNode.getDeclaredMethodsMap();
      for (String methodName : declaredMethodsMap.keySet()) {
        MethodNode methodNode = declaredMethodsMap.get(methodName);
        if (isCandidateMethod(methodNode) && methodNode.getName().startsWith("test")) {
          if (methodNode.getAnnotations().size() == 0) {
            methodNode.addAnnotation(TEST_ANNOTATION);
          }
        }
      }
    }

    final MethodNode methodToAdd = weaveMock(classNode, ce, true);
    if (methodToAdd != null && junit3Test) {
      addMethodCallsToMethod(classNode, SET_UP_METHOD, Arrays.asList(methodToAdd));
    }
  }
  private void createBuilderForAnnotatedMethod(
      BuilderASTTransformation transform, MethodNode mNode, AnnotationNode anno) {
    if (transform.getMemberValue(anno, "includes") != null
        || transform.getMemberValue(anno, "includes") != null) {
      transform.addError(
          "Error during "
              + BuilderASTTransformation.MY_TYPE_NAME
              + " processing: includes/excludes only allowed on classes",
          anno);
    }
    if (mNode instanceof ConstructorNode) {
      mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC);
    } else {
      if ((mNode.getModifiers() & ACC_STATIC) == 0) {
        transform.addError(
            "Error during "
                + BuilderASTTransformation.MY_TYPE_NAME
                + " processing: method builders only allowed on static methods",
            anno);
      }
      mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC | ACC_STATIC);
    }
    ClassNode buildee = mNode.getDeclaringClass();
    Parameter[] parameters = mNode.getParameters();
    ClassNode builder =
        createInnerHelperClass(buildee, getBuilderClassName(buildee, anno), parameters.length);
    List<FieldNode> convertedFields = convertParamsToFields(builder, parameters);

    buildCommon(buildee, anno, convertedFields, builder);
    if (mNode instanceof ConstructorNode) {
      createBuildeeConstructors(transform, buildee, builder, convertedFields, false);
    } else {
      createBuildeeMethods(buildee, mNode, builder, convertedFields);
    }
  }
 @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;
 }
  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);
  }
Пример #5
0
 public static void addMethodIfNotPresent(ClassNode controllerClassNode, MethodNode methodNode) {
   MethodNode existing =
       controllerClassNode.getMethod(methodNode.getName(), methodNode.getParameters());
   if (existing == null) {
     controllerClassNode.addMethod(methodNode);
   }
 }
  public void visitConstructorCallExpression(ConstructorCallExpression call) {
    isSpecialConstructorCall = call.isSpecialCall();
    super.visitConstructorCallExpression(call);
    isSpecialConstructorCall = false;
    if (!call.isUsingAnonymousInnerClass()) return;

    pushState();
    InnerClassNode innerClass = (InnerClassNode) call.getType();
    innerClass.setVariableScope(currentScope);
    for (MethodNode method : innerClass.getMethods()) {
      Parameter[] parameters = method.getParameters();
      if (parameters.length == 0) parameters = null; // null means no implicit "it"
      ClosureExpression cl = new ClosureExpression(parameters, method.getCode());
      visitClosureExpression(cl);
    }

    for (FieldNode field : innerClass.getFields()) {
      final Expression expression = field.getInitialExpression();
      if (expression != null) {
        expression.visit(this);
      }
    }

    for (Statement statement : innerClass.getObjectInitializerStatements()) {
      statement.visit(this);
    }
    markClosureSharedVariables();
    popState();
  }
Пример #7
0
 private void setMethodDefaultValue(MethodNode mn, Method m) {
   Object defaultValue = m.getDefaultValue();
   ConstantExpression cExp = ConstantExpression.NULL;
   if (defaultValue != null) cExp = new ConstantExpression(defaultValue);
   mn.setCode(new ReturnStatement(cExp));
   mn.setAnnotationDefault(true);
 }
  /**
   * Adds the necessary field and methods to support resource locating.
   *
   * @param declaringClass the class to which we add the support field and methods
   */
  public static void apply(@Nonnull ClassNode declaringClass, @Nullable String beanName) {
    injectInterface(declaringClass, EVENT_PUBLISHER_CNODE);

    FieldNode epField =
        injectField(
            declaringClass, EVENT_ROUTER_FIELD_NAME, PRIVATE, EVENT_PUBLISHER_FIELD_CNODE, null);

    Parameter erParam = param(EVENT_ROUTER_CNODE, EVENT_ROUTER_PROPERTY);
    if (!isBlank(beanName)) {
      AnnotationNode namedAnnotation = new AnnotationNode(NAMED_TYPE);
      namedAnnotation.addMember("value", new ConstantExpression(beanName));
      erParam.addAnnotation(namedAnnotation);
    }

    MethodNode setter =
        new MethodNode(
            METHOD_SET_EVENT_ROUTER,
            PRIVATE,
            VOID_TYPE,
            params(erParam),
            NO_EXCEPTIONS,
            stmnt(call(field(epField), METHOD_SET_EVENT_ROUTER, args(var(EVENT_ROUTER_PROPERTY)))));
    setter.addAnnotation(new AnnotationNode(INJECT_TYPE));
    injectMethod(declaringClass, setter);

    addDelegateMethods(declaringClass, EVENT_PUBLISHER_CNODE, field(epField));
  }
 private MethodNode toMethod(ClassNode declaringType, ResolverCache resolver) {
   if (cachedRegularParameters == null) {
     cachedRegularParameters = initParams(params, resolver);
     cachedOptionalParameters = initParams(optionalParams, resolver);
     cachedNamedParameters = initParams(namedParams, resolver);
     if (cachedReturnType == null) {
       if (resolver != null) {
         cachedReturnType = resolver.resolve(returnType);
       } else {
         cachedReturnType = VariableScope.OBJECT_CLASS_NODE;
       }
     }
   }
   MethodNode meth =
       new NamedArgsMethodNode(
           methodName,
           opcode(),
           cachedReturnType,
           cachedRegularParameters,
           cachedNamedParameters,
           cachedOptionalParameters,
           NO_EXCEPTIONS,
           EMPTY_BLOCK);
   meth.setDeclaringClass(ensureDeclaringType(declaringType, resolver));
   return meth;
 }
Пример #10
0
 public static void visitScriptCode(SourceUnit source, GroovyCodeVisitor transformer) {
   source.getAST().getStatementBlock().visit(transformer);
   for (Object method : source.getAST().getMethods()) {
     MethodNode methodNode = (MethodNode) method;
     methodNode.getCode().visit(transformer);
   }
 }
 public static String makeDescriptorWithoutReturnType(MethodNode mn) {
   StringBuilder sb = new StringBuilder();
   sb.append(mn.getName()).append(':');
   for (Parameter p : mn.getParameters()) {
     sb.append(p.getType()).append(',');
   }
   return sb.toString();
 }
Пример #12
0
  private AnnotatedNode createMethodDeclaration(
      String finderName,
      String[] props,
      String[] comparators,
      String newPropName,
      String newComparator) {
    // need to determine number of parameters

    // first figure out how many properties we need to look at
    int numArgs = -1;
    if (newPropName != null) {
      for (int i = 0; i < props.length; i++) {
        if (props[i] == null) {
          props[i] = newPropName;
          numArgs = i + 1;
          break;
        }
      }
    }
    if (newComparator != null) {
      for (int i = 0; i < comparators.length; i++) {
        if (comparators[i] == null) {
          comparators[i] = newComparator;
          numArgs = i + 1;
          break;
        }
      }
    }

    List<Parameter> params = new ArrayList<Parameter>(2);
    // now go through each component and comparator.
    // determine the kind of parameters they require
    for (int i = 0; i < numArgs; i++) {
      ClassNode[] classNodes = COMPARATOR_ARGUMENT_MAP.get(comparators[i]);
      if (classNodes.length > 0) {
        String uncapitalized = uncapitalize(props[i]);
        params.add(new Parameter(classNodes[0], uncapitalized));
        if (classNodes.length == 2) {
          params.add(new Parameter(classNodes[1], uncapitalized + "1"));
        }
      }
    }

    MethodNode method =
        new MethodNode(
            finderName,
            Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC,
            createReturnType(finderName),
            params.toArray(new Parameter[params.size()]),
            NO_EXCEPTIONS,
            EMPTY_BLOCK);
    if (domain != null) {
      method.setDeclaringClass(domain.getGroovyClass());
    } else {
      method.setDeclaringClass(VariableScope.OBJECT_CLASS_NODE);
    }
    return method;
  }
 private void checkMethodModifiers(MethodNode node) {
   // don't check volatile here as it overlaps with ACC_BRIDGE
   // additional modifiers not allowed for interfaces
   if ((this.currentClass.getModifiers() & ACC_INTERFACE) != 0) {
     checkMethodForModifier(node, isStrict(node.getModifiers()), "strictfp");
     checkMethodForModifier(node, isSynchronized(node.getModifiers()), "synchronized");
     checkMethodForModifier(node, isNative(node.getModifiers()), "native");
   }
 }
 private void memorizeInitialExpressions(final MethodNode node) {
   // add node metadata for default parameters because they are erased by the Verifier
   if (node.getParameters() != null) {
     for (Parameter parameter : node.getParameters()) {
       parameter.putNodeMetaData(
           StaticTypesMarker.INITIAL_EXPRESSION, parameter.getInitialExpression());
     }
   }
 }
 public static boolean hasDeclaredMethod(ClassNode cNode, String name, int argsCount) {
   List<MethodNode> ms = cNode.getDeclaredMethods(name);
   for (MethodNode m : ms) {
     Parameter[] paras = m.getParameters();
     if (paras != null && paras.length == argsCount) {
       return true;
     }
   }
   return false;
 }
Пример #16
0
 public static boolean isConstructorMethod(MethodNode declaredMethod) {
   return declaredMethod.isStatic()
       && declaredMethod.isPublic()
       && declaredMethod.getName().equals("initialize")
       && declaredMethod.getParameters().length >= 1
       && declaredMethod
           .getParameters()[0]
           .getType()
           .equals(AbstractGrailsArtefactTransformer.OBJECT_CLASS);
 }
 private void visitMethodNode(MethodNode methodNode) {
   if (methodNode.isSyntheticPublic()) revertVisibility(methodNode);
   else
     throw new RuntimeException(
         "Can't use "
             + MY_TYPE_NAME
             + " for method '"
             + methodNode.getName()
             + "' which has explicit visibility.");
 }
Пример #18
0
 // no rename so delete and add
 private static void renameMethod(ClassNode buildee, MethodNode mNode, String newName) {
   buildee.addMethod(
       newName,
       mNode.getModifiers(),
       mNode.getReturnType(),
       mNode.getParameters(),
       mNode.getExceptions(),
       mNode.getCode());
   buildee.removeMethod(mNode);
 }
  /**
   * This method is used to add "bridge" methods for private methods of an inner/outer class, so
   * that the outer class is capable of calling them. It does basically the same job as access$000
   * like methods in Java.
   *
   * @param node an inner/outer class node for which to generate bridge methods
   */
  @SuppressWarnings("unchecked")
  private void addPrivateBridgeMethods(final ClassNode node) {
    Set<ASTNode> accessedMethods =
        (Set<ASTNode>) node.getNodeMetaData(StaticTypesMarker.PV_METHODS_ACCESS);
    if (accessedMethods == null) return;
    List<MethodNode> methods = new ArrayList<MethodNode>(node.getAllDeclaredMethods());
    Map<MethodNode, MethodNode> privateBridgeMethods =
        (Map<MethodNode, MethodNode>) node.getNodeMetaData(PRIVATE_BRIDGE_METHODS);
    if (privateBridgeMethods != null) {
      // private bridge methods already added
      return;
    }
    privateBridgeMethods = new HashMap<MethodNode, MethodNode>();
    int i = -1;
    final int access = Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC;
    for (MethodNode method : methods) {
      if (accessedMethods.contains(method)) {
        i++;
        Parameter[] methodParameters = method.getParameters();
        Parameter[] newParams = new Parameter[methodParameters.length + 1];
        System.arraycopy(methodParameters, 0, newParams, 1, methodParameters.length);
        newParams[0] = new Parameter(node.getPlainNodeReference(), "$that");
        Expression arguments;
        if (method.getParameters() == null || method.getParameters().length == 0) {
          arguments = ArgumentListExpression.EMPTY_ARGUMENTS;
        } else {
          List<Expression> args = new LinkedList<Expression>();
          for (Parameter parameter : methodParameters) {
            args.add(new VariableExpression(parameter));
          }
          arguments = new ArgumentListExpression(args);
        }
        Expression receiver =
            method.isStatic() ? new ClassExpression(node) : new VariableExpression(newParams[0]);
        MethodCallExpression mce = new MethodCallExpression(receiver, method.getName(), arguments);
        mce.setMethodTarget(method);

        ExpressionStatement returnStatement = new ExpressionStatement(mce);
        MethodNode bridge =
            node.addMethod(
                "access$" + i,
                access,
                method.getReturnType(),
                newParams,
                method.getExceptions(),
                returnStatement);
        privateBridgeMethods.put(method, bridge);
        bridge.addAnnotation(new AnnotationNode(COMPILESTATIC_CLASSNODE));
      }
    }
    if (!privateBridgeMethods.isEmpty()) {
      node.setNodeMetaData(PRIVATE_BRIDGE_METHODS, privateBridgeMethods);
    }
  }
 public void visitMethod(MethodNode node) {
   inConstructor = false;
   inStaticConstructor = node.isStaticConstructor();
   checkAbstractDeclaration(node);
   checkRepetitiveMethod(node);
   checkOverloadingPrivateAndPublic(node);
   checkMethodModifiers(node);
   checkGenericsUsage(node, node.getParameters());
   checkGenericsUsage(node, node.getReturnType());
   super.visitMethod(node);
 }
 /**
  * Tests whether the ClassNode implements the specified method name
  *
  * @param classNode The ClassNode
  * @param methodName The method name
  * @param argTypes
  * @return True if it implements the method
  */
 private static boolean implementsMethod(
     ClassNode classNode, String methodName, Class[] argTypes) {
   List methods = classNode.getMethods();
   for (Iterator i = methods.iterator(); i.hasNext(); ) {
     MethodNode mn = (MethodNode) i.next();
     final boolean isZeroArg = (argTypes == null || argTypes.length == 0);
     boolean methodMatch = mn.getName().equals(methodName) && isZeroArg;
     if (methodMatch) return true;
     // TODO Implement further parameter analysis
   }
   return false;
 }
 private void checkAbstractDeclaration(MethodNode methodNode) {
   if (!methodNode.isAbstract()) return;
   if (isAbstract(currentClass.getModifiers())) return;
   addError(
       "Can't have an abstract method in a non-abstract class."
           + " The "
           + getDescription(currentClass)
           + " must be declared abstract or the method '"
           + methodNode.getTypeDescriptor()
           + "' must not be abstract.",
       methodNode);
 }
  @Test
  public void transformationOfAnnotationOnMethod() {
    ClassNode classNode = new ClassNode("Test", 0, new ClassNode(Object.class));
    this.moduleNode.addClass(classNode);

    MethodNode methodNode =
        new MethodNode(
            "test", 0, new ClassNode(Void.class), new Parameter[0], new ClassNode[0], null);
    methodNode.addAnnotation(this.grabAnnotation);
    classNode.addMethod(methodNode);

    assertGrabAnnotationHasBeenTransformed();
  }
Пример #24
0
  private void changeBaseScriptType(
      final AnnotatedNode parent, final ClassNode cNode, final ClassNode baseScriptType) {
    if (!cNode.isScriptBody()) {
      addError("Annotation " + MY_TYPE_NAME + " can only be used within a Script.", parent);
      return;
    }

    if (!baseScriptType.isScript()) {
      addError(
          "Declared type " + baseScriptType + " does not extend groovy.lang.Script class!", parent);
      return;
    }

    cNode.setSuperClass(baseScriptType);

    // Method in base script that will contain the script body code.
    MethodNode runScriptMethod = ClassHelper.findSAM(baseScriptType);

    // If they want to use a name other than than "run", then make the change.
    if (isCustomScriptBodyMethod(runScriptMethod)) {
      MethodNode defaultMethod = cNode.getDeclaredMethod("run", Parameter.EMPTY_ARRAY);
      // GROOVY-6706: Sometimes an NPE is thrown here.
      // The reason is that our transform is getting called more than once sometimes.
      if (defaultMethod != null) {
        cNode.removeMethod(defaultMethod);
        MethodNode methodNode =
            new MethodNode(
                runScriptMethod.getName(),
                runScriptMethod.getModifiers() & ~ACC_ABSTRACT,
                runScriptMethod.getReturnType(),
                runScriptMethod.getParameters(),
                runScriptMethod.getExceptions(),
                defaultMethod.getCode());
        // The AST node metadata has the flag that indicates that this method is a script body.
        // It may also be carrying data for other AST transforms.
        methodNode.copyNodeMetaData(defaultMethod);
        cNode.addMethod(methodNode);
      }
    }

    // If the new script base class does not have a contextual constructor (g.l.Binding), then we
    // won't either.
    // We have to do things this way (and rely on just default constructors) because the logic that
    // generates
    // the constructors for our script class have already run.
    if (cNode.getSuperClass().getDeclaredConstructor(CONTEXT_CTOR_PARAMETERS) == null) {
      ConstructorNode orphanedConstructor = cNode.getDeclaredConstructor(CONTEXT_CTOR_PARAMETERS);
      cNode.removeConstructor(orphanedConstructor);
    }
  }
Пример #25
0
 private MethodNode createBuildMethodForMethod(
     AnnotationNode anno, ClassNode buildee, MethodNode mNode, Parameter[] params) {
   String buildMethodName = getMemberStringValue(anno, "buildMethodName", "build");
   final BlockStatement body = new BlockStatement();
   ClassNode returnType;
   if (mNode instanceof ConstructorNode) {
     returnType = newClass(buildee);
     body.addStatement(returnS(ctorX(newClass(mNode.getDeclaringClass()), args(params))));
   } else {
     body.addStatement(
         returnS(callX(newClass(mNode.getDeclaringClass()), mNode.getName(), args(params))));
     returnType = newClass(mNode.getReturnType());
   }
   return new MethodNode(buildMethodName, ACC_PUBLIC, returnType, NO_PARAMS, NO_EXCEPTIONS, body);
 }
 private void visitDeprecation(AnnotatedNode node, AnnotationNode visited) {
   if (visited.getClassNode().isResolved()
       && visited.getClassNode().getName().equals("java.lang.Deprecated")) {
     if (node instanceof MethodNode) {
       MethodNode mn = (MethodNode) node;
       mn.setModifiers(mn.getModifiers() | Opcodes.ACC_DEPRECATED);
     } else if (node instanceof FieldNode) {
       FieldNode fn = (FieldNode) node;
       fn.setModifiers(fn.getModifiers() | Opcodes.ACC_DEPRECATED);
     } else if (node instanceof ClassNode) {
       ClassNode cn = (ClassNode) node;
       cn.setModifiers(cn.getModifiers() | Opcodes.ACC_DEPRECATED);
     }
   }
 }
  private String getPropertyName(MethodNode m) {
    String name = m.getName();
    if (!(name.startsWith("set") || name.startsWith("get"))) return null;
    String pname = name.substring(3);
    if (pname.length() == 0) return null;
    pname = java.beans.Introspector.decapitalize(pname);

    if (name.startsWith("get")
        && (m.getReturnType() == ClassHelper.VOID_TYPE || m.getParameters().length != 0)) {
      return null;
    }
    if (name.startsWith("set") && m.getParameters().length != 1) {
      return null;
    }
    return pname;
  }
Пример #28
0
 private static VariableExpression addApiVariableDeclaration(
     Expression delegate, MethodNode declaredMethod, BlockStatement methodBody) {
   VariableExpression apiVar = new VariableExpression("$api_" + declaredMethod.getName());
   DeclarationExpression de = new DeclarationExpression(apiVar, ASSIGNMENT_OPERATOR, delegate);
   methodBody.addStatement(new ExpressionStatement(de));
   return apiVar;
 }
Пример #29
0
 public static boolean isCandidateInstanceMethod(ClassNode classNode, MethodNode declaredMethod) {
   Parameter[] parameterTypes = declaredMethod.getParameters();
   return isCandidateMethod(declaredMethod)
       && parameterTypes != null
       && parameterTypes.length > 0
       && isAssignableFrom(parameterTypes[0].getType(), classNode);
 }
 @Override
 public void visitMethod(final MethodNode node) {
   if (isSkipMode(node)) {
     node.putNodeMetaData(STATIC_COMPILE_NODE, false);
   }
   super.visitMethod(node);
   checkForConstructorWithCSButClassWithout(node);
 }