Logo Search packages:      
Sourcecode: aspectj version File versions  Download package

ResolvedMemberImpl.java

/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * 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: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.weaver;

import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.aspectj.bridge.ISourceLocation;

/**
 * This is the declared member, i.e. it will always correspond to an actual method/... declaration
 */
00031 public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, AnnotatedElement, TypeVariableDeclaringElement,
            ResolvedMember {

      private String[] parameterNames = null;
      protected UnresolvedType[] checkedExceptions = UnresolvedType.NONE;
      /**
       * if this member is a parameterized version of a member in a generic type, then this field holds a reference to the member we
       * parameterize.
       */
00040       protected ResolvedMember backingGenericMember = null;

      protected Set<ResolvedType> annotationTypes = null;
      protected ResolvedType[][] parameterAnnotationTypes = null;

      // Some members are 'created' to represent other things (for example ITDs).
      // These
      // members have their annotations stored elsewhere, and this flag indicates
      // that is
      // the case. It is up to the caller to work out where that is!
      // Once determined the caller may choose to stash the annotations in this
      // member...
      private boolean isAnnotatedElsewhere = false; // this field is not
      // serialized.
      private boolean isAjSynthetic = false;

      // generic methods have type variables
      protected TypeVariable[] typeVariables;

      // these three fields hold the source location of this member
      protected int start, end;
      protected ISourceContext sourceContext = null;

      // XXX deprecate this in favor of the constructor below
      public ResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
                  UnresolvedType[] parameterTypes) {
            super(kind, declaringType, modifiers, returnType, name, parameterTypes);
      }

      public ResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
                  UnresolvedType[] parameterTypes, UnresolvedType[] checkedExceptions) {
            super(kind, declaringType, modifiers, returnType, name, parameterTypes);
            this.checkedExceptions = checkedExceptions;
      }

      public ResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
                  UnresolvedType[] parameterTypes, UnresolvedType[] checkedExceptions, ResolvedMember backingGenericMember) {
            this(kind, declaringType, modifiers, returnType, name, parameterTypes, checkedExceptions);
            this.backingGenericMember = backingGenericMember;
            this.isAjSynthetic = backingGenericMember.isAjSynthetic();
      }

      public ResolvedMemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, String name, String signature) {
            super(kind, declaringType, modifiers, name, signature);
      }

      /**
       * Compute the full set of signatures for a member. This walks up the hierarchy giving the ResolvedMember in each defining type
       * in the hierarchy. A shadowMember can be created with a target type (declaring type) that does not actually define the member.
       * This is ok as long as the member is inherited in the declaring type. Each declaring type in the line to the actual declaring
       * type is added as an additional signature. For example:
       * 
       * class A { void foo(); } class B extends A {}
       * 
       * shadowMember : void B.foo()
       * 
       * gives { void B.foo(), void A.foo() }
       * 
       * @param joinPointSignature
       * @param inAWorld
       */
00101       public static JoinPointSignature[] getJoinPointSignatures(Member joinPointSignature, World inAWorld) {

            // Walk up hierarchy creating one member for each type up to and
            // including the
            // first defining type
            ResolvedType originalDeclaringType = joinPointSignature.getDeclaringType().resolve(inAWorld);
            ResolvedMemberImpl firstDefiningMember = (ResolvedMemberImpl) joinPointSignature.resolve(inAWorld);
            if (firstDefiningMember == null) {
                  return new JoinPointSignature[0];
            }
            // declaringType can be unresolved if we matched a synthetic member
            // generated by Aj...
            // should be fixed elsewhere but add this resolve call on the end for
            // now so that we can
            // focus on one problem at a time...
            ResolvedType firstDefiningType = firstDefiningMember.getDeclaringType().resolve(inAWorld);
            if (firstDefiningType != originalDeclaringType) {
                  if (joinPointSignature.getKind() == Member.CONSTRUCTOR) {
                        return new JoinPointSignature[0];
                  }
                  // else if (shadowMember.isStatic()) {
                  // return new ResolvedMember[] {firstDefiningMember};
                  // }
            }

            List<ResolvedType> declaringTypes = new ArrayList<ResolvedType>();
            accumulateTypesInBetween(originalDeclaringType, firstDefiningType, declaringTypes);
            Set<ResolvedMember> memberSignatures = new HashSet<ResolvedMember>();
            for (ResolvedType declaringType : declaringTypes) {
                  ResolvedMember member = firstDefiningMember.withSubstituteDeclaringType(declaringType);
                  memberSignatures.add(member);
            }

            if (shouldWalkUpHierarchyFor(firstDefiningMember)) {
                  // now walk up the hierarchy from the firstDefiningMember and
                  // include the signature for
                  // every type between the firstDefiningMember and the root defining
                  // member.
                  Iterator<ResolvedType> superTypeIterator = firstDefiningType.getDirectSupertypes();
                  List typesAlreadyVisited = new ArrayList();
                  accumulateMembersMatching(firstDefiningMember, superTypeIterator, typesAlreadyVisited, memberSignatures, false);
            }

            JoinPointSignature[] ret = new JoinPointSignature[memberSignatures.size()];
            memberSignatures.toArray(ret);
            return ret;
      }

      private static boolean shouldWalkUpHierarchyFor(Member aMember) {
            if (aMember.getKind() == Member.CONSTRUCTOR)
                  return false;
            if (aMember.getKind() == Member.FIELD)
                  return false;
            if (aMember.isStatic())
                  return false;
            return true;
      }

      /**
       * Build a list containing every type between subtype and supertype, inclusively.
       */
00162       private static void accumulateTypesInBetween(ResolvedType subType, ResolvedType superType, List<ResolvedType> types) {
            types.add(subType);
            if (subType == superType) {
                  return;
            } else {
                  for (Iterator<ResolvedType> iter = subType.getDirectSupertypes(); iter.hasNext();) {
                        ResolvedType parent = iter.next();
                        if (superType.isAssignableFrom(parent)) {
                              accumulateTypesInBetween(parent, superType, types);
                        }
                  }
            }
      }

      /**
       * We have a resolved member, possibly with type parameter references as parameters or return type. We need to find all its
       * ancestor members. When doing this, a type parameter matches regardless of bounds (bounds can be narrowed down the hierarchy).
       */
00180       private static void accumulateMembersMatching(ResolvedMemberImpl memberToMatch, Iterator<ResolvedType> typesToLookIn,
                  List<ResolvedType> typesAlreadyVisited, Set<ResolvedMember> foundMembers, boolean ignoreGenerics) {
            while (typesToLookIn.hasNext()) {
                  ResolvedType toLookIn = typesToLookIn.next();
                  if (!typesAlreadyVisited.contains(toLookIn)) {
                        typesAlreadyVisited.add(toLookIn);
                        ResolvedMemberImpl foundMember = (ResolvedMemberImpl) toLookIn.lookupResolvedMember(memberToMatch, true,
                                    ignoreGenerics);
                        if (foundMember != null && isVisibleTo(memberToMatch, foundMember)) {
                              List<ResolvedType> declaringTypes = new ArrayList<ResolvedType>();
                              // declaring type can be unresolved if the member can from
                              // an ITD...
                              ResolvedType resolvedDeclaringType = foundMember.getDeclaringType().resolve(toLookIn.getWorld());
                              accumulateTypesInBetween(toLookIn, resolvedDeclaringType, declaringTypes);
                              for (ResolvedType declaringType : declaringTypes) {
                                    // typesAlreadyVisited.add(declaringType);
                                    ResolvedMember member = foundMember.withSubstituteDeclaringType(declaringType);
                                    foundMembers.add(member);
                              }
                              if (!ignoreGenerics && toLookIn.isParameterizedType() && (foundMember.backingGenericMember != null)) {
                                    foundMembers.add(new JoinPointSignature(foundMember.backingGenericMember, foundMember.declaringType
                                                .resolve(toLookIn.getWorld())));
                              }
                              accumulateMembersMatching(foundMember, toLookIn.getDirectSupertypes(), typesAlreadyVisited, foundMembers,
                                          ignoreGenerics);
                              // if this was a parameterized type, look in the generic
                              // type that backs it too
                        }
                  }
            }
      }

      /**
       * Returns true if the parent member is visible to the child member In the same declaring type this is always true, otherwise if
       * parent is private it is false.
       * 
       * @param childMember
       * @param parentMember
       * @return
       */
00220       private static boolean isVisibleTo(ResolvedMember childMember, ResolvedMember parentMember) {
            if (childMember.getDeclaringType().equals(parentMember.getDeclaringType()))
                  return true;
            if (Modifier.isPrivate(parentMember.getModifiers())) {
                  return false;
            } else {
                  return true;
            }
      }

      // ----

      @Override
      public final int getModifiers(World world) {
            return modifiers;
      }

      @Override
      public final int getModifiers() {
            return modifiers;
      }

      // ----

      @Override
      public final UnresolvedType[] getExceptions(World world) {
            return getExceptions();
      }

      public UnresolvedType[] getExceptions() {
            return checkedExceptions;
      }

      public ShadowMunger getAssociatedShadowMunger() {
            return null;
      }

      // ??? true or false?
      public boolean isAjSynthetic() {
            return isAjSynthetic;
      }

      protected void setAjSynthetic(boolean b) {
            isAjSynthetic = b;
      }

      public boolean hasAnnotations() {
            return (annotationTypes != null);
      }

      /**
       * Check if this member has an annotation of the specified type. If the member has a backing generic member then this member
       * represents a parameterization of a member in a generic type and the annotations available on the backing generic member
       * should be used.
       * 
       * @param ofType the type of the annotation being searched for
       * @return true if the annotation is found on this member or its backing generic member
       */
00278       public boolean hasAnnotation(UnresolvedType ofType) {
            // The ctors don't allow annotations to be specified ... yet - but
            // that doesn't mean it is an error to call this method.
            // Normally the weaver will be working with subtypes of
            // this type - BcelField/BcelMethod
            if (backingGenericMember != null) {
                  if (annotationTypes != null) {
                        throw new BCException("Unexpectedly found a backing generic member and a local set of annotations");
                  }
                  return backingGenericMember.hasAnnotation(ofType);
            }
            if (annotationTypes == null) {
                  return false;
            }
            return annotationTypes.contains(ofType);
      }

      public ResolvedType[] getAnnotationTypes() {
            // The ctors don't allow annotations to be specified ... yet - but
            // that doesn't mean it is an error to call this method.
            // Normally the weaver will be working with subtypes of
            // this type - BcelField/BcelMethod
            if (backingGenericMember != null) {
                  if (annotationTypes != null) {
                        throw new BCException("Unexpectedly found a backing generic member and a local set of annotations");
                  }
                  return backingGenericMember.getAnnotationTypes();
            }
            if (annotationTypes == null) {
                  return null;
            }
            return annotationTypes.toArray(new ResolvedType[] {});
      }

      public String getAnnotationDefaultValue() {
            throw new UnsupportedOperationException(
                        "You should resolve this member and call getAnnotationDefaultValue() on the result...");
      }

      @Override
      public AnnotationAJ[] getAnnotations() {
            if (backingGenericMember != null)
                  return backingGenericMember.getAnnotations();
            return super.getAnnotations();
      }

      public void setAnnotationTypes(ResolvedType[] annotationtypes) {
            if (annotationTypes == null) {
                  annotationTypes = new HashSet<ResolvedType>();
            }
            for (int i = 0; i < annotationtypes.length; i++) {
                  ResolvedType typeX = annotationtypes[i];
                  annotationTypes.add(typeX);
            }
      }

      public ResolvedType[][] getParameterAnnotationTypes() {
            if (parameterAnnotationTypes == null)
                  return null;
            return parameterAnnotationTypes;
      }

      public AnnotationAJ[][] getParameterAnnotations() {
            if (backingGenericMember != null)
                  return backingGenericMember.getParameterAnnotations();
            throw new BCException("Cannot return parameter annotations for a " + this.getClass().getName() + " member");
            // return super.getParameterAnnotations();
      }

      public void addAnnotation(AnnotationAJ annotation) {
            // FIXME asc only allows for annotation types, not instances - should
            // it?
            if (annotationTypes == null) {
                  annotationTypes = new HashSet<ResolvedType>();
            }
            annotationTypes.add(annotation.getType());
      }

      public boolean isBridgeMethod() {
            return (modifiers & Constants.ACC_BRIDGE) != 0 && getKind().equals(METHOD);
      }

      public boolean isVarargsMethod() {
            return (modifiers & Constants.ACC_VARARGS) != 0;
      }

      public void setVarargsMethod() {
            modifiers = modifiers | Constants.ACC_VARARGS;
      }

      public boolean isSynthetic() {
            // See Bcelmethod.isSynthetic() which takes account of preJava5
            // Synthetic modifier
            return (modifiers & 4096) != 0; // do we know better?
      }

      public void write(DataOutputStream s) throws IOException {
            getKind().write(s);
            getDeclaringType().write(s);
            s.writeInt(modifiers);
            s.writeUTF(getName());
            s.writeUTF(getSignature());
            UnresolvedType.writeArray(getExceptions(), s);

            s.writeInt(getStart());
            s.writeInt(getEnd());
            s.writeBoolean(isVarargsMethod());

            // Write out any type variables...
            if (typeVariables == null) {
                  s.writeInt(0);
            } else {
                  s.writeInt(typeVariables.length);
                  for (int i = 0; i < typeVariables.length; i++) {
                        typeVariables[i].write(s);
                  }
            }
            String gsig = getGenericSignature();
            if (getSignature().equals(gsig)) {
                  s.writeBoolean(false);
            } else {
                  s.writeBoolean(true);
                  s.writeInt(parameterTypes.length);
                  for (int i = 0; i < parameterTypes.length; i++) {
                        UnresolvedType array_element = parameterTypes[i];
                        array_element.write(s);
                  }
                  returnType.write(s);
            }
      }

      /**
       * Return the member generic signature that would be suitable for inclusion in a class file Signature attribute. For: <T>
       * List<String> getThem(T t) {} we would create: <T:Ljava/lang/Object;>(TT;)Ljava/util/List<Ljava/lang/String;>;;
       * 
       * @return the generic signature for the member that could be inserted into a class file
       */
00415       public String getSignatureForAttribute() {
            StringBuffer sb = new StringBuffer();
            if (typeVariables != null) {
                  sb.append("<");
                  for (int i = 0; i < typeVariables.length; i++) {
                        sb.append(typeVariables[i].getSignatureForAttribute()); // need
                        // a
                        // 'getSignatureForAttribute()'
                  }
                  sb.append(">");
            }
            sb.append("(");
            for (int i = 0; i < parameterTypes.length; i++) {
                  ResolvedType ptype = (ResolvedType) parameterTypes[i];
                  sb.append(ptype.getSignatureForAttribute());
            }
            sb.append(")");
            sb.append(((ResolvedType) returnType).getSignatureForAttribute());
            return sb.toString();
      }

      public String getGenericSignature() {
            StringBuffer sb = new StringBuffer();
            if (typeVariables != null) {
                  sb.append("<");
                  for (int i = 0; i < typeVariables.length; i++) {
                        sb.append(typeVariables[i].getSignature());
                  }
                  sb.append(">");
            }
            sb.append("(");
            for (int i = 0; i < parameterTypes.length; i++) {
                  UnresolvedType ptype = parameterTypes[i];
                  sb.append(ptype.getSignature());
            }
            sb.append(")");
            sb.append(returnType.getSignature());
            return sb.toString();
      }

      public static void writeArray(ResolvedMember[] members, DataOutputStream s) throws IOException {
            s.writeInt(members.length);
            for (int i = 0, len = members.length; i < len; i++) {
                  members[i].write(s);
            }
      }

      public static ResolvedMemberImpl readResolvedMember(VersionedDataInputStream s, ISourceContext sourceContext)
                  throws IOException {

            ResolvedMemberImpl m = new ResolvedMemberImpl(MemberKind.read(s), UnresolvedType.read(s), s.readInt(), s.readUTF(), s
                        .readUTF());
            m.checkedExceptions = UnresolvedType.readArray(s);

            m.start = s.readInt();
            m.end = s.readInt();
            m.sourceContext = sourceContext;

            if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {

                  if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150M4) {
                        boolean isvarargs = s.readBoolean();
                        if (isvarargs)
                              m.setVarargsMethod();
                  }

                  int tvcount = s.readInt();
                  if (tvcount != 0) {
                        m.typeVariables = new TypeVariable[tvcount];
                        for (int i = 0; i < tvcount; i++) {
                              m.typeVariables[i] = TypeVariable.read(s);
                              m.typeVariables[i].setDeclaringElement(m);
                        }
                  }
                  if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150M4) {
                        boolean hasAGenericSignature = s.readBoolean();
                        if (hasAGenericSignature) {
                              int ps = s.readInt();
                              UnresolvedType[] params = new UnresolvedType[ps];
                              for (int i = 0; i < params.length; i++) {
                                    params[i] = TypeFactory.createTypeFromSignature(s.readUTF());
                              }
                              UnresolvedType rt = TypeFactory.createTypeFromSignature(s.readUTF());
                              m.parameterTypes = params;
                              m.returnType = rt;
                        }
                  }
            }
            return m;
      }

      public static ResolvedMember[] readResolvedMemberArray(VersionedDataInputStream s, ISourceContext context) throws IOException {
            int len = s.readInt();
            ResolvedMember[] members = new ResolvedMember[len];
            for (int i = 0; i < len; i++) {
                  members[i] = ResolvedMemberImpl.readResolvedMember(s, context);
            }
            return members;
      }

      // OPTIMIZE dont like how resolve(world) on ResolvedMemberImpl does
      // something different to world.resolve(member)
      @Override
      public ResolvedMember resolve(World world) {
            // make sure all the pieces of a resolvedmember really are resolved
            try {
                  if (typeVariables != null && typeVariables.length > 0) {
                        for (int i = 0; i < typeVariables.length; i++) {
                              typeVariables[i] = typeVariables[i].resolve(world);
                        }
                  }
                  world.setTypeVariableLookupScope(this);
                  // if (annotationTypes != null) {
                  // Set<ResolvedType> r = new HashSet<ResolvedType>();
                  // for (UnresolvedType element : annotationTypes) {
                  // // for (Iterator iter = annotationTypes.iterator(); iter.hasNext();) {
                  // // UnresolvedType element = (UnresolvedType) iter.next();
                  // r.add(world.resolve(element));
                  // }
                  // annotationTypes = r;
                  // }
                  declaringType = declaringType.resolve(world);
                  if (declaringType.isRawType())
                        declaringType = ((ReferenceType) declaringType).getGenericType();

                  if (parameterTypes != null && parameterTypes.length > 0) {
                        for (int i = 0; i < parameterTypes.length; i++) {
                              parameterTypes[i] = parameterTypes[i].resolve(world);
                        }
                  }

                  returnType = returnType.resolve(world);

            } finally {
                  world.setTypeVariableLookupScope(null);
            }
            return this;
      }

      public ISourceContext getSourceContext(World world) {
            return getDeclaringType().resolve(world).getSourceContext();
      }

      public String[] getParameterNames() {
            return parameterNames;
      }

      public final void setParameterNames(String[] pnames) {
            parameterNames = pnames;
      }

      @Override
      public final String[] getParameterNames(World world) {
            return getParameterNames();
      }

      public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() {
            return null;
      }

      public ISourceLocation getSourceLocation() {
            // System.out.println("get context: " + this + " is " + sourceContext);
            if (getSourceContext() == null) {
                  // System.err.println("no context: " + this);
                  return null;
            }
            return getSourceContext().makeSourceLocation(this);
      }

      public int getEnd() {
            return end;
      }

      public ISourceContext getSourceContext() {
            return sourceContext;
      }

      public int getStart() {
            return start;
      }

      public void setPosition(int sourceStart, int sourceEnd) {
            this.start = sourceStart;
            this.end = sourceEnd;
      }

      public void setDeclaringType(ReferenceType rt) {
            declaringType = rt;
      }

      public void setSourceContext(ISourceContext sourceContext) {
            this.sourceContext = sourceContext;
      }

      public boolean isAbstract() {
            return Modifier.isAbstract(modifiers);
      }

      public boolean isPublic() {
            return Modifier.isPublic(modifiers);
      }

      public boolean isProtected() {
            return Modifier.isProtected(modifiers);
      }

      public boolean isNative() {
            return Modifier.isNative(modifiers);
      }

      public boolean isDefault() {
            return !(isPublic() || isProtected() || isPrivate());
      }

      public boolean isVisible(ResolvedType fromType) {
            World world = fromType.getWorld();
            return ResolvedType.isVisible(getModifiers(), getDeclaringType().resolve(world), fromType);
      }

      public void setCheckedExceptions(UnresolvedType[] checkedExceptions) {
            this.checkedExceptions = checkedExceptions;
      }

      public void setAnnotatedElsewhere(boolean b) {
            isAnnotatedElsewhere = b;
      }

      public boolean isAnnotatedElsewhere() {
            return isAnnotatedElsewhere;
      }

      /**
       * Get the UnresolvedType for the return type, taking generic signature into account
       */
      @Override
00650       public UnresolvedType getGenericReturnType() {
            return getReturnType();
      }

      /**
       * Get the TypeXs of the parameter types, taking generic signature into account
       */
      @Override
00658       public UnresolvedType[] getGenericParameterTypes() {
            return getParameterTypes();
      }

      public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType,
                  boolean isParameterized) {
            return parameterizedWith(typeParameters, newDeclaringType, isParameterized, null);
      }

      /**
       * Return a resolvedmember in which all the type variables in the signature have been replaced with the given bindings. The
       * 'isParameterized' flag tells us whether we are creating a raw type version or not. if (isParameterized) then List<T> will
       * turn into List<String> (for example) - if (!isParameterized) then List<T> will turn into List.
       */
00672       public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType,
                  boolean isParameterized, List aliases) {
            if (// isParameterized && <-- might need this bit...
            !getDeclaringType().isGenericType()) {
                  throw new IllegalStateException("Can't ask to parameterize a member of non-generic type: " + getDeclaringType()
                              + "  kind(" + getDeclaringType().typeKind + ")");
            }
            TypeVariable[] typeVariables = getDeclaringType().getTypeVariables();
            if (isParameterized && (typeVariables.length != typeParameters.length)) {
                  throw new IllegalStateException("Wrong number of type parameters supplied");
            }
            Map<String, UnresolvedType> typeMap = new HashMap<String, UnresolvedType>();
            boolean typeParametersSupplied = typeParameters != null && typeParameters.length > 0;
            if (typeVariables != null) {
                  // If no 'replacements' were supplied in the typeParameters array
                  // then collapse
                  // type variables to their first bound.
                  for (int i = 0; i < typeVariables.length; i++) {
                        UnresolvedType ut = (!typeParametersSupplied ? typeVariables[i].getFirstBound() : typeParameters[i]);
                        typeMap.put(typeVariables[i].getName(), ut);
                  }
            }
            // For ITDs on generic types that use type variables from the target
            // type, the aliases
            // record the alternative names used throughout the ITD expression that
            // must map to
            // the same value as the type variables real name.
            if (aliases != null) {
                  int posn = 0;
                  for (Iterator iter = aliases.iterator(); iter.hasNext();) {
                        String typeVariableAlias = (String) iter.next();
                        typeMap.put(typeVariableAlias, (!typeParametersSupplied ? typeVariables[posn].getFirstBound()
                                    : typeParameters[posn]));
                        posn++;
                  }
            }

            UnresolvedType parameterizedReturnType = parameterize(getGenericReturnType(), typeMap, isParameterized, newDeclaringType
                        .getWorld());
            UnresolvedType[] parameterizedParameterTypes = new UnresolvedType[getGenericParameterTypes().length];
            UnresolvedType[] genericParameterTypes = getGenericParameterTypes();
            for (int i = 0; i < parameterizedParameterTypes.length; i++) {
                  parameterizedParameterTypes[i] = parameterize(genericParameterTypes[i], typeMap, isParameterized, newDeclaringType
                              .getWorld());
            }
            ResolvedMemberImpl ret = new ResolvedMemberImpl(getKind(), newDeclaringType, getModifiers(), parameterizedReturnType,
                        getName(), parameterizedParameterTypes, getExceptions(), this);
            ret.setTypeVariables(getTypeVariables());
            ret.setSourceContext(getSourceContext());
            ret.setPosition(getStart(), getEnd());
            ret.setParameterNames(getParameterNames());
            return ret;
      }

      /**
       * Replace occurrences of type variables in the signature with values contained in the map. The map is of the form
       * A=String,B=Integer and so a signature List<A> Foo.m(B i) {} would become List<String> Foo.m(Integer i) {}
       */
00730       public ResolvedMember parameterizedWith(Map m, World w) {
            // if (//isParameterized && <-- might need this bit...
            // !getDeclaringType().isGenericType()) {
            // throw new IllegalStateException(
            // "Can't ask to parameterize a member of non-generic type: "
            // +getDeclaringType()+"  kind("+
            // getDeclaringType().typeKind+")");
            // }
            declaringType = declaringType.resolve(w);
            if (declaringType.isRawType())
                  declaringType = ((ResolvedType) declaringType).getGenericType();
            // TypeVariable[] typeVariables = getDeclaringType().getTypeVariables();
            // if (isParameterized && (typeVariables.length !=
            // typeParameters.length)) {
            // throw new
            // IllegalStateException("Wrong number of type parameters supplied");
            // }
            // Map typeMap = new HashMap();
            // boolean typeParametersSupplied = typeParameters!=null &&
            // typeParameters.length>0;
            // if (typeVariables!=null) {
            // // If no 'replacements' were supplied in the typeParameters array
            // then collapse
            // // type variables to their first bound.
            // for (int i = 0; i < typeVariables.length; i++) {
            // UnresolvedType ut =
            // (!typeParametersSupplied?typeVariables[i].getFirstBound
            // ():typeParameters[i]);
            // typeMap.put(typeVariables[i].getName(),ut);
            // }
            // }
            // // For ITDs on generic types that use type variables from the target
            // type, the aliases
            // // record the alternative names used throughout the ITD expression
            // that must map to
            // // the same value as the type variables real name.
            // if (aliases!=null) {
            // int posn = 0;
            // for (Iterator iter = aliases.iterator(); iter.hasNext();) {
            // String typeVariableAlias = (String) iter.next();
            // typeMap.put(typeVariableAlias,(!typeParametersSupplied?typeVariables[
            // posn].getFirstBound():typeParameters[posn]));
            // posn++;
            // }
            // }

            UnresolvedType parameterizedReturnType = parameterize(getGenericReturnType(), m, true, w);
            UnresolvedType[] parameterizedParameterTypes = new UnresolvedType[getGenericParameterTypes().length];
            UnresolvedType[] genericParameterTypes = getGenericParameterTypes();
            for (int i = 0; i < parameterizedParameterTypes.length; i++) {
                  parameterizedParameterTypes[i] = parameterize(genericParameterTypes[i], m, true, w);
            }
            ResolvedMemberImpl ret = new ResolvedMemberImpl(getKind(), declaringType, getModifiers(), parameterizedReturnType,
                        getName(), parameterizedParameterTypes, getExceptions(), this);
            ret.setTypeVariables(getTypeVariables());
            ret.setSourceContext(getSourceContext());
            ret.setPosition(getStart(), getEnd());
            ret.setParameterNames(getParameterNames());
            return ret;
      }

      public void setTypeVariables(TypeVariable[] tvars) {
            typeVariables = tvars;
      }

      public TypeVariable[] getTypeVariables() {
            return typeVariables;
      }

      protected UnresolvedType parameterize(UnresolvedType aType, Map typeVariableMap, boolean inParameterizedType, World w) {
            if (aType instanceof TypeVariableReference) {
                  String variableName = ((TypeVariableReference) aType).getTypeVariable().getName();
                  if (!typeVariableMap.containsKey(variableName)) {
                        return aType; // if the type variable comes from the method (and
                        // not the type) thats OK
                  }
                  return (UnresolvedType) typeVariableMap.get(variableName);
            } else if (aType.isParameterizedType()) {
                  if (inParameterizedType) {
                        if (w != null)
                              aType = aType.resolve(w);
                        else {
                              UnresolvedType dType = getDeclaringType();
                              aType = aType.resolve(((ResolvedType) dType).getWorld());
                        }
                        return aType.parameterize(typeVariableMap);
                  } else {
                        return aType.getRawType();
                  }
            } else if (aType.isArray()) {
                  // The component type might be a type variable (pr150095)
                  int dims = 1;
                  String sig = aType.getSignature();
                  // while (sig.charAt(dims) == '[')
                  // dims++;
                  UnresolvedType arrayType = null;
                  UnresolvedType componentSig = UnresolvedType.forSignature(sig.substring(dims));
                  UnresolvedType parameterizedComponentSig = parameterize(componentSig, typeVariableMap, inParameterizedType, w);
                  if (parameterizedComponentSig.isTypeVariableReference()
                              && parameterizedComponentSig instanceof UnresolvedTypeVariableReferenceType
                              && typeVariableMap.containsKey(((UnresolvedTypeVariableReferenceType) parameterizedComponentSig)
                                          .getTypeVariable().getName())) { // pr250632
                        // TODO ASC bah, this code is rubbish - i should fix it properly
                        StringBuffer newsig = new StringBuffer();
                        newsig.append("[T");
                        newsig.append(((UnresolvedTypeVariableReferenceType) parameterizedComponentSig).getTypeVariable().getName());
                        newsig.append(";");
                        arrayType = UnresolvedType.forSignature(newsig.toString());
                  } else {
                        arrayType = ResolvedType.makeArray(parameterizedComponentSig, dims);
                  }
                  return arrayType;
            }
            return aType;
      }

      /**
       * If this member is defined by a parameterized super-type, return the erasure of that member. For example: interface I<T> { T
       * foo(T aTea); } class C implements I<String> { String foo(String aString) { return "something"; } } The resolved member for
       * C.foo has signature String foo(String). The erasure of that member is Object foo(Object) -- use upper bound of type variable.
       * A type is a supertype of itself.
       */
      // public ResolvedMember getErasure() {
      // if (calculatedMyErasure) return myErasure;
      // calculatedMyErasure = true;
      // ResolvedType resolvedDeclaringType = (ResolvedType) getDeclaringType();
      // // this next test is fast, and the result is cached.
      // if (!resolvedDeclaringType.hasParameterizedSuperType()) {
      // return null;
      // } else {
      // // we have one or more parameterized super types.
      // // this member may be defined by one of them... we need to find out.
      // Collection declaringTypes =
      // this.getDeclaringTypes(resolvedDeclaringType.getWorld());
      // for (Iterator iter = declaringTypes.iterator(); iter.hasNext();) {
      // ResolvedType aDeclaringType = (ResolvedType) iter.next();
      // if (aDeclaringType.isParameterizedType()) {
      // // we've found the (a?) parameterized type that defines this member.
      // // now get the erasure of it
      // ResolvedMemberImpl matchingMember = (ResolvedMemberImpl)
      // aDeclaringType.lookupMemberNoSupers(this);
      // if (matchingMember != null && matchingMember.backingGenericMember !=
      // null) {
      // myErasure = matchingMember.backingGenericMember;
      // return myErasure;
      // }
      // }
      // }
      // }
      // return null;
      // }
      //    
      // private ResolvedMember myErasure = null;
      // private boolean calculatedMyErasure = false;
00884       public boolean hasBackingGenericMember() {
            return backingGenericMember != null;
      }

      public ResolvedMember getBackingGenericMember() {
            return backingGenericMember;
      }

      /**
       * For ITDs, we use the default factory methods to build a resolved member, then alter a couple of characteristics using this
       * method - this is safe.
       */
00896       public void resetName(String newName) {
            this.name = newName;
      }

      public void resetKind(MemberKind newKind) {
            this.kind = newKind;
      }

      public void resetModifiers(int newModifiers) {
            this.modifiers = newModifiers;
      }

      public void resetReturnTypeToObjectArray() {
            returnType = UnresolvedType.OBJECTARRAY;
      }

      /**
       * Returns a copy of this member but with the declaring type swapped. Copy only needs to be shallow.
       * 
       * @param newDeclaringType
       */
00917       public JoinPointSignature withSubstituteDeclaringType(ResolvedType newDeclaringType) {
            JoinPointSignature ret = new JoinPointSignature(this, newDeclaringType);
            return ret;
      }

      /**
       * Returns true if this member matches the other. The matching takes into account name and parameter types only. When comparing
       * parameter types, we allow any type variable to match any other type variable regardless of bounds.
       */
00926       public boolean matches(ResolvedMember aCandidateMatch, boolean ignoreGenerics) {
            // if (this.getName().equals("get")) {
            // System.out.println("In RMI.matches() this=" + this + " candidate=" + aCandidateMatch);
            // }
            ResolvedMemberImpl candidateMatchImpl = (ResolvedMemberImpl) aCandidateMatch;
            if (!getName().equals(aCandidateMatch.getName())) {
                  return false;
            }
            UnresolvedType[] myParameterTypes = getGenericParameterTypes();
            UnresolvedType[] candidateParameterTypes = aCandidateMatch.getGenericParameterTypes();
            if (myParameterTypes.length != candidateParameterTypes.length) {
                  return false;
            }
            boolean b = false;
            /*
             * if (ignoreGenerics) { String myParameterSignature = getParameterSigWithBoundsRemoved(); String
             * candidateParameterSignature = candidateMatchImpl.getParameterSigWithBoundsRemoved(); if
             * (myParameterSignature.equals(candidateParameterSignature)) { b = true; } else { myParameterSignature =
             * (hasBackingGenericMember() ? backingGenericMember.getParameterSignatureErased() : getParameterSignatureErased());
             * candidateParameterSignature = (candidateMatchImpl.hasBackingGenericMember() ? candidateMatchImpl.backingGenericMember
             * .getParameterSignatureErased() : candidateMatchImpl.getParameterSignatureErased()); // System.out.println("my psig = " +
             * myParameterSignature); // System.out.println("can psig = " + candidateParameterSignature); b =
             * myParameterSignature.equals(candidateParameterSignature); } } else {
             */
            String myParameterSignature = getParameterSigWithBoundsRemoved();
            String candidateParameterSignature = candidateMatchImpl.getParameterSigWithBoundsRemoved();
            if (myParameterSignature.equals(candidateParameterSignature)) {
                  b = true;
            } else {
                  // try erasure
                  myParameterSignature = getParameterSignatureErased();
                  candidateParameterSignature = candidateMatchImpl.getParameterSignatureErased();
                  // myParameterSignature = (hasBackingGenericMember() ? backingGenericMember.getParameterSignatureErased()
                  // : getParameterSignatureErased());
                  // candidateParameterSignature = (candidateMatchImpl.hasBackingGenericMember() ?
                  // candidateMatchImpl.backingGenericMember
                  // .getParameterSignatureErased() : candidateMatchImpl.getParameterSignatureErased());
                  // System.out.println("my psig = " + myParameterSignature);
                  // System.out.println("can psig = " + candidateParameterSignature);
                  b = myParameterSignature.equals(candidateParameterSignature);
                  // }
            }
            // System.out.println("Checking param signatures: " + b);
            return b;
      }

      /**
       * converts e.g. <T extends Number>.... List<T> to just Ljava/util/List<T;>; whereas the full signature would be
       * Ljava/util/List<T:Ljava/lang/Number;>;
       */
00976       private String myParameterSignatureWithBoundsRemoved = null;
      /**
       * converts e.g. <T extends Number>.... List<T> to just Ljava/util/List;
       */
00980       private String myParameterSignatureErasure = null;

      // does NOT produce a meaningful java signature, but does give a unique
      // string suitable for
      // comparison.
      private String getParameterSigWithBoundsRemoved() {
            if (myParameterSignatureWithBoundsRemoved != null)
                  return myParameterSignatureWithBoundsRemoved;
            StringBuffer sig = new StringBuffer();
            UnresolvedType[] myParameterTypes = getGenericParameterTypes();
            for (int i = 0; i < myParameterTypes.length; i++) {
                  appendSigWithTypeVarBoundsRemoved(myParameterTypes[i], sig, new HashSet());
            }
            myParameterSignatureWithBoundsRemoved = sig.toString();
            return myParameterSignatureWithBoundsRemoved;
      }

      /**
       * Return the erased form of the signature with bounds collapsed for type variables, etc. Does not include the return type, @see
       * getParam
       */
01001       public String getParameterSignatureErased() {
            if (myParameterSignatureErasure != null)
                  return myParameterSignatureErasure;
            StringBuffer sig = new StringBuffer();
            UnresolvedType[] myParameterTypes = getParameterTypes();
            for (int i = 0; i < myParameterTypes.length; i++) {
                  UnresolvedType thisParameter = myParameterTypes[i];
                  // type vars will be erased to first bound
                  sig.append(thisParameter.getErasureSignature());
            }
            myParameterSignatureErasure = sig.toString();
            return myParameterSignatureErasure;
      }

      public String getSignatureErased() {
            StringBuffer sb = new StringBuffer();
            sb.append("(");
            sb.append(getParameterSignatureErased());
            sb.append(")");
            sb.append(getReturnType().getErasureSignature());
            return sb.toString();
      }

      // does NOT produce a meaningful java signature, but does give a unique
      // string suitable for
      // comparison.
      public static void appendSigWithTypeVarBoundsRemoved(UnresolvedType aType, StringBuffer toBuffer, Set alreadyUsedTypeVars) {
            if (aType.isTypeVariableReference()) {
                  TypeVariableReferenceType typeVariableRT = (TypeVariableReferenceType) aType;
                  // pr204505
                  if (alreadyUsedTypeVars.contains(aType)) {
                        toBuffer.append("...");
                  } else {
                        alreadyUsedTypeVars.add(aType);
                        appendSigWithTypeVarBoundsRemoved(typeVariableRT.getUpperBound(), toBuffer, alreadyUsedTypeVars);
                  }
                  // toBuffer.append("T;");
            } else if (aType.isParameterizedType()) {
                  toBuffer.append(aType.getRawType().getSignature());
                  toBuffer.append("<");
                  for (int i = 0; i < aType.getTypeParameters().length; i++) {
                        appendSigWithTypeVarBoundsRemoved(aType.getTypeParameters()[i], toBuffer, alreadyUsedTypeVars);
                  }
                  toBuffer.append(">;");
            } else {
                  toBuffer.append(aType.getSignature());
            }
      }

      /**
       * Useful for writing tests, returns *everything* we know about this member.
       */
01053       public String toDebugString() {
            StringBuffer r = new StringBuffer();

            // modifiers
            int mods = modifiers;
            if ((mods & 4096) > 0)
                  mods = mods - 4096; // remove synthetic (added in the ASM case but
            // not in the BCEL case...)
            if ((mods & 512) > 0)
                  mods = mods - 512; // remove interface (added in the BCEL case but
            // not in the ASM case...)
            if ((mods & 131072) > 0)
                  mods = mods - 131072; // remove deprecated (added in the ASM case
            // but not in the BCEL case...)
            String modsStr = Modifier.toString(mods);
            if (modsStr.length() != 0)
                  r.append(modsStr).append("(" + mods + ")").append(" ");

            // type variables
            if (typeVariables != null && typeVariables.length > 0) {
                  r.append("<");
                  for (int i = 0; i < typeVariables.length; i++) {
                        if (i > 0)
                              r.append(",");
                        TypeVariable t = typeVariables[i];
                        r.append(t.toDebugString());
                  }
                  r.append("> ");
            }

            // 'declaring' type
            r.append(getGenericReturnType().toDebugString());
            r.append(' ');

            // name
            r.append(declaringType.getName());
            r.append('.');
            r.append(name);

            // parameter signature if a method
            if (kind != FIELD) {
                  r.append("(");
                  UnresolvedType[] params = getGenericParameterTypes();
                  boolean parameterNamesExist = showParameterNames && parameterNames != null && parameterNames.length == params.length;
                  if (params.length != 0) {
                        for (int i = 0, len = params.length; i < len; i++) {
                              if (i > 0)
                                    r.append(", ");
                              r.append(params[i].toDebugString());
                              if (parameterNamesExist)
                                    r.append(" ").append(parameterNames[i]);
                        }
                  }
                  r.append(")");
            }
            return r.toString();
      }

      // SECRETAPI - controlling whether parameter names come out in the debug
      // string (for testing purposes)
      public static boolean showParameterNames = true;

      public String toGenericString() {
            StringBuffer buf = new StringBuffer();
            buf.append(getGenericReturnType().getSimpleName());
            buf.append(' ');
            buf.append(declaringType.getName());
            buf.append('.');
            buf.append(name);
            if (kind != FIELD) {
                  buf.append("(");
                  UnresolvedType[] params = getGenericParameterTypes();
                  if (params.length != 0) {
                        buf.append(params[0].getSimpleName());
                        for (int i = 1, len = params.length; i < len; i++) {
                              buf.append(", ");
                              buf.append(params[i].getSimpleName());
                        }
                  }
                  buf.append(")");
            }
            return buf.toString();
      }

      public boolean isCompatibleWith(Member am) {
            if (kind != METHOD || am.getKind() != METHOD)
                  return true;
            if (!name.equals(am.getName()))
                  return true;
            if (!equalTypes(getParameterTypes(), am.getParameterTypes()))
                  return true;
            return getReturnType().equals(am.getReturnType());
      }

      private static boolean equalTypes(UnresolvedType[] a, UnresolvedType[] b) {
            int len = a.length;
            if (len != b.length)
                  return false;
            for (int i = 0; i < len; i++) {
                  if (!a[i].equals(b[i]))
                        return false;
            }
            return true;
      }

      public TypeVariable getTypeVariableNamed(String name) {
            // Check locally...
            if (typeVariables != null) {
                  for (int i = 0; i < typeVariables.length; i++) {
                        if (typeVariables[i].getName().equals(name))
                              return typeVariables[i];
                  }
            }
            // check the declaring type!
            return declaringType.getTypeVariableNamed(name);

            // Do generic aspects with ITDs that share type variables with the
            // aspect and the target type and have their own tvars cause
            // this to be messier?
      }

      public void evictWeavingState() {
      }

      public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
            throw new UnsupportedOperationException("You should resolve this member and call getAnnotationOfType() on the result...");
      }

      public boolean isEquivalentTo(Object other) {
            return this.equals(other);
      }

      public boolean isDefaultConstructor() {
            return false;
      }
}

Generated by  Doxygen 1.6.0   Back to index