Example usage for org.eclipse.jdt.internal.compiler.lookup ParameterizedTypeBinding enclosingType

List of usage examples for org.eclipse.jdt.internal.compiler.lookup ParameterizedTypeBinding enclosingType

Introduction

In this page you can find the example usage for org.eclipse.jdt.internal.compiler.lookup ParameterizedTypeBinding enclosingType.

Prototype

ReferenceBinding enclosingType

To view the source code for org.eclipse.jdt.internal.compiler.lookup ParameterizedTypeBinding enclosingType.

Click Source Link

Usage

From source file:com.codenvy.ide.ext.java.server.internal.core.search.matching.PatternLocator.java

License:Open Source License

protected void updateMatch(ParameterizedTypeBinding parameterizedBinding, char[][][] patternTypeArguments,
        boolean patternHasTypeParameters, int depth, MatchLocator locator) {
    // Only possible if locator has an unit scope.
    if (locator.unitScope == null)
        return;//from  w w w  .  jav a  2  s .co  m

    // Set match raw flag
    boolean endPattern = patternTypeArguments == null ? true : depth >= patternTypeArguments.length;
    TypeBinding[] argumentsBindings = parameterizedBinding.arguments;
    boolean isRaw = parameterizedBinding.isRawType()
            || (argumentsBindings == null && parameterizedBinding.genericType().isGenericType());
    if (isRaw && !this.match.isRaw()) {
        this.match.setRaw(isRaw);
    }

    // Update match
    if (!endPattern && patternTypeArguments != null) {
        // verify if this is a reference to the generic type itself
        if (!isRaw && patternHasTypeParameters && argumentsBindings != null) {
            boolean needUpdate = false;
            TypeVariableBinding[] typeVariables = parameterizedBinding.genericType().typeVariables();
            int length = argumentsBindings.length;
            if (length == typeVariables.length) {
                for (int i = 0; i < length; i++) {
                    if (argumentsBindings[i] != typeVariables[i]) {
                        needUpdate = true;
                        break;
                    }
                }
            }
            if (needUpdate) {
                char[][] patternArguments = patternTypeArguments[depth];
                updateMatch(argumentsBindings, locator, patternArguments, patternHasTypeParameters);
            }
        } else {
            char[][] patternArguments = patternTypeArguments[depth];
            updateMatch(argumentsBindings, locator, patternArguments, patternHasTypeParameters);
        }
    }

    // Recurse
    TypeBinding enclosingType = parameterizedBinding.enclosingType();
    if (enclosingType != null && (enclosingType.isParameterizedType() || enclosingType.isRawType())) {
        updateMatch((ParameterizedTypeBinding) enclosingType, patternTypeArguments, patternHasTypeParameters,
                depth + 1, locator);
    }
}

From source file:com.codenvy.ide.ext.java.server.internal.core.search.matching.PatternLocator.java

License:Open Source License

protected int resolveLevelForType(char[] simpleNamePattern, char[] qualificationPattern,
        char[][][] patternTypeArguments, int depth, TypeBinding type) {
    // standard search with no generic additional information must succeed
    int level = resolveLevelForType(simpleNamePattern, qualificationPattern, type);
    if (level == IMPOSSIBLE_MATCH)
        return IMPOSSIBLE_MATCH;
    if (type == null || patternTypeArguments == null || patternTypeArguments.length == 0
            || depth >= patternTypeArguments.length) {
        return level;
    }/*  w  ww.  j av  a2  s  .  co m*/

    // if pattern is erasure match (see bug 79790), commute impossible to erasure
    int impossible = this.isErasureMatch ? ERASURE_MATCH : IMPOSSIBLE_MATCH;

    // pattern has type parameter(s) or type argument(s)
    if (type.isGenericType()) {
        // Binding is generic, get its type variable(s)
        TypeVariableBinding[] typeVariables = null;
        if (type instanceof SourceTypeBinding) {
            SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) type;
            typeVariables = sourceTypeBinding.typeVariables;
        } else if (type instanceof BinaryTypeBinding) {
            BinaryTypeBinding binaryTypeBinding = (BinaryTypeBinding) type;
            if (this.mustResolve)
                typeVariables = binaryTypeBinding.typeVariables(); // TODO (frederic) verify performance
        }
        if (patternTypeArguments[depth] != null && patternTypeArguments[depth].length > 0
                && typeVariables != null && typeVariables.length > 0) {
            if (typeVariables.length != patternTypeArguments[depth].length)
                return IMPOSSIBLE_MATCH;
        }
        // TODO (frederic) do we need to verify each parameter?
        return level; // we can't do better
    }

    // raw type always match
    if (type.isRawType()) {
        return level;
    }

    // Standard types (i.e. neither generic nor parameterized nor raw types)
    // cannot match pattern with type parameters or arguments
    TypeBinding leafType = type.leafComponentType();
    if (!leafType.isParameterizedType()) {
        return (patternTypeArguments[depth] == null || patternTypeArguments[depth].length == 0) ? level
                : IMPOSSIBLE_MATCH;
    }

    // Parameterized type
    ParameterizedTypeBinding paramTypeBinding = (ParameterizedTypeBinding) leafType;

    // Compare arguments only if there ones on both sides
    if (patternTypeArguments[depth] != null && patternTypeArguments[depth].length > 0
            && paramTypeBinding.arguments != null && paramTypeBinding.arguments.length > 0) {

        // type parameters length must match at least specified type names length
        int length = patternTypeArguments[depth].length;
        if (paramTypeBinding.arguments.length != length)
            return IMPOSSIBLE_MATCH;

        // verify each pattern type parameter
        nextTypeArgument: for (int i = 0; i < length; i++) {
            char[] patternTypeArgument = patternTypeArguments[depth][i];
            TypeBinding argTypeBinding = paramTypeBinding.arguments[i];
            // get corresponding pattern wildcard
            switch (patternTypeArgument[0]) {
            case Signature.C_STAR: // unbound parameter always match
            case Signature.C_SUPER: // needs pattern type parameter binding
                // skip to next type argument as it will be resolved later
                continue nextTypeArgument;
            case Signature.C_EXTENDS:
                // remove wildcard from patter type argument
                patternTypeArgument = CharOperation.subarray(patternTypeArgument, 1,
                        patternTypeArgument.length);
                break;
            default:
                // no wildcard
                break;
            }
            // get pattern type argument from its signature
            patternTypeArgument = Signature.toCharArray(patternTypeArgument);
            if (!this.isCaseSensitive)
                patternTypeArgument = CharOperation.toLowerCase(patternTypeArgument);
            boolean patternTypeArgHasAnyChars = CharOperation.contains(new char[] { '*', '?' },
                    patternTypeArgument);

            // Verify that names match...
            // ...special case for wildcard
            if (argTypeBinding instanceof CaptureBinding) {
                WildcardBinding capturedWildcard = ((CaptureBinding) argTypeBinding).wildcard;
                if (capturedWildcard != null)
                    argTypeBinding = capturedWildcard;
            }
            if (argTypeBinding.isWildcard()) {
                WildcardBinding wildcardBinding = (WildcardBinding) argTypeBinding;
                switch (wildcardBinding.boundKind) {
                case Wildcard.EXTENDS:
                    // Invalid if type argument is not exact
                    if (patternTypeArgHasAnyChars)
                        return impossible;
                    continue nextTypeArgument;
                case Wildcard.UNBOUND:
                    // there's no bound name to match => valid
                    continue nextTypeArgument;
                }
                // Look if bound name match pattern type argument
                ReferenceBinding boundBinding = (ReferenceBinding) wildcardBinding.bound;
                if (CharOperation.match(patternTypeArgument, boundBinding.shortReadableName(),
                        this.isCaseSensitive)
                        || CharOperation.match(patternTypeArgument, boundBinding.readableName(),
                                this.isCaseSensitive)) {
                    // found name in hierarchy => match
                    continue nextTypeArgument;
                }

                // If pattern is not exact then match fails
                if (patternTypeArgHasAnyChars)
                    return impossible;

                // Look for bound name in type argument superclasses
                boundBinding = boundBinding.superclass();
                while (boundBinding != null) {
                    if (CharOperation.equals(patternTypeArgument, boundBinding.shortReadableName(),
                            this.isCaseSensitive)
                            || CharOperation.equals(patternTypeArgument, boundBinding.readableName(),
                                    this.isCaseSensitive)) {
                        // found name in hierarchy => match
                        continue nextTypeArgument;
                    } else if (boundBinding.isLocalType() || boundBinding.isMemberType()) {
                        // for local or member type, verify also source name (bug 81084)
                        if (CharOperation.match(patternTypeArgument, boundBinding.sourceName(),
                                this.isCaseSensitive))
                            continue nextTypeArgument;
                    }
                    boundBinding = boundBinding.superclass();
                }
                return impossible;
            }

            // See if names match
            if (CharOperation.match(patternTypeArgument, argTypeBinding.shortReadableName(),
                    this.isCaseSensitive)
                    || CharOperation.match(patternTypeArgument, argTypeBinding.readableName(),
                            this.isCaseSensitive)) {
                continue nextTypeArgument;
            } else if (argTypeBinding.isLocalType() || argTypeBinding.isMemberType()) {
                // for local or member type, verify also source name (bug 81084)
                if (CharOperation.match(patternTypeArgument, argTypeBinding.sourceName(), this.isCaseSensitive))
                    continue nextTypeArgument;
            }

            // If pattern is not exact then match fails
            if (patternTypeArgHasAnyChars)
                return impossible;

            // Scan hierarchy
            TypeBinding leafTypeBinding = argTypeBinding.leafComponentType();
            if (leafTypeBinding.isBaseType())
                return impossible;
            ReferenceBinding refBinding = ((ReferenceBinding) leafTypeBinding).superclass();
            while (refBinding != null) {
                if (CharOperation.equals(patternTypeArgument, refBinding.shortReadableName(),
                        this.isCaseSensitive)
                        || CharOperation.equals(patternTypeArgument, refBinding.readableName(),
                                this.isCaseSensitive)) {
                    // found name in hierarchy => match
                    continue nextTypeArgument;
                } else if (refBinding.isLocalType() || refBinding.isMemberType()) {
                    // for local or member type, verify also source name (bug 81084)
                    if (CharOperation.match(patternTypeArgument, refBinding.sourceName(), this.isCaseSensitive))
                        continue nextTypeArgument;
                }
                refBinding = refBinding.superclass();
            }
            return impossible;
        }
    }

    // Recurse on enclosing type
    TypeBinding enclosingType = paramTypeBinding.enclosingType();
    if (enclosingType != null && enclosingType.isParameterizedType() && depth < patternTypeArguments.length
            && qualificationPattern != null) {
        int lastDot = CharOperation.lastIndexOf('.', qualificationPattern);
        char[] enclosingQualificationPattern = lastDot == -1 ? null
                : CharOperation.subarray(qualificationPattern, 0, lastDot);
        char[] enclosingSimpleNamePattern = lastDot == -1 ? qualificationPattern
                : CharOperation.subarray(qualificationPattern, lastDot + 1, qualificationPattern.length);
        int enclosingLevel = resolveLevelForType(enclosingSimpleNamePattern, enclosingQualificationPattern,
                patternTypeArguments, depth + 1, enclosingType);
        if (enclosingLevel == impossible)
            return impossible;
        if (enclosingLevel == IMPOSSIBLE_MATCH)
            return IMPOSSIBLE_MATCH;
    }
    return level;
}

From source file:com.redhat.ceylon.eclipse.core.model.loader.JDTUtils.java

License:Open Source License

public static ReferenceBinding inferTypeParametersFromSuperClass(ReferenceBinding declaringClass,
        ReferenceBinding superClass, LookupEnvironment lookupEnvironment) {
    if (superClass instanceof RawTypeBinding && declaringClass instanceof ParameterizedTypeBinding) {
        ParameterizedTypeBinding rawSuperType = (ParameterizedTypeBinding) superClass;
        ParameterizedTypeBinding declaringType = (ParameterizedTypeBinding) declaringClass;
        superClass = lookupEnvironment.createParameterizedType(rawSuperType.genericType(),
                declaringType.arguments, rawSuperType.enclosingType());
    }/*from w  ww  . j a  v a2 s. c o m*/
    return superClass;
}

From source file:com.redhat.ceylon.eclipse.core.model.mirror.JDTUtils.java

License:Open Source License

public static ReferenceBinding inferTypeParametersFromSuperClass(ReferenceBinding declaringClass,
        ReferenceBinding superClass) {//  www.ja v  a  2 s  .c  om
    if (superClass instanceof RawTypeBinding && declaringClass instanceof ParameterizedTypeBinding) {
        LookupEnvironment lookupEnvironment = superClass.getPackage().environment;
        ParameterizedTypeBinding rawSuperType = (ParameterizedTypeBinding) superClass;
        ParameterizedTypeBinding declaringType = (ParameterizedTypeBinding) declaringClass;
        superClass = lookupEnvironment.createParameterizedType(rawSuperType.genericType(),
                declaringType.arguments, rawSuperType.enclosingType());
    }
    return superClass;
}

From source file:org.eclipse.che.jdt.internal.core.search.matching.PatternLocator.java

License:Open Source License

protected void updateMatch(ParameterizedTypeBinding parameterizedBinding, char[][][] patternTypeArguments,
        boolean patternHasTypeParameters, int depth, MatchLocator locator) {
    // Only possible if locator has an unit scope.
    if (locator.unitScope == null)
        return;/*from  w  w  w . j  ava2s  . c om*/

    // Set match raw flag
    boolean endPattern = patternTypeArguments == null ? true : depth >= patternTypeArguments.length;
    TypeBinding[] argumentsBindings = parameterizedBinding.arguments;
    boolean isRaw = parameterizedBinding.isRawType()
            || (argumentsBindings == null && parameterizedBinding.genericType().isGenericType());
    if (isRaw && !this.match.isRaw()) {
        this.match.setRaw(isRaw);
    }

    // Update match
    if (!endPattern && patternTypeArguments != null) {
        // verify if this is a reference to the generic type itself
        if (!isRaw && patternHasTypeParameters && argumentsBindings != null) {
            boolean needUpdate = false;
            TypeVariableBinding[] typeVariables = parameterizedBinding.genericType().typeVariables();
            int length = argumentsBindings.length;
            if (length == typeVariables.length) {
                for (int i = 0; i < length; i++) {
                    if (TypeBinding.notEquals(argumentsBindings[i], typeVariables[i])) {
                        needUpdate = true;
                        break;
                    }
                }
            }
            if (needUpdate) {
                char[][] patternArguments = patternTypeArguments[depth];
                updateMatch(argumentsBindings, locator, patternArguments, patternHasTypeParameters);
            }
        } else {
            char[][] patternArguments = patternTypeArguments[depth];
            updateMatch(argumentsBindings, locator, patternArguments, patternHasTypeParameters);
        }
    }

    // Recurse
    TypeBinding enclosingType = parameterizedBinding.enclosingType();
    if (enclosingType != null && (enclosingType.isParameterizedType() || enclosingType.isRawType())) {
        updateMatch((ParameterizedTypeBinding) enclosingType, patternTypeArguments, patternHasTypeParameters,
                depth + 1, locator);
    }
}

From source file:org.eclipse.jdt.internal.compiler.lookup.Scope.java

License:Open Source License

/**
 * Returns a type where either all variables or specific ones got discarded.
 * e.g. List<E> (discarding <E extends Enum<E>) will return:  List<? extends Enum<?>>
 *//*from w  w  w.j a  va  2  s.c om*/
public static TypeBinding convertEliminatingTypeVariables(TypeBinding originalType,
        ReferenceBinding genericType, int rank, Set eliminatedVariables) {
    if ((originalType.tagBits & TagBits.HasTypeVariable) != 0) {
        switch (originalType.kind()) {
        case Binding.ARRAY_TYPE:
            ArrayBinding originalArrayType = (ArrayBinding) originalType;
            TypeBinding originalLeafComponentType = originalArrayType.leafComponentType;
            TypeBinding substitute = convertEliminatingTypeVariables(originalLeafComponentType, genericType,
                    rank, eliminatedVariables); // substitute could itself be array type
            if (substitute != originalLeafComponentType) {
                return originalArrayType.environment.createArrayType(substitute.leafComponentType(),
                        substitute.dimensions() + originalArrayType.dimensions());
            }
            break;
        case Binding.PARAMETERIZED_TYPE:
            ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) originalType;
            ReferenceBinding originalEnclosing = paramType.enclosingType();
            ReferenceBinding substitutedEnclosing = originalEnclosing;
            if (originalEnclosing != null) {
                substitutedEnclosing = (ReferenceBinding) convertEliminatingTypeVariables(originalEnclosing,
                        genericType, rank, eliminatedVariables);
            }
            TypeBinding[] originalArguments = paramType.arguments;
            TypeBinding[] substitutedArguments = originalArguments;
            for (int i = 0, length = originalArguments == null ? 0
                    : originalArguments.length; i < length; i++) {
                TypeBinding originalArgument = originalArguments[i];
                TypeBinding substitutedArgument = convertEliminatingTypeVariables(originalArgument,
                        paramType.genericType(), i, eliminatedVariables);
                if (substitutedArgument != originalArgument) {
                    if (substitutedArguments == originalArguments) {
                        System.arraycopy(originalArguments, 0, substitutedArguments = new TypeBinding[length],
                                0, i);
                    }
                    substitutedArguments[i] = substitutedArgument;
                } else if (substitutedArguments != originalArguments) {
                    substitutedArguments[i] = originalArgument;
                }
            }
            if (originalEnclosing != substitutedEnclosing || originalArguments != substitutedArguments) {
                return paramType.environment.createParameterizedType(paramType.genericType(),
                        substitutedArguments, substitutedEnclosing);
            }
            break;
        case Binding.TYPE_PARAMETER:
            if (genericType == null) {
                break;
            }
            TypeVariableBinding originalVariable = (TypeVariableBinding) originalType;
            if (eliminatedVariables != null && eliminatedVariables.contains(originalType)) {
                return originalVariable.environment.createWildcard(genericType, rank, null, null,
                        Wildcard.UNBOUND);
            }
            TypeBinding originalUpperBound = originalVariable.upperBound();
            if (eliminatedVariables == null) {
                eliminatedVariables = new HashSet(2);
            }
            eliminatedVariables.add(originalVariable);
            TypeBinding substitutedUpperBound = convertEliminatingTypeVariables(originalUpperBound, genericType,
                    rank, eliminatedVariables);
            eliminatedVariables.remove(originalVariable);
            return originalVariable.environment.createWildcard(genericType, rank, substitutedUpperBound, null,
                    Wildcard.EXTENDS);
        case Binding.RAW_TYPE:
            break;
        case Binding.GENERIC_TYPE:
            ReferenceBinding currentType = (ReferenceBinding) originalType;
            originalEnclosing = currentType.enclosingType();
            substitutedEnclosing = originalEnclosing;
            if (originalEnclosing != null) {
                substitutedEnclosing = (ReferenceBinding) convertEliminatingTypeVariables(originalEnclosing,
                        genericType, rank, eliminatedVariables);
            }
            originalArguments = currentType.typeVariables();
            substitutedArguments = originalArguments;
            for (int i = 0, length = originalArguments == null ? 0
                    : originalArguments.length; i < length; i++) {
                TypeBinding originalArgument = originalArguments[i];
                TypeBinding substitutedArgument = convertEliminatingTypeVariables(originalArgument, currentType,
                        i, eliminatedVariables);
                if (substitutedArgument != originalArgument) {
                    if (substitutedArguments == originalArguments) {
                        System.arraycopy(originalArguments, 0, substitutedArguments = new TypeBinding[length],
                                0, i);
                    }
                    substitutedArguments[i] = substitutedArgument;
                } else if (substitutedArguments != originalArguments) {
                    substitutedArguments[i] = originalArgument;
                }
            }
            if (originalEnclosing != substitutedEnclosing || originalArguments != substitutedArguments) {
                return ((TypeVariableBinding) originalArguments[0]).environment
                        .createParameterizedType(genericType, substitutedArguments, substitutedEnclosing);
            }
            break;
        case Binding.WILDCARD_TYPE:
            WildcardBinding wildcard = (WildcardBinding) originalType;
            TypeBinding originalBound = wildcard.bound;
            TypeBinding substitutedBound = originalBound;
            if (originalBound != null) {
                substitutedBound = convertEliminatingTypeVariables(originalBound, genericType, rank,
                        eliminatedVariables);
                if (substitutedBound != originalBound) {
                    return wildcard.environment.createWildcard(wildcard.genericType, wildcard.rank,
                            substitutedBound, null, wildcard.boundKind);
                }
            }
            break;
        case Binding.INTERSECTION_TYPE:
            WildcardBinding intersection = (WildcardBinding) originalType;
            originalBound = intersection.bound;
            substitutedBound = originalBound;
            if (originalBound != null) {
                substitutedBound = convertEliminatingTypeVariables(originalBound, genericType, rank,
                        eliminatedVariables);
            }
            TypeBinding[] originalOtherBounds = intersection.otherBounds;
            TypeBinding[] substitutedOtherBounds = originalOtherBounds;
            for (int i = 0, length = originalOtherBounds == null ? 0
                    : originalOtherBounds.length; i < length; i++) {
                TypeBinding originalOtherBound = originalOtherBounds[i];
                TypeBinding substitutedOtherBound = convertEliminatingTypeVariables(originalOtherBound,
                        genericType, rank, eliminatedVariables);
                if (substitutedOtherBound != originalOtherBound) {
                    if (substitutedOtherBounds == originalOtherBounds) {
                        System.arraycopy(originalOtherBounds, 0,
                                substitutedOtherBounds = new TypeBinding[length], 0, i);
                    }
                    substitutedOtherBounds[i] = substitutedOtherBound;
                } else if (substitutedOtherBounds != originalOtherBounds) {
                    substitutedOtherBounds[i] = originalOtherBound;
                }
            }
            if (substitutedBound != originalBound || substitutedOtherBounds != originalOtherBounds) {
                return intersection.environment.createWildcard(intersection.genericType, intersection.rank,
                        substitutedBound, substitutedOtherBounds, intersection.boundKind);
            }
            break;
        }
    }
    return originalType;
}

From source file:org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.java

License:Open Source License

/**
 * Returns true if a type is identical to another one,
 * or for generic types, true if compared to its raw type.
 *//* www  .ja  va  2 s  .c  o  m*/
public boolean isEquivalentTo(TypeBinding otherType) {

    if (this == otherType)
        return true;
    if (otherType == null)
        return false;
    switch (otherType.kind()) {

    case Binding.WILDCARD_TYPE:
    case Binding.INTERSECTION_TYPE:
        return ((WildcardBinding) otherType).boundCheck(this);

    case Binding.PARAMETERIZED_TYPE:
        if ((otherType.tagBits & TagBits.HasDirectWildcard) == 0
                && (!isMemberType() || !otherType.isMemberType()))
            return false; // should have been identical
        ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
        if (this != otherParamType.genericType())
            return false;
        if (!isStatic()) { // static member types do not compare their enclosing
            ReferenceBinding enclosing = enclosingType();
            if (enclosing != null) {
                ReferenceBinding otherEnclosing = otherParamType.enclosingType();
                if (otherEnclosing == null)
                    return false;
                if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) {
                    if (enclosing != otherEnclosing)
                        return false;
                } else {
                    if (!enclosing.isEquivalentTo(otherParamType.enclosingType()))
                        return false;
                }
            }
        }
        int length = this.typeVariables == null ? 0 : this.typeVariables.length;
        TypeBinding[] otherArguments = otherParamType.arguments;
        int otherLength = otherArguments == null ? 0 : otherArguments.length;
        if (otherLength != length)
            return false;
        for (int i = 0; i < length; i++)
            if (!this.typeVariables[i].isTypeArgumentContainedBy(otherArguments[i]))
                return false;
        return true;

    case Binding.RAW_TYPE:
        return otherType.erasure() == this;
    }
    return false;
}

From source file:org.eclipse.objectteams.otdt.internal.core.compiler.mappings.MethodMappingImplementor.java

License:Open Source License

/** If original is a type variable or contains a type variable replace that type variable
 *  with a corresponding type variable from variables.
 *  This method is used to adjust the scope of type variables that originally were
 *  resolved in the method mappings scope, but should be resolved in the wrapper method scope.
 *///w w  w  . j av  a  2  s .  co m
TypeBinding substituteVariables(TypeBinding original, TypeVariableBinding[] variables) {
    if (original.isTypeVariable()) {
        for (int i = 0; i < variables.length; i++)
            if (CharOperation.equals(original.internalName(), variables[i].sourceName))
                return variables[i];
    } else if (original.isParameterizedType()) {
        ParameterizedTypeBinding pt = (ParameterizedTypeBinding) original;
        TypeBinding[] args = pt.arguments;
        if (args != null) {
            int l = args.length;
            System.arraycopy(args, 0, args = new TypeBinding[l], 0, l);
            boolean changed = false;
            for (int i = 0; i < l; i++) {
                TypeBinding tb = substituteVariables(args[i], variables);
                if (TypeBinding.notEquals(tb, args[i])) {
                    args[i] = tb;
                    changed = true;
                }
            }
            if (changed)
                return new ParameterizedTypeBinding((ReferenceBinding) pt.erasure(), args, pt.enclosingType(),
                        pt.environment);
        }
    }
    return original;
}