Logo Search packages:      
Sourcecode: ecj version File versions

ParameterizedTypeBinding.java

/*******************************************************************************
 * Copyright (c) 2005, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;

import java.util.Map;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;

/**
 * A parameterized type encapsulates a type with type arguments,
 */
00021 public class ParameterizedTypeBinding extends ReferenceBinding implements Substitution {

      public ReferenceBinding type; 
      public TypeBinding[] arguments;
      public LookupEnvironment environment; 
      public char[] genericTypeSignature;
      public ReferenceBinding superclass;
      public ReferenceBinding[] superInterfaces;      
      public FieldBinding[] fields; 
      public ReferenceBinding[] memberTypes;
      public MethodBinding[] methods;
      private ReferenceBinding enclosingType;
      
      public ParameterizedTypeBinding(ReferenceBinding type, TypeBinding[] arguments,  ReferenceBinding enclosingType, LookupEnvironment environment){

            this.environment = environment;
            this.enclosingType = enclosingType; // never unresolved, never lazy per construction
//          if (enclosingType != null && enclosingType.isGenericType()) {
//                RuntimeException e = new RuntimeException("PARAM TYPE with GENERIC ENCLOSING");
//                e.printStackTrace();
//                throw e;
//          }
            initialize(type, arguments);
            if (type instanceof UnresolvedReferenceBinding)
                  ((UnresolvedReferenceBinding) type).addWrapper(this);
            if (arguments != null) {
                  for (int i = 0, l = arguments.length; i < l; i++)
                        if (arguments[i] instanceof UnresolvedReferenceBinding)
                              ((UnresolvedReferenceBinding) arguments[i]).addWrapper(this);
            }
            this.tagBits |=  TagBits.HasUnresolvedTypeVariables; // cleared in resolve()
      }

      /**
       * Iterate type arguments, and validate them according to corresponding variable bounds.
       */
00057       public void boundCheck(Scope scope, TypeReference[] argumentReferences) {
            if ((this.tagBits & TagBits.PassedBoundCheck) == 0) {
                  boolean hasErrors = false;
                  TypeVariableBinding[] typeVariables = this.type.typeVariables();
                  if (this.arguments != null && typeVariables != null) { // arguments may be null in error cases
                        for (int i = 0, length = typeVariables.length; i < length; i++) {
                            if (typeVariables[i].boundCheck(this, this.arguments[i])  != TypeConstants.OK) {
                              hasErrors = true;
                                    scope.problemReporter().typeMismatchError(this.arguments[i], typeVariables[i], this.type, argumentReferences[i]);
                            }
                        }
                  }     
                  if (!hasErrors) this.tagBits |= TagBits.PassedBoundCheck; // no need to recheck it in the future
            }
      }
      
      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#canBeInstantiated()
       */
00076       public boolean canBeInstantiated() {
            return ((this.tagBits & TagBits.HasDirectWildcard) == 0) && super.canBeInstantiated(); // cannot instantiate param type with wildcard arguments
      }
      public int kind() {
            return PARAMETERIZED_TYPE;
      }     
      /**
       * Perform capture conversion for a parameterized type with wildcard arguments
       * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#capture(Scope,int)
       */
00086       public TypeBinding capture(Scope scope, int position) {
            if ((this.tagBits & TagBits.HasDirectWildcard) == 0) 
                  return this;
            
            TypeBinding[] originalArguments = arguments;
            int length = originalArguments.length;
            TypeBinding[] capturedArguments = new TypeBinding[length];
            
            // Retrieve the type context for capture bindingKey
            ReferenceBinding contextType = scope.enclosingSourceType();
            if (contextType != null) contextType = contextType.outermostEnclosingType(); // maybe null when used programmatically by DOM
            
            for (int i = 0; i < length; i++) {
                  TypeBinding argument = originalArguments[i];
                  if (argument.kind() == Binding.WILDCARD_TYPE && ((WildcardBinding)argument).otherBounds == null) { // no capture for intersection types
                        capturedArguments[i] = new CaptureBinding((WildcardBinding) argument, contextType, position);
                  } else {
                        capturedArguments[i] = argument;
                  }
            }
            ParameterizedTypeBinding capturedParameterizedType = this.environment.createParameterizedType(this.type, capturedArguments, enclosingType());
            for (int i = 0; i < length; i++) {
                  TypeBinding argument = capturedArguments[i];
                  if (argument.isCapture()) {
                        ((CaptureBinding)argument).initializeBounds(scope, capturedParameterizedType);
                  }
            }
            return capturedParameterizedType;
      }
      /**
       * Collect the substitutes into a map for certain type variables inside the receiver type
       * e.g.   Collection<T>.collectSubstitutes(Collection<List<X>>, Map), will populate Map with: T --> List<X>
       * Constraints:
       *   A << F   corresponds to:   F.collectSubstitutes(..., A, ..., 1)
       *   A = F   corresponds to:      F.collectSubstitutes(..., A, ..., 0)
       *   A >> F   corresponds to:   F.collectSubstitutes(..., A, ..., 2)
       */
00123       public void collectSubstitutes(Scope scope, TypeBinding actualType, Map substitutes, int constraint) {
            
            if ((this.tagBits & TagBits.HasTypeVariable) == 0) return;
            if (actualType == TypeBinding.NULL) return;
      
            if (!(actualType instanceof ReferenceBinding)) return;
            TypeBinding formalEquivalent, actualEquivalent;
            switch (constraint) {
                  case TypeConstants.CONSTRAINT_EQUAL :
                  case TypeConstants.CONSTRAINT_EXTENDS :
                        formalEquivalent = this;
                    actualEquivalent = actualType.findSuperTypeWithSameErasure(this.type);
                    if (actualEquivalent == null) return;
                    break;
                  case TypeConstants.CONSTRAINT_SUPER :
              default:
                    formalEquivalent = this.findSuperTypeWithSameErasure(actualType);
                    if (formalEquivalent == null) return;
                    actualEquivalent = actualType;
                    break;
            }
            // collect through enclosing type
            ReferenceBinding formalEnclosingType = formalEquivalent.enclosingType();
            if (formalEnclosingType != null) {
                  formalEnclosingType.collectSubstitutes(scope, actualEquivalent.enclosingType(), substitutes, constraint);
            }
            // collect through type arguments
            if (this.arguments == null) return;
        TypeBinding[] formalArguments;
        switch (formalEquivalent.kind()) {
            case Binding.GENERIC_TYPE :
                  formalArguments = formalEquivalent.typeVariables();
                  break;
            case Binding.PARAMETERIZED_TYPE :
                  formalArguments = ((ParameterizedTypeBinding)formalEquivalent).arguments;
                  break;
            case Binding.RAW_TYPE :
                  substitutes.clear(); // clear all variables to indicate raw generic method in the end
                  return;
            default :
                  return;
        }
        TypeBinding[] actualArguments;
        switch (actualEquivalent.kind()) {
            case Binding.GENERIC_TYPE :
                  actualArguments = actualEquivalent.typeVariables();
                  break;
            case Binding.PARAMETERIZED_TYPE :
                  actualArguments = ((ParameterizedTypeBinding)actualEquivalent).arguments;
                  break;
            case Binding.RAW_TYPE :
                  substitutes.clear(); // clear all variables to indicate raw generic method in the end
                  if (constraint == TypeConstants.CONSTRAINT_EQUAL) {
                        substitutes.put(TypeBinding.VOID, Binding.NO_TYPES); // marker for impossible inference
                  }
                  return;
            default :
                  return;
        }
        for (int i = 0, length = formalArguments.length; i < length; i++) {
            TypeBinding formalArgument = formalArguments[i];
            TypeBinding actualArgument = actualArguments[i];
            if (formalArgument.isWildcard()) {
                formalArgument.collectSubstitutes(scope, actualArgument, substitutes, constraint);
                continue;
            } else if (actualArgument.isWildcard()){
                  WildcardBinding actualWildcardArgument = (WildcardBinding) actualArgument;
                  if (actualWildcardArgument.otherBounds == null) {
                        if (constraint == TypeConstants.CONSTRAINT_SUPER) { // JLS 15.12.7, p.459
                                    switch(actualWildcardArgument.boundKind) {
                                    case Wildcard.EXTENDS :
                                          formalArgument.collectSubstitutes(scope, actualWildcardArgument.bound, substitutes, TypeConstants.CONSTRAINT_SUPER);
                                          continue;
                                    case Wildcard.SUPER :
                                          formalArgument.collectSubstitutes(scope, actualWildcardArgument.bound, substitutes, TypeConstants.CONSTRAINT_EXTENDS);
                                          continue;
                                    default :
                                          continue; // cannot infer anything further from unbound wildcard
                              }
                        } else {
                              continue; // cannot infer anything further from wildcard
                        }
                  }
            }
            // by default, use EQUAL constraint
            formalArgument.collectSubstitutes(scope, actualArgument, substitutes, TypeConstants.CONSTRAINT_EQUAL);
        }
      }
      
      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#computeId()
       */
00215       public void computeId() {
            this.id = TypeIds.NoId;       
      }
      
      public char[] computeUniqueKey(boolean isLeaf) {
          StringBuffer sig = new StringBuffer(10);
          ReferenceBinding enclosing;
            if (isMemberType() && ((enclosing = enclosingType()).isParameterizedType() || enclosing.isRawType())) {
                char[] typeSig = enclosing.computeUniqueKey(false/*not a leaf*/);
                for (int i = 0; i < typeSig.length-1; i++) sig.append(typeSig[i]); // copy all but trailing semicolon
                sig.append('.').append(sourceName());
            } else if(this.type.isLocalType()){
                  LocalTypeBinding localTypeBinding = (LocalTypeBinding) this.type;
                  enclosing = localTypeBinding.enclosingType();
                  ReferenceBinding temp;
                  while ((temp = enclosing.enclosingType()) != null)
                        enclosing = temp;
                  char[] typeSig = enclosing.computeUniqueKey(false/*not a leaf*/);
                for (int i = 0; i < typeSig.length-1; i++) sig.append(typeSig[i]); // copy all but trailing semicolon
                  sig.append('$');
                  sig.append(localTypeBinding.sourceStart);
            } else {
                char[] typeSig = this.type.computeUniqueKey(false/*not a leaf*/);
                for (int i = 0; i < typeSig.length-1; i++) sig.append(typeSig[i]); // copy all but trailing semicolon
            }
            ReferenceBinding captureSourceType = null;
            if (this.arguments != null) {
                sig.append('<');
                for (int i = 0, length = this.arguments.length; i < length; i++) {
                  TypeBinding typeBinding = this.arguments[i];
                    sig.append(typeBinding.computeUniqueKey(false/*not a leaf*/));
                    if (typeBinding instanceof CaptureBinding)
                        captureSourceType = ((CaptureBinding) typeBinding).sourceType;
                }
                sig.append('>');
            }
            sig.append(';');
            if (captureSourceType != null && captureSourceType != this.type) {
                  // contains a capture binding
                  sig.insert(0, "&"); //$NON-NLS-1$
                  sig.insert(0, captureSourceType.computeUniqueKey(false/*not a leaf*/));
            }
      
            int sigLength = sig.length();
            char[] uniqueKey = new char[sigLength];
            sig.getChars(0, sigLength, uniqueKey, 0);             
            return uniqueKey;
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#constantPoolName()
       */
00267       public char[] constantPoolName() {
            return this.type.constantPoolName(); // erasure
      }

      public ParameterizedMethodBinding createParameterizedMethod(MethodBinding originalMethod) {
            return new ParameterizedMethodBinding(this, originalMethod);
      }
      
      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#debugName()
       */
00278       public String debugName() {
          StringBuffer nameBuffer = new StringBuffer(10);
            nameBuffer.append(this.type.sourceName());
            if (this.arguments != null) {
                  nameBuffer.append('<');
                for (int i = 0, length = this.arguments.length; i < length; i++) {
                    if (i > 0) nameBuffer.append(',');
                    nameBuffer.append(this.arguments[i].debugName());
                }
                nameBuffer.append('>');
            }
          return nameBuffer.toString();         
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#enclosingType()
       */
00295       public ReferenceBinding enclosingType() {
          return this.enclosingType;
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.Substitution#environment()
       */
00302       public LookupEnvironment environment() {
            return this.environment;
      }
      
      /**
     * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#erasure()
     */
00309     public TypeBinding erasure() {
        return this.type.erasure(); // erasure
    }
      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#fieldCount()
       */
00315       public int fieldCount() {
            return this.type.fieldCount(); // same as erasure (lazy)
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#fields()
       */
00322       public FieldBinding[] fields() {
            if ((tagBits & TagBits.AreFieldsComplete) != 0)
                  return this.fields;

            try {
                  FieldBinding[] originalFields = this.type.fields();
                  int length = originalFields.length;
                  FieldBinding[] parameterizedFields = new FieldBinding[length];
                  for (int i = 0; i < length; i++)
                        // substitute all fields, so as to get updated declaring class at least
                        parameterizedFields[i] = new ParameterizedFieldBinding(this, originalFields[i]);
                  this.fields = parameterizedFields;      
            } finally {
                  // if the original fields cannot be retrieved (ex. AbortCompilation), then assume we do not have any fields
                  if (this.fields == null) 
                        this.fields = Binding.NO_FIELDS;
                  tagBits |= TagBits.AreFieldsComplete;
            }
            return this.fields;
      }

      /**
       * Ltype<param1 ... paramN>;
       * LY<TT;>;
       */
00347       public char[] genericTypeSignature() {
          if (this.genericTypeSignature == null) {
                StringBuffer sig = new StringBuffer(10);
                  if (this.isMemberType() && this.enclosingType().isParameterizedType()) {
                      char[] typeSig = this.enclosingType().genericTypeSignature();
                      for (int i = 0; i < typeSig.length-1; i++) sig.append(typeSig[i]); // copy all but trailing semicolon
                      sig.append('.').append(this.sourceName());
                  } else {
                      char[] typeSig = this.type.signature();
                      for (int i = 0; i < typeSig.length-1; i++) sig.append(typeSig[i]); // copy all but trailing semicolon
                  }               
                  if (this.arguments != null) {
                      sig.append('<');
                      for (int i = 0, length = this.arguments.length; i < length; i++) {
                          sig.append(this.arguments[i].genericTypeSignature());
                      }
                      sig.append('>');
                  }
                  sig.append(';');
                  int sigLength = sig.length();
                  this.genericTypeSignature = new char[sigLength];
                  sig.getChars(0, sigLength, this.genericTypeSignature, 0);               
          }
            return this.genericTypeSignature;       
      }     

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#getAnnotationTagBits()
       */
00376       public long getAnnotationTagBits() {
            return this.type.getAnnotationTagBits();
      }
      
      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#getExactConstructor(TypeBinding[])
       */
00383       public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
            int argCount = argumentTypes.length;

            if ((tagBits & TagBits.AreMethodsComplete) != 0) { // have resolved all arg types & return type of the methods
                  long range;
                  if ((range = ReferenceBinding.binarySearch(TypeConstants.INIT, this.methods)) >= 0) {
                        nextMethod: for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {
                              MethodBinding method = methods[imethod];
                              if (method.parameters.length == argCount) {
                                    TypeBinding[] toMatch = method.parameters;
                                    for (int iarg = 0; iarg < argCount; iarg++)
                                          if (toMatch[iarg] != argumentTypes[iarg])
                                                continue nextMethod;
                                    return method;
                              }
                        }
                  }
            } else {
                  MethodBinding[] matchingMethods = getMethods(TypeConstants.INIT); // takes care of duplicates & default abstract methods
                  nextMethod : for (int m = matchingMethods.length; --m >= 0;) {
                        MethodBinding method = matchingMethods[m];
                        TypeBinding[] toMatch = method.parameters;
                        if (toMatch.length == argCount) {
                              for (int p = 0; p < argCount; p++)
                                    if (toMatch[p] != argumentTypes[p])
                                          continue nextMethod;
                                    return method;
                        }
                  }
            }
            return null;
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#getExactMethod(char[], TypeBinding[],CompilationUnitScope)
       */
00419       public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes, CompilationUnitScope refScope) {
            // sender from refScope calls recordTypeReference(this)
            int argCount = argumentTypes.length;
            boolean foundNothing = true;
            MethodBinding match = null;

            if ((tagBits & TagBits.AreMethodsComplete) != 0) { // have resolved all arg types & return type of the methods
                  long range;
                  if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {
                        nextMethod: for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {
                              MethodBinding method = methods[imethod];
                              foundNothing = false; // inner type lookups must know that a method with this name exists
                              if (method.parameters.length == argCount) {
                                    TypeBinding[] toMatch = method.parameters;
                                    for (int iarg = 0; iarg < argCount; iarg++)
                                          if (toMatch[iarg] != argumentTypes[iarg])
                                                continue nextMethod;
                                    if (match != null) return null; // collision case
                                    match = method;
                              }
                        }
                  }
            } else {
                  MethodBinding[] matchingMethods = getMethods(selector); // takes care of duplicates & default abstract methods
                  foundNothing = matchingMethods == Binding.NO_METHODS;
                  nextMethod : for (int m = matchingMethods.length; --m >= 0;) {
                        MethodBinding method = matchingMethods[m];
                        TypeBinding[] toMatch = method.parameters;
                        if (toMatch.length == argCount) {
                              for (int p = 0; p < argCount; p++)
                                    if (toMatch[p] != argumentTypes[p])
                                          continue nextMethod;
                                    if (match != null) return null; // collision case
                                    match = method;
                        }
                  }
            }
            if (match != null) {
                  // cannot be picked up as an exact match if its a possible anonymous case, such as:
                  // class A<T extends Number> { public void id(T t) {} }
                  // class B<TT> extends A<Integer> { public <ZZ> void id(Integer i) {} }
                  if (match.hasSubstitutedParameters()) return null;
                  return match;
            }
      
            if (foundNothing && (this.arguments == null || this.arguments.length <= 1)) {
                  if (isInterface()) {
                         if (superInterfaces().length == 1) {
                              if (refScope != null)
                                    refScope.recordTypeReference(superInterfaces[0]);
                              return superInterfaces[0].getExactMethod(selector, argumentTypes, refScope);
                         }
                  } else if (superclass() != null) {
                        if (refScope != null)
                              refScope.recordTypeReference(superclass);
                        return superclass.getExactMethod(selector, argumentTypes, refScope);
                  }
            }
            return null;
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#getField(char[], boolean)
       */
00483       public FieldBinding getField(char[] fieldName, boolean needResolve) {
            fields(); // ensure fields have been initialized... must create all at once unlike methods
            return ReferenceBinding.binarySearch(fieldName, this.fields);
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#getMemberType(char[])
       */
00491       public ReferenceBinding getMemberType(char[] typeName) {
            memberTypes(); // ensure memberTypes have been initialized... must create all at once unlike methods
            int typeLength = typeName.length;
            for (int i = this.memberTypes.length; --i >= 0;) {
                  ReferenceBinding memberType = this.memberTypes[i];
                  if (memberType.sourceName.length == typeLength && CharOperation.equals(memberType.sourceName, typeName))
                        return memberType;
            }
            return null;
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#getMethods(char[])
       */
00505       public MethodBinding[] getMethods(char[] selector) {
            if (this.methods != null) {
                  long range;
                  if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {
                        int start = (int) range;
                        int length = (int) (range >> 32) - start + 1;
                        // cannot optimize since some clients rely on clone array
                        // if (start == 0 && length == this.methods.length) 
                        //    return this.methods; // current set is already interesting subset
                        MethodBinding[] result;
                        System.arraycopy(this.methods, start, result = new MethodBinding[length], 0, length);
                        return result;
                  }
            }
            if ((tagBits & TagBits.AreMethodsComplete) != 0)
                  return Binding.NO_METHODS; // have created all the methods and there are no matches

            MethodBinding[] parameterizedMethods = null;
            try {
                MethodBinding[] originalMethods = this.type.getMethods(selector);
                int length = originalMethods.length;
                if (length == 0) return Binding.NO_METHODS; 

                parameterizedMethods = new MethodBinding[length];
                for (int i = 0; i < length; i++)
                  // substitute methods, so as to get updated declaring class at least
                  parameterizedMethods[i] = createParameterizedMethod(originalMethods[i]);
                if (this.methods == null) {
                        MethodBinding[] temp = new MethodBinding[length];
                        System.arraycopy(parameterizedMethods, 0, temp, 0, length);
                        this.methods = temp; // must be a copy of parameterizedMethods since it will be returned below
                } else {
                        int total = length + this.methods.length;
                        MethodBinding[] temp = new MethodBinding[total];
                        System.arraycopy(parameterizedMethods, 0, temp, 0, length);
                        System.arraycopy(this.methods, 0, temp, length, this.methods.length);
                        if (total > 1)
                              ReferenceBinding.sortMethods(temp, 0, total); // resort to ensure order is good
                        this.methods = temp;
                  }
                return parameterizedMethods;
            } finally {
                  // if the original methods cannot be retrieved (ex. AbortCompilation), then assume we do not have any methods
                if (parameterizedMethods == null) 
                    this.methods = parameterizedMethods = Binding.NO_METHODS;
            }
      }

      public boolean hasMemberTypes() {
          return this.type.hasMemberTypes();
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#implementsMethod(MethodBinding)
       */
00560       public boolean implementsMethod(MethodBinding method) {
            return this.type.implementsMethod(method); // erasure
      }

      void initialize(ReferenceBinding someType, TypeBinding[] someArguments) {
            this.type = someType;
            this.sourceName = someType.sourceName;
            this.compoundName = someType.compoundName;
            this.fPackage = someType.fPackage;
            this.fileName = someType.fileName;
            // should not be set yet
            // this.superclass = null;
            // this.superInterfaces = null;
            // this.fields = null;
            // this.methods = null;       
            this.modifiers = someType.modifiers & ~ExtraCompilerModifiers.AccGenericSignature; // discard generic signature, will compute later
            // only set AccGenericSignature if parameterized or have enclosing type required signature
            if (someArguments != null) {
                  this.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
            } else if (this.enclosingType != null) {
                  this.modifiers |= (this.enclosingType.modifiers & ExtraCompilerModifiers.AccGenericSignature);
                  this.tagBits |= this.enclosingType.tagBits & TagBits.HasTypeVariable;
            }
            if (someArguments != null) {
                  this.arguments = someArguments;
                  for (int i = 0, length = someArguments.length; i < length; i++) {
                        TypeBinding someArgument = someArguments[i];
                        boolean isWildcardArgument = someArgument.isWildcard();
                        if (isWildcardArgument) {
                              this.tagBits |= TagBits.HasDirectWildcard;
                        }
                        if (!isWildcardArgument || ((WildcardBinding) someArgument).boundKind != Wildcard.UNBOUND) {
                              this.tagBits |= TagBits.IsBoundParameterizedType;
                        }
                      this.tagBits |= someArgument.tagBits & TagBits.HasTypeVariable;
                  }
            }         
            this.tagBits |= someType.tagBits & (TagBits.IsLocalType| TagBits.IsMemberType | TagBits.IsNestedType);
            this.tagBits &= ~(TagBits.AreFieldsComplete|TagBits.AreMethodsComplete);
      }

      protected void initializeArguments() {
          // do nothing for true parameterized types (only for raw types)
      }
      
      public boolean isEquivalentTo(TypeBinding otherType) {
            if (this == otherType) 
                return true;
          if (otherType == null) 
              return false;
          switch(otherType.kind()) {
      
            case Binding.WILDCARD_TYPE :
                  return ((WildcardBinding) otherType).boundCheck(this);
                  
            case Binding.PARAMETERIZED_TYPE :
                  ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
                  if (this.type != otherParamType.type) 
                      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;
                              }
                        }
                  }
                  if (this.arguments == null) {
                        return otherParamType.arguments == null;
                  }
                  int length = this.arguments.length;
                  TypeBinding[] otherArguments = otherParamType.arguments;
                  if (otherArguments == null || otherArguments.length != length) return false;
                  for (int i = 0; i < length; i++) {
                        if (!this.arguments[i].isTypeArgumentContainedBy(otherArguments[i]))
                              return false;
                  }
                  return true;
            
            case Binding.RAW_TYPE :
                  return erasure() == otherType.erasure();
          }
        return false;
      }

      public boolean isIntersectingWith(TypeBinding otherType) {
            if (this == otherType) 
                return true;
          if (otherType == null) 
              return false;
          switch(otherType.kind()) {
      
            case Binding.PARAMETERIZED_TYPE :
                  ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
                  if (this.type != otherParamType.type) 
                      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.arguments == null ? 0 : this.arguments.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.arguments[i].isTypeArgumentIntersecting(otherArguments[i]))
                              return false;
                  }
                  return true;

            case Binding.GENERIC_TYPE :
                  SourceTypeBinding otherGenericType = (SourceTypeBinding) otherType;
                  if (this.type != otherGenericType) 
                      return false;
                  if (!isStatic()) { // static member types do not compare their enclosing
                        ReferenceBinding enclosing = enclosingType();
                        if (enclosing != null) {
                              ReferenceBinding otherEnclosing = otherGenericType.enclosingType();
                              if (otherEnclosing == null) return false;
                              if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) {
                                          if (enclosing != otherEnclosing) return false;
                              } else {
                                    if (!enclosing.isEquivalentTo(otherGenericType.enclosingType())) return false;
                              }
                        }
                  }
                  length = this.arguments == null ? 0 : this.arguments.length;
                  otherArguments = otherGenericType.typeVariables();
                  otherLength = otherArguments == null ? 0 : otherArguments.length;
                  if (otherLength != length) 
                      return false;
                  for (int i = 0; i < length; i++) {
                        if (!this.arguments[i].isTypeArgumentIntersecting(otherArguments[i]))
                              return false;
                  }
                  return true;
                  
            case Binding.RAW_TYPE :
                  return erasure() == otherType.erasure();
          }
        return false;
      }
      
      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isParameterizedType()
       */
00719       public boolean isParameterizedType() {
          return true;
      }
      
      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.Substitution#isRawSubstitution()
       */
00726       public boolean isRawSubstitution() {
            return isRawType();
      }
      
      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#memberTypes()
       */
00733       public ReferenceBinding[] memberTypes() {
            if (this.memberTypes == null) {
                  try {
                        ReferenceBinding[] originalMemberTypes = this.type.memberTypes();
                        int length = originalMemberTypes.length;
                        ReferenceBinding[] parameterizedMemberTypes = new ReferenceBinding[length];
                        // boolean isRaw = this.isRawType();
                        for (int i = 0; i < length; i++)
                              // substitute all member types, so as to get updated enclosing types
                              parameterizedMemberTypes[i] = /*isRaw && originalMemberTypes[i].isGenericType()
                                    ? this.environment.createRawType(originalMemberTypes[i], this)
                                    : */ this.environment.createParameterizedType(originalMemberTypes[i], null, this);
                        this.memberTypes = parameterizedMemberTypes;        
                  } finally {
                        // if the original fields cannot be retrieved (ex. AbortCompilation), then assume we do not have any fields
                        if (this.memberTypes == null) 
                              this.memberTypes = Binding.NO_MEMBER_TYPES;
                  }
            }
            return this.memberTypes;
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#methods()
       */
00758       public MethodBinding[] methods() {
            if ((tagBits & TagBits.AreMethodsComplete) != 0)
                  return this.methods;

            try {
                MethodBinding[] originalMethods = this.type.methods();
                int length = originalMethods.length;
                MethodBinding[] parameterizedMethods = new MethodBinding[length];
                for (int i = 0; i < length; i++)
                  // substitute all methods, so as to get updated declaring class at least
                  parameterizedMethods[i] = createParameterizedMethod(originalMethods[i]);
                this.methods = parameterizedMethods;
            } finally {
                  // if the original methods cannot be retrieved (ex. AbortCompilation), then assume we do not have any methods
                if (this.methods == null) 
                    this.methods = Binding.NO_METHODS;

                  tagBits |=  TagBits.AreMethodsComplete;
            }           
            return this.methods;
      }
      
      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#qualifiedSourceName()
       */
00783       public char[] qualifiedSourceName() {
            return this.type.qualifiedSourceName();
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.Binding#readableName()
       */
00790       public char[] readableName() {
          StringBuffer nameBuffer = new StringBuffer(10);
            if (this.isMemberType()) {
                  nameBuffer.append(CharOperation.concat(this.enclosingType().readableName(), sourceName, '.'));
            } else {
                  nameBuffer.append(CharOperation.concatWith(this.type.compoundName, '.'));
            }         
            if (this.arguments != null) {
                  nameBuffer.append('<');
                for (int i = 0, length = this.arguments.length; i < length; i++) {
                    if (i > 0) nameBuffer.append(',');
                    nameBuffer.append(this.arguments[i].readableName());
                }
                nameBuffer.append('>');
            }
            int nameLength = nameBuffer.length();
            char[] readableName = new char[nameLength];
            nameBuffer.getChars(0, nameLength, readableName, 0);        
          return readableName;
      }

      ReferenceBinding resolve() {
            if ((this.tagBits & TagBits.HasUnresolvedTypeVariables) == 0)
                  return this;

            this.tagBits &= ~TagBits.HasUnresolvedTypeVariables; // can be recursive so only want to call once
            ReferenceBinding resolvedType = BinaryTypeBinding.resolveType(this.type, this.environment, false); // still part of parameterized type ref
            if (this.arguments != null) {
                  int argLength = this.arguments.length;
                  for (int i = 0; i < argLength; i++)
                        BinaryTypeBinding.resolveType(this.arguments[i], this.environment, this, i);
                  // arity check
                  TypeVariableBinding[] refTypeVariables = resolvedType.typeVariables();
                  if (refTypeVariables == Binding.NO_TYPE_VARIABLES) { // check generic
                        this.environment.problemReporter.nonGenericTypeCannotBeParameterized(null, resolvedType, this.arguments);
                        return this; // cannot reach here as AbortCompilation is thrown
                  } else if (argLength != refTypeVariables.length) { // check arity
                        this.environment.problemReporter.incorrectArityForParameterizedType(null, resolvedType, this.arguments);
                        return this; // cannot reach here as AbortCompilation is thrown
                  }
                  // check argument type compatibility... REMOVED for now since incremental build will propagate change & detect in source
//                for (int i = 0; i < argLength; i++) {
//                    TypeBinding resolvedArgument = this.arguments[i];
//                      if (refTypeVariables[i].boundCheck(this, resolvedArgument) != TypeConstants.OK) {
//                            this.environment.problemReporter.typeMismatchError(resolvedArgument, refTypeVariables[i], resolvedType, null);
//                    }
//                }
            }
            return this;
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.Binding#shortReadableName()
       */
00844       public char[] shortReadableName() {
          StringBuffer nameBuffer = new StringBuffer(10);
            if (this.isMemberType()) {
                  nameBuffer.append(CharOperation.concat(this.enclosingType().shortReadableName(), sourceName, '.'));
            } else {
                  nameBuffer.append(this.type.sourceName);
            }         
            if (this.arguments != null) {
                  nameBuffer.append('<');
                for (int i = 0, length = this.arguments.length; i < length; i++) {
                    if (i > 0) nameBuffer.append(',');
                    nameBuffer.append(this.arguments[i].shortReadableName());
                }
                nameBuffer.append('>');
            }
            int nameLength = nameBuffer.length();
            char[] shortReadableName = new char[nameLength];
            nameBuffer.getChars(0, nameLength, shortReadableName, 0);       
          return shortReadableName;
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#signature()
       */
00868       public char[] signature() {
          if (this.signature == null) {
              this.signature = this.type.signature();  // erasure
          }
            return this.signature; 
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#sourceName()
       */
00878       public char[] sourceName() {
            return this.type.sourceName();
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.Substitution#substitute(org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding)
       */
00885       public TypeBinding substitute(TypeVariableBinding originalVariable) {
            
            ParameterizedTypeBinding currentType = this;
            while (true) {
                  TypeVariableBinding[] typeVariables = currentType.type.typeVariables();
                  int length = typeVariables.length;
                  // check this variable can be substituted given parameterized type
                  if (originalVariable.rank < length && typeVariables[originalVariable.rank] == originalVariable) {
                      // lazy init, since cannot do so during binding creation if during supertype connection
                      if (currentType.arguments == null)
                              currentType.initializeArguments(); // only for raw types
                      if (currentType.arguments != null)
                              return currentType.arguments[originalVariable.rank];
                  }
                  // recurse on enclosing type, as it may hold more substitutions to perform
                  if (currentType.isStatic()) break;
                  ReferenceBinding enclosing = currentType.enclosingType();
                  if (!(enclosing instanceof ParameterizedTypeBinding))
                        break;
                  currentType = (ParameterizedTypeBinding) enclosing;
            }
            return originalVariable;
      }     

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#superclass()
       */
00912       public ReferenceBinding superclass() {
          if (this.superclass == null) {
              // note: Object cannot be generic
              ReferenceBinding genericSuperclass = this.type.superclass();
              if (genericSuperclass == null) return null; // e.g. interfaces
                this.superclass = (ReferenceBinding) Scope.substitute(this, genericSuperclass);
          }
            return this.superclass;
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#superInterfaces()
       */
00925       public ReferenceBinding[] superInterfaces() {
          if (this.superInterfaces == null) {
                  if (this.type.isHierarchyBeingConnected())
                        return Binding.NO_SUPERINTERFACES; // prevent superinterfaces from being assigned before they are connected
                  this.superInterfaces = Scope.substitute(this, this.type.superInterfaces());
          }
            return this.superInterfaces;
      }

      public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType, LookupEnvironment env) {
            boolean update = false;
            if (this.type == unresolvedType) {
                  this.type = resolvedType; // cannot be raw since being parameterized below
                  update = true;
                  ReferenceBinding enclosing = resolvedType.enclosingType();
                  if (enclosing != null) {
                        this.enclosingType = (ReferenceBinding) env.convertUnresolvedBinaryToRawType(enclosing); // needed when binding unresolved member type
                  }
            }
            if (this.arguments != null) {
                  for (int i = 0, l = this.arguments.length; i < l; i++) {
                        if (this.arguments[i] == unresolvedType) {
                              this.arguments[i] = env.convertUnresolvedBinaryToRawType(resolvedType);
                              update = true;
                        }
                  }
            }
            if (update)
                  initialize(this.type, this.arguments);
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#syntheticEnclosingInstanceTypes()
       */
00959       public ReferenceBinding[] syntheticEnclosingInstanceTypes() {
            return this.type.syntheticEnclosingInstanceTypes();
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#syntheticOuterLocalVariables()
       */
00966       public SyntheticArgumentBinding[] syntheticOuterLocalVariables() {
            return this.type.syntheticOuterLocalVariables();
      }

      /**
       * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#qualifiedPackageName()
       */
00973       public char[] qualifiedPackageName() {
            return this.type.qualifiedPackageName();
      }

      /**
       * @see java.lang.Object#toString()
       */
00980       public String toString() {
          StringBuffer buffer = new StringBuffer(30);
            if (isDeprecated()) buffer.append("deprecated "); //$NON-NLS-1$
            if (isPublic()) buffer.append("public "); //$NON-NLS-1$
            if (isProtected()) buffer.append("protected "); //$NON-NLS-1$
            if (isPrivate()) buffer.append("private "); //$NON-NLS-1$
            if (isAbstract() && isClass()) buffer.append("abstract "); //$NON-NLS-1$
            if (isStatic() && isNestedType()) buffer.append("static "); //$NON-NLS-1$
            if (isFinal()) buffer.append("final "); //$NON-NLS-1$
      
            if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
            else if (isAnnotationType()) buffer.append("@interface "); //$NON-NLS-1$
            else if (isClass()) buffer.append("class "); //$NON-NLS-1$
            else buffer.append("interface "); //$NON-NLS-1$
            buffer.append(this.debugName());
      
            buffer.append("\n\textends "); //$NON-NLS-1$
            buffer.append((superclass != null) ? superclass.debugName() : "NULL TYPE"); //$NON-NLS-1$
      
            if (superInterfaces != null) {
                  if (superInterfaces != Binding.NO_SUPERINTERFACES) {
                        buffer.append("\n\timplements : "); //$NON-NLS-1$
                        for (int i = 0, length = superInterfaces.length; i < length; i++) {
                              if (i  > 0)
                                    buffer.append(", "); //$NON-NLS-1$
                              buffer.append((superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"); //$NON-NLS-1$
                        }
                  }
            } else {
                  buffer.append("NULL SUPERINTERFACES"); //$NON-NLS-1$
            }
      
            if (enclosingType() != null) {
                  buffer.append("\n\tenclosing type : "); //$NON-NLS-1$
                  buffer.append(enclosingType().debugName());
            }
      
            if (fields != null) {
                  if (fields != Binding.NO_FIELDS) {
                        buffer.append("\n/*   fields   */"); //$NON-NLS-1$
                        for (int i = 0, length = fields.length; i < length; i++)
                            buffer.append('\n').append((fields[i] != null) ? fields[i].toString() : "NULL FIELD"); //$NON-NLS-1$ 
                  }
            } else {
                  buffer.append("NULL FIELDS"); //$NON-NLS-1$
            }
      
            if (methods != null) {
                  if (methods != Binding.NO_METHODS) {
                        buffer.append("\n/*   methods   */"); //$NON-NLS-1$
                        for (int i = 0, length = methods.length; i < length; i++)
                              buffer.append('\n').append((methods[i] != null) ? methods[i].toString() : "NULL METHOD"); //$NON-NLS-1$
                  }
            } else {
                  buffer.append("NULL METHODS"); //$NON-NLS-1$
            }
      
//          if (memberTypes != null) {
//                if (memberTypes != NoMemberTypes) {
//                      buffer.append("\n/*   members   */");
//                      for (int i = 0, length = memberTypes.length; i < length; i++)
//                            buffer.append('\n').append((memberTypes[i] != null) ? memberTypes[i].toString() : "NULL TYPE");
//                }
//          } else {
//                buffer.append("NULL MEMBER TYPES");
//          }
      
            buffer.append("\n\n"); //$NON-NLS-1$
            return buffer.toString();
            
      }

      public TypeVariableBinding[] typeVariables() {
            if (this.arguments == null) {
                  // retain original type variables if not substituted (member type of parameterized type)
                  return this.type.typeVariables();
            } 
            return Binding.NO_TYPE_VARIABLES;
      }     
}

Generated by  Doxygen 1.6.0   Back to index