Пример #1
0
  private String genericsBounds(ClassNode theType, Set<String> visited) {
    String ret =
        theType.isArray() ? theType.getComponentType().getName() + "[]" : theType.getName();
    GenericsType[] genericsTypes = theType.getGenericsTypes();
    if (genericsTypes == null || genericsTypes.length == 0) return ret;
    // TODO instead of catching Object<T> here stop it from being placed into type in first place
    if (genericsTypes.length == 1
        && genericsTypes[0].isPlaceholder()
        && theType.getName().equals("java.lang.Object")) {
      return genericsTypes[0].getName();
    }
    ret += "<";
    for (int i = 0; i < genericsTypes.length; i++) {
      if (i != 0) ret += ", ";

      GenericsType type = genericsTypes[i];
      if (type.isPlaceholder() && visited.contains(type.getName())) {
        ret += type.getName();
      } else {
        ret += type.toString(visited);
      }
    }
    ret += ">";
    return ret;
  }
Пример #2
0
 private static void writeGenericsBounds(
     StringBuffer ret, GenericsType type, boolean writeInterfaceMarker) {
   if (type.getUpperBounds() != null) {
     ClassNode[] bounds = type.getUpperBounds();
     for (int i = 0; i < bounds.length; i++) {
       writeGenericsBoundType(ret, bounds[i], writeInterfaceMarker);
     }
   } else if (type.getLowerBound() != null) {
     writeGenericsBoundType(ret, type.getLowerBound(), writeInterfaceMarker);
   } else {
     writeGenericsBoundType(ret, type.getType(), writeInterfaceMarker);
   }
 }
Пример #3
0
 public static GenericsType configureTypeVariableDefinition(ClassNode base, ClassNode[] cBounds) {
   ClassNode redirect = base.redirect();
   base.setRedirect(null);
   GenericsType gt;
   if (cBounds == null || cBounds.length == 0) {
     gt = new GenericsType(base);
   } else {
     gt = new GenericsType(base, cBounds, null);
     gt.setName(base.getName());
     gt.setPlaceholder(true);
   }
   base.setRedirect(redirect);
   return gt;
 }
Пример #4
0
  /**
   * 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;
  }
Пример #5
0
 private GenericsType configureTypeVariableDefinition(TypeVariable tv) {
   ClassNode base = configureTypeVariableReference(tv);
   ClassNode redirect = base.redirect();
   base.setRedirect(null);
   Type[] tBounds = tv.getBounds();
   GenericsType gt;
   if (tBounds.length == 0) {
     gt = new GenericsType(base);
   } else {
     ClassNode[] cBounds = configureTypes(tBounds);
     gt = new GenericsType(base, cBounds, null);
     gt.setName(base.getName());
     gt.setPlaceholder(true);
   }
   base.setRedirect(redirect);
   return gt;
 }
Пример #6
0
  private ClassNode configureWildcardType(WildcardType wildcardType) {
    ClassNode base = ClassHelper.makeWithoutCaching("?");
    base.setRedirect(ClassHelper.OBJECT_TYPE);
    // TODO: more than one lower bound for wildcards?
    ClassNode[] lowers = configureTypes(wildcardType.getLowerBounds());
    ClassNode lower = null;
    // TODO: is it safe to remove this? What was the original intention?
    if (lower != null) lower = lowers[0];

    ClassNode[] upper = configureTypes(wildcardType.getUpperBounds());
    GenericsType t = new GenericsType(base, upper, lower);
    t.setWildcard(true);

    ClassNode ref = ClassHelper.makeWithoutCaching(Object.class, false);
    ref.setGenericsTypes(new GenericsType[] {t});

    return ref;
  }
Пример #7
0
  /**
   * 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]);
      }
    }
  }
Пример #8
0
 /**
  * This exists to avoid a recursive definition of toString. The default toString in GenericsType
  * calls ClassNode.toString(), which calls GenericsType.toString(), etc.
  *
  * @param genericsType
  * @param showRedirect
  * @return the string representing the generic type
  */
 private String genericTypeAsString(GenericsType genericsType, boolean showRedirect) {
   String ret = genericsType.getName();
   if (genericsType.getUpperBounds() != null) {
     ret += " extends ";
     for (int i = 0; i < genericsType.getUpperBounds().length; i++) {
       ClassNode classNode = genericsType.getUpperBounds()[i];
       if (classNode.equals(this)) {
         ret += classNode.getName();
       } else {
         ret += classNode.toString(showRedirect);
       }
       if (i + 1 < genericsType.getUpperBounds().length) ret += " & ";
     }
   } else if (genericsType.getLowerBound() != null) {
     ClassNode classNode = genericsType.getLowerBound();
     if (classNode.equals(this)) {
       ret += " super " + classNode.getName();
     } else {
       ret += " super " + classNode;
     }
   }
   return ret;
 }
Пример #9
0
 /**
  * Given a parameterized type and a generic type information, aligns actual type parameters. For
  * example, if a class uses generic type
  *
  * <pre>&lt;T,U,V&gt;</pre>
  *
  * (redirectGenericTypes), is used with actual type parameters
  *
  * <pre>&lt;java.lang.String, U,V&gt;</pre>
  *
  * , then a class or interface using generic types
  *
  * <pre>&lt;T,V&gt;</pre>
  *
  * will be aligned to
  *
  * <pre>&lt;java.lang.String,V&gt;</pre>
  *
  * @param redirectGenericTypes the type arguments or the redirect class node
  * @param parameterizedTypes the actual type arguments used on this class node
  * @param alignmentTarget the generic type arguments to which we want to align to
  * @return aligned type arguments
  */
 public static GenericsType[] alignGenericTypes(
     final GenericsType[] redirectGenericTypes,
     final GenericsType[] parameterizedTypes,
     final GenericsType[] alignmentTarget) {
   if (alignmentTarget == null) return EMPTY_GENERICS_ARRAY;
   if (parameterizedTypes == null || parameterizedTypes.length == 0) return alignmentTarget;
   GenericsType[] generics = new GenericsType[alignmentTarget.length];
   for (int i = 0, scgtLength = alignmentTarget.length; i < scgtLength; i++) {
     final GenericsType currentTarget = alignmentTarget[i];
     GenericsType match = null;
     if (redirectGenericTypes != null) {
       for (int j = 0; j < redirectGenericTypes.length && match == null; j++) {
         GenericsType redirectGenericType = redirectGenericTypes[j];
         if (redirectGenericType.isCompatibleWith(currentTarget.getType())) {
           if (currentTarget.isPlaceholder()
               && redirectGenericType.isPlaceholder()
               && !currentTarget.getName().equals(redirectGenericType.getName())) {
             // check if there's a potential better match
             boolean skip = false;
             for (int k = j + 1; k < redirectGenericTypes.length && !skip; k++) {
               GenericsType ogt = redirectGenericTypes[k];
               if (ogt.isPlaceholder()
                   && ogt.isCompatibleWith(currentTarget.getType())
                   && ogt.getName().equals(currentTarget.getName())) {
                 skip = true;
               }
             }
             if (skip) continue;
           }
           match = parameterizedTypes[j];
           if (currentTarget.isWildcard()) {
             // if alignment target is a wildcard type
             // then we must make best effort to return a parameterized
             // wildcard
             ClassNode lower = currentTarget.getLowerBound() != null ? match.getType() : null;
             ClassNode[] currentUpper = currentTarget.getUpperBounds();
             ClassNode[] upper = currentUpper != null ? new ClassNode[currentUpper.length] : null;
             if (upper != null) {
               for (int k = 0; k < upper.length; k++) {
                 upper[k] =
                     currentUpper[k].isGenericsPlaceHolder() ? match.getType() : currentUpper[k];
               }
             }
             match = new GenericsType(ClassHelper.makeWithoutCaching("?"), upper, lower);
             match.setWildcard(true);
           }
         }
       }
     }
     if (match == null) {
       match = currentTarget;
     }
     generics[i] = match;
   }
   return generics;
 }
Пример #10
0
 /**
  * Generates a wildcard generic type in order to be used for checks against class nodes. See
  * {@link GenericsType#isCompatibleWith(org.codehaus.groovy.ast.ClassNode)}.
  *
  * @param types the type to be used as the wildcard upper bound
  * @return a wildcard generics type
  */
 public static GenericsType buildWildcardType(final ClassNode... types) {
   ClassNode base = ClassHelper.makeWithoutCaching("?");
   GenericsType gt = new GenericsType(base, types, null);
   gt.setWildcard(true);
   return gt;
 }