You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1266 lines
44 KiB
1266 lines
44 KiB
/* ******************************************************************* |
|
* Copyright (c) 2002-2010 Contributors |
|
* 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 |
|
* ******************************************************************/ |
|
package com.fr.third.aspectj.weaver; |
|
|
|
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 com.fr.third.aspectj.bridge.ISourceLocation; |
|
|
|
/** |
|
* Represent a resolved member. Components of it are expected to exist. This member will correspond to a real member *unless* it is |
|
* being used to represent the effect of an ITD. |
|
* |
|
* @author PARC |
|
* @author Andy Clement |
|
*/ |
|
public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, ResolvedMember { |
|
|
|
private String[] parameterNames = null; |
|
private boolean isResolved = false; |
|
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. |
|
*/ |
|
protected ResolvedMember backingGenericMember = null; |
|
|
|
protected AnnotationAJ[] annotations = null; |
|
protected ResolvedType[] annotationTypes = null; |
|
protected AnnotationAJ[][] parameterAnnotations = 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; |
|
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 |
|
*/ |
|
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 JoinPointSignature.EMPTY_ARRAY; |
|
} |
|
// 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() == CONSTRUCTOR) { |
|
return JoinPointSignature.EMPTY_ARRAY; |
|
} |
|
// 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) { |
|
memberSignatures.add(new JoinPointSignature(firstDefiningMember, declaringType)); |
|
} |
|
|
|
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<ResolvedType> typesAlreadyVisited = new ArrayList<ResolvedType>(); |
|
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() == CONSTRUCTOR) { |
|
return false; |
|
} |
|
if (aMember.getKind() == FIELD) { |
|
return false; |
|
} |
|
if (Modifier.isStatic(aMember.getModifiers())) { |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
/** |
|
* Build a list containing every type between subtype and supertype, inclusively. |
|
*/ |
|
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). |
|
*/ |
|
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); |
|
foundMembers.add(new JoinPointSignature(foundMember, declaringType)); |
|
} |
|
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 |
|
*/ |
|
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 |
|
*/ |
|
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) { |
|
for (int i = 0, max = annotationTypes.length; i < max; i++) { |
|
if (annotationTypes[i].equals(ofType)) { |
|
return true; |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
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(); |
|
} |
|
return annotationTypes; |
|
} |
|
|
|
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(); |
|
} |
|
if (annotations!=null) { |
|
return annotations; |
|
} |
|
return super.getAnnotations(); |
|
} |
|
|
|
public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) { |
|
if (annotations!=null) { |
|
// this means they have been set (we are likely a placeholder for an ITD, so a fake member) |
|
for (AnnotationAJ annotation: annotations) { |
|
if (annotation.getType().equals(ofType)) { |
|
return annotation; |
|
} |
|
} |
|
return null; |
|
} |
|
throw new UnsupportedOperationException("You should resolve this member and call getAnnotationOfType() on the result..."); |
|
} |
|
|
|
public void setAnnotations(AnnotationAJ[] annotations) { |
|
this.annotations = annotations; |
|
} |
|
|
|
public void setAnnotationTypes(ResolvedType[] annotationTypes) { |
|
this.annotationTypes = annotationTypes; |
|
} |
|
|
|
public ResolvedType[][] getParameterAnnotationTypes() { |
|
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) { |
|
if (annotationTypes == null) { |
|
annotationTypes = new ResolvedType[1]; |
|
annotationTypes[0] = annotation.getType(); |
|
annotations = new AnnotationAJ[1]; |
|
annotations[0] = annotation; |
|
} else { |
|
int len = annotations.length; |
|
AnnotationAJ[] ret = new AnnotationAJ[len + 1]; |
|
System.arraycopy(annotations, 0, ret, 0, len); |
|
ret[len] = annotation; |
|
annotations = ret; |
|
|
|
ResolvedType[] newAnnotationTypes = new ResolvedType[len + 1]; |
|
System.arraycopy(annotationTypes, 0, newAnnotationTypes, 0, len); |
|
newAnnotationTypes[len] = annotation.getType(); |
|
annotationTypes = newAnnotationTypes; |
|
} |
|
} |
|
|
|
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(CompressingDataOutputStream s) throws IOException { |
|
getKind().write(s); |
|
s.writeBoolean(s.canCompress()); // boolean indicates if parts of this are compressed references |
|
|
|
// write out the signature of the declaring type of this member |
|
if (s.canCompress()) { |
|
s.writeCompressedSignature(getDeclaringType().getSignature()); |
|
} else { |
|
getDeclaringType().write(s); |
|
} |
|
|
|
// write out the modifiers |
|
s.writeInt(modifiers); |
|
|
|
// write out the name and the signature of this member |
|
if (s.canCompress()) { |
|
s.writeCompressedName(getName()); |
|
s.writeCompressedSignature(getSignature()); |
|
} else { |
|
s.writeUTF(getName()); |
|
s.writeUTF(getSignature()); |
|
} |
|
|
|
// write out the array clauses |
|
UnresolvedType.writeArray(getExceptions(), s); |
|
|
|
s.writeInt(getStart()); |
|
s.writeInt(getEnd()); |
|
s.writeBoolean(isVarargsMethod()); |
|
|
|
// Write out any type variables... |
|
if (typeVariables == null) { |
|
s.writeByte(0); |
|
} else { |
|
s.writeByte(typeVariables.length); |
|
for (int i = 0; i < typeVariables.length; i++) { |
|
typeVariables[i].write(s); |
|
} |
|
} |
|
String gsig = getGenericSignature(); |
|
|
|
// change this to a byte: 255=false 0>254 means true and encodes the number of parameters |
|
if (getSignature().equals(gsig)) { |
|
s.writeByte(0xff); |
|
} else { |
|
s.writeByte(parameterTypes.length); |
|
for (int i = 0; i < parameterTypes.length; i++) { |
|
if (s.canCompress()) { |
|
s.writeCompressedSignature(parameterTypes[i].getSignature()); |
|
} else { |
|
UnresolvedType array_element = parameterTypes[i]; |
|
array_element.write(s); |
|
} |
|
} |
|
if (s.canCompress()) { |
|
s.writeCompressedSignature(returnType.getSignature()); |
|
} else { |
|
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 |
|
*/ |
|
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, CompressingDataOutputStream 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 { |
|
|
|
MemberKind mk = MemberKind.read(s); |
|
boolean compressed = (s.isAtLeast169() ? s.readBoolean() : false); |
|
UnresolvedType declaringType = compressed ? UnresolvedType.forSignature(s.readUtf8(s.readShort())) : UnresolvedType.read(s); |
|
int modifiers = s.readInt(); |
|
String name = compressed ? s.readUtf8(s.readShort()) : s.readUTF(); |
|
String signature = compressed ? s.readUtf8(s.readShort()) : s.readUTF(); |
|
ResolvedMemberImpl m = new ResolvedMemberImpl(mk, declaringType, modifiers, name, signature); |
|
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.isAtLeast169() ? s.readByte() : 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); |
|
m.typeVariables[i].setRank(i); |
|
} |
|
} |
|
if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150M4) { |
|
int pcount = -1; |
|
boolean hasAGenericSignature = false; |
|
if (s.isAtLeast169()) { |
|
pcount = s.readByte(); |
|
hasAGenericSignature = (pcount >= 0 && pcount < 255); |
|
} else { |
|
hasAGenericSignature = s.readBoolean(); |
|
} |
|
if (hasAGenericSignature) { |
|
int ps = (s.isAtLeast169() ? pcount : s.readInt()); |
|
UnresolvedType[] params = new UnresolvedType[ps]; |
|
for (int i = 0; i < params.length; i++) { |
|
if (compressed) { |
|
params[i] = TypeFactory.createTypeFromSignature(s.readSignature()); |
|
} else { |
|
params[i] = TypeFactory.createTypeFromSignature(s.readUTF()); |
|
} |
|
} |
|
UnresolvedType rt = compressed ? TypeFactory.createTypeFromSignature(s.readSignature()) : 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) { |
|
if (isResolved) { |
|
return this; |
|
} |
|
// 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); |
|
} |
|
isResolved = true; |
|
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 isDefault() { |
|
int mods = getModifiers(); |
|
return !(Modifier.isPublic(mods) || Modifier.isProtected(mods) || Modifier.isPrivate(mods)); |
|
} |
|
|
|
public boolean isVisible(ResolvedType fromType) { |
|
UnresolvedType declaringType = getDeclaringType(); |
|
ResolvedType type = null; |
|
if (fromType.equals(declaringType)) { |
|
type = fromType; |
|
} else { |
|
World world = fromType.getWorld(); |
|
type = declaringType.resolve(world); |
|
} |
|
return ResolvedType.isVisible(getModifiers(), type, 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 |
|
public UnresolvedType getGenericReturnType() { |
|
return getReturnType(); |
|
} |
|
|
|
/** |
|
* Get the TypeXs of the parameter types, taking generic signature into account |
|
*/ |
|
@Override |
|
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. |
|
*/ |
|
public ResolvedMemberImpl parameterizedWith(UnresolvedType[] typeParameters, ResolvedType newDeclaringType, |
|
boolean isParameterized, List<String> aliases) { |
|
// PR308773 |
|
// this check had problems for the inner type of a generic type because the inner type can be represented |
|
// by a 'simple type' if it is only sharing type variables with the outer and has none of its own. To avoid the |
|
// check going bang in this case we check for $ (crap...) - we can't check the outer because the declaring type |
|
// is considered unresolved... |
|
if (// isParameterized && <-- might need this bit... |
|
!getDeclaringType().isGenericType() && getDeclaringType().getName().indexOf("$") == -1) { |
|
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 (String typeVariableAlias : aliases) { |
|
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) {} |
|
*/ |
|
public ResolvedMember parameterizedWith(Map<String, UnresolvedType> 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<String, UnresolvedType> 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 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; |
|
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. |
|
*/ |
|
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 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. |
|
*/ |
|
public boolean matches(ResolvedMember aCandidateMatch, boolean ignoreGenerics) { |
|
ResolvedMemberImpl candidateMatchImpl = (ResolvedMemberImpl) aCandidateMatch; |
|
if (!getName().equals(aCandidateMatch.getName())) { |
|
return false; |
|
} |
|
UnresolvedType[] parameterTypes = getGenericParameterTypes(); |
|
UnresolvedType[] candidateParameterTypes = aCandidateMatch.getGenericParameterTypes(); |
|
if (parameterTypes.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;>; |
|
*/ |
|
private String myParameterSignatureWithBoundsRemoved = null; |
|
/** |
|
* converts e.g. <T extends Number>.... List<T> to just Ljava/util/List; |
|
*/ |
|
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<UnresolvedType>()); |
|
} |
|
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 |
|
*/ |
|
public String getParameterSignatureErased() { |
|
if (myParameterSignatureErasure == null) { |
|
StringBuilder sig = new StringBuilder(); |
|
for (UnresolvedType parameter : getParameterTypes()) { |
|
sig.append(parameter.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<UnresolvedType> alreadyUsedTypeVars) { |
|
if (aType.isTypeVariableReference()) { |
|
TypeVariableReferenceType typeVariableRT = (TypeVariableReferenceType) aType; |
|
// pr204505 |
|
if (alreadyUsedTypeVars.contains(aType)) { |
|
toBuffer.append("..."); |
|
} else { |
|
alreadyUsedTypeVars.add(aType); |
|
appendSigWithTypeVarBoundsRemoved(typeVariableRT.getTypeVariable().getFirstBound(), 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. |
|
*/ |
|
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 boolean isEquivalentTo(Object other) { |
|
return this.equals(other); |
|
} |
|
|
|
public boolean isDefaultConstructor() { |
|
return false; |
|
} |
|
}
|
|
|