All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.groovy.ast.tools.GenericsUtils Maven / Gradle / Ivy

There is a newer version: 3.9
Show newest version
/*
 * Copyright 2003-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.codehaus.groovy.ast.tools;

import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.GenericsType;

import java.util.HashMap;
import java.util.Map;

/**
 * Utility methods to deal with generic types.
 *
 * @author Cedric Champeau
 */
public class GenericsUtils {
    public static final GenericsType[] EMPTY_GENERICS_ARRAY = new GenericsType[0];

    /**
     * Given a parameterized type and a generic type information, aligns actual type parameters. For example, if a
     * class uses generic type 
<T,U,V>
(redirectGenericTypes), is used with actual type parameters *
<java.lang.String, U,V>
, then a class or interface using generic types
<T,V>
* will be aligned to
<java.lang.String,V>
* @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 extractPlaceholders(ClassNode cn) { HashMap ret = new HashMap(); extractPlaceholders(cn, ret); return ret; } /** * 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 map) { if (node == null) 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]); } } if (node.isArray()) { extractPlaceholders(node.getComponentType(), map); } } /** * 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 * @deprecated Use #parameterizeType instead */ public static ClassNode parameterizeInterfaceGenerics(final ClassNode hint, final ClassNode target) { return parameterizeType(hint, target); } /** * 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 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 , node=List , anInterface = Iterable 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 parameters = new HashMap(); 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy