private static boolean usesGenericsInClassSignature(ClassNode node) {
    if (!node.isUsingGenerics()) return false;
    if (hasGenerics(node)) return true;
    ClassNode sclass = node.getUnresolvedSuperClass(false);
    if (sclass.isUsingGenerics()) return true;
    ClassNode[] interfaces = node.getInterfaces();
    if (interfaces != null) {
      for (int i = 0; i < interfaces.length; i++) {
        if (interfaces[i].isUsingGenerics()) return true;
      }
    }

    return false;
  }
  /**
   * Interface class nodes retrieved from {@link org.codehaus.groovy.ast.ClassNode#getInterfaces()}
   * or {@link org.codehaus.groovy.ast.ClassNode#getAllInterfaces()} are returned with generic type
   * arguments. This method allows returning a parameterized interface given the parameterized class
   * node which implements this interface.
   *
   * @param hint the class node where generics types are parameterized
   * @param target the interface we want to parameterize generics types
   * @return a parameterized interface class node
   */
  public static ClassNode parameterizeType(final ClassNode hint, final ClassNode target) {
    ClassNode interfaceFromClassNode = null;
    if (hint.equals(target)) interfaceFromClassNode = hint;
    if (ClassHelper.OBJECT_TYPE.equals(target)
        && target.isUsingGenerics()
        && target.getGenericsTypes() != null
        && target.getGenericsTypes()[0].isPlaceholder()) {
      // Object<T>
      return ClassHelper.getWrapper(hint);
    }
    if (interfaceFromClassNode == null) {
      ClassNode[] interfaces = hint.getInterfaces();
      for (ClassNode node : interfaces) {
        if (node.equals(target)) {
          interfaceFromClassNode = node;
          break;
        } else if (node.implementsInterface(target)) {
          // ex: classNode = LinkedList<A> , node=List<E> , anInterface = Iterable<T>
          return parameterizeType(parameterizeType(hint, node), target);
        }
      }
    }
    if (interfaceFromClassNode == null && hint.getUnresolvedSuperClass() != null) {
      return parameterizeType(hint.getUnresolvedSuperClass(), target);
    }
    if (interfaceFromClassNode == null) {

      //            return target;
      interfaceFromClassNode = hint;
    }
    Map<String, GenericsType> parameters = new HashMap<String, GenericsType>();
    extractPlaceholders(hint, parameters);
    ClassNode node = target.getPlainNodeReference();
    GenericsType[] interfaceGTs = interfaceFromClassNode.getGenericsTypes();
    if (interfaceGTs == null) return target;
    GenericsType[] types = new GenericsType[interfaceGTs.length];
    for (int i = 0; i < interfaceGTs.length; i++) {
      GenericsType interfaceGT = interfaceGTs[i];
      types[i] = interfaceGT;
      if (interfaceGT.isPlaceholder()) {
        String name = interfaceGT.getName();
        if (parameters.containsKey(name)) {
          types[i] = parameters.get(name);
        }
      }
    }
    node.setGenericsTypes(types);
    return node;
  }
 /**
  * @param name is the full name of the class
  * @param modifiers the modifiers,
  * @param superClass the base class name - use "java.lang.Object" if no direct base class
  * @param interfaces the interfaces for this class
  * @param mixins the mixins for this class
  * @see org.objectweb.asm.Opcodes
  */
 public ClassNode(
     String name,
     int modifiers,
     ClassNode superClass,
     ClassNode[] interfaces,
     MixinNode[] mixins) {
   this.name = name;
   this.modifiers = modifiers;
   this.superClass = superClass;
   this.interfaces = interfaces;
   this.mixins = mixins;
   isPrimaryNode = true;
   if (superClass != null) {
     usesGenerics = superClass.isUsingGenerics();
   }
   if (!usesGenerics && interfaces != null) {
     for (ClassNode anInterface : interfaces) {
       usesGenerics = usesGenerics || anInterface.isUsingGenerics();
       if (usesGenerics) break;
     }
   }
   this.methods = new MapOfLists();
   this.methodsList = Collections.emptyList();
 }
Exemple #4
0
  public static ClassNode nonGeneric(ClassNode type) {
    if (type.isUsingGenerics()) {
      final ClassNode nonGen = ClassHelper.makeWithoutCaching(type.getName());
      nonGen.setRedirect(type);
      nonGen.setGenericsTypes(null);
      nonGen.setUsingGenerics(false);
      return nonGen;
    }

    if (type.isArray()) {
      final ClassNode nonGen = ClassHelper.makeWithoutCaching(Object.class);
      nonGen.setUsingGenerics(false);
      return nonGen.makeArray();
    }

    return type.getPlainNodeReference();
  }
 private void checkGenericsUsage(ASTNode ref, ClassNode node) {
   if (node.isArray()) {
     checkGenericsUsage(ref, node.getComponentType());
   } else if (!node.isRedirectNode() && node.isUsingGenerics()) {
     addError(
         "A transform used a generics containing ClassNode "
             + node
             + " "
             + "for "
             + getRefDescriptor(ref)
             + "directly. You are not suppposed to do this. "
             + "Please create a new ClassNode refering to the old ClassNode "
             + "and use the new ClassNode instead of the old one. Otherwise "
             + "the compiler will create wrong descriptors and a potential "
             + "NullPointerException in TypeResolver in the OpenJDK. If this is "
             + "not your own doing, please report this bug to the writer of the "
             + "transform.",
         ref);
   }
 }
  /**
   * For a given classnode, fills in the supplied map with the parameterized types it defines.
   *
   * @param node
   * @param map
   */
  public static void extractPlaceholders(ClassNode node, Map<String, GenericsType> map) {
    if (node == null) return;

    if (node.isArray()) {
      extractPlaceholders(node.getComponentType(), map);
      return;
    }

    if (!node.isUsingGenerics() || !node.isRedirectNode()) return;
    GenericsType[] parameterized = node.getGenericsTypes();
    if (parameterized == null || parameterized.length == 0) return;
    GenericsType[] redirectGenericsTypes = node.redirect().getGenericsTypes();
    if (redirectGenericsTypes == null) redirectGenericsTypes = parameterized;
    for (int i = 0; i < redirectGenericsTypes.length; i++) {
      GenericsType redirectType = redirectGenericsTypes[i];
      if (redirectType.isPlaceholder()) {
        String name = redirectType.getName();
        if (!map.containsKey(name)) map.put(name, parameterized[i]);
      }
    }
  }
 public ClassNode parameterizedType(ClassNode baseType, ClassNode... genericsTypeArguments) {
   ClassNode result = baseType.getPlainNodeReference();
   if (result.isUsingGenerics()) {
     GenericsType[] gts = new GenericsType[genericsTypeArguments.length];
     int expectedLength = result.getGenericsTypes().length;
     if (expectedLength != genericsTypeArguments.length) {
       throw new GroovyBugError(
           "Expected number of generic type arguments for "
               + baseType.toString(false)
               + " is "
               + expectedLength
               + " but you gave "
               + genericsTypeArguments.length);
     }
     for (int i = 0; i < gts.length; i++) {
       gts[i] = new GenericsType(genericsTypeArguments[i]);
     }
     result.setGenericsTypes(gts);
   }
   return result;
 }
  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;
  }