org.aspectj.weaver.MemberImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/* *******************************************************************
* 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 v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* PARC initial implementation
* ******************************************************************/
package org.aspectj.weaver;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
public class MemberImpl implements Member {
protected MemberKind kind;
protected int modifiers;
protected String name;
protected UnresolvedType declaringType;
protected UnresolvedType returnType;
protected UnresolvedType[] parameterTypes;
private final String erasedSignature; // eg. (Ljava/util/Set;V)Ljava/lang/String;
private String paramSignature; // eg. (Ljava/util/Set;V) // no return type
// OPTIMIZE move out of the member!
private boolean reportedCantFindDeclaringType = false;
private boolean reportedUnresolvableMember = false;
/**
* All the signatures that a join point with this member as its signature has.
*/
private JoinPointSignatureIterator joinPointSignatures = null;
/**
* Construct a MemberImpl using an erased signature for the parameters and return type (member method/ctor) or type (member
* field)
*/
public MemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, String name, String erasedSignature) {
this.kind = kind;
this.declaringType = declaringType;
this.modifiers = modifiers;
this.name = name;
this.erasedSignature = erasedSignature;
if (kind == FIELD) {
this.returnType = UnresolvedType.forSignature(erasedSignature);
this.parameterTypes = UnresolvedType.NONE;
} else {
Object[] returnAndParams = signatureToTypes(erasedSignature);
this.returnType = (UnresolvedType) returnAndParams[0];
this.parameterTypes = (UnresolvedType[]) returnAndParams[1];
}
}
/**
* Construct a MemberImpl using real type information for the parameters and return type (member method/ctor) or type (member
* field)
*/
public MemberImpl(MemberKind kind, UnresolvedType declaringType, int modifiers, UnresolvedType returnType, String name,
UnresolvedType[] parameterTypes) {
this.kind = kind;
this.declaringType = declaringType;
this.modifiers = modifiers;
this.returnType = returnType;
this.name = name;
this.parameterTypes = parameterTypes;
if (kind == FIELD) {
this.erasedSignature = returnType.getErasureSignature();
} else {
this.erasedSignature = typesToSignature(returnType, parameterTypes, true);
// Check parameter recovery by collapsing types to the string then rebuilding them from that
// this will check we are capable of having WeakRefs to the parameter types
// String nonErasedSignature = getParameterSignature()+getReturnType().getSignature();
// Object[] returnAndParams = signatureToTypes(nonErasedSignature);
// UnresolvedType[] recoveredParams = (UnresolvedType[]) returnAndParams[1];
// for (int jj=0;jj
*
*
* UnresolvedType.signatureToTypes("()[Z")[0].equals(Type.forSignature("[Z"))
* UnresolvedType.signatureToTypes("(JJ)I")[1]
* .equals(UnresolvedType.forSignatures(new String[] {"J", "J"}))
*
*
*
*
* @param erasedSignature the JVM bytecode method signature string we want to break apart
* @return a pair of UnresolvedType, UnresolvedType[] representing the return types and parameter types.
*/
private static Object[] signatureToTypes(String sig) {
boolean hasParameters = sig.charAt(1) != ')';
if (hasParameters) {
List l = new ArrayList<>();
int i = 1;
boolean hasAnyAnglies = sig.indexOf('<') != -1;
while (true) {
char c = sig.charAt(i);
if (c == ')') {
break; // break out when the hit the ')'
}
int start = i;
while (c == '[') {
c = sig.charAt(++i);
}
if (c == 'L' || c == 'P') {
int nextSemicolon = sig.indexOf(';', start);
int firstAngly = (hasAnyAnglies ? sig.indexOf('<', start) : -1);
if (!hasAnyAnglies || firstAngly == -1 || firstAngly > nextSemicolon) {
i = nextSemicolon + 1;
l.add(UnresolvedType.forSignature(sig.substring(start, i)));
} else {
// generics generics generics
// Have to skip to the *correct* ';'
boolean endOfSigReached = false;
int posn = firstAngly;
int genericDepth = 0;
while (!endOfSigReached) {
switch (sig.charAt(posn)) {
case '<':
genericDepth++;
break;
case '>':
genericDepth--;
break;
case ';':
if (genericDepth == 0) {
endOfSigReached = true;
}
break;
default:
}
posn++;
}
// posn now points to the correct nextSemicolon :)
i = posn;
l.add(UnresolvedType.forSignature(sig.substring(start, i)));
}
} else if (c == 'T') { // assumed 'reference' to a type
// variable, so just "Tname;"
int nextSemicolon = sig.indexOf(';', start);
String nextbit = sig.substring(start, nextSemicolon + 1);
l.add(UnresolvedType.forSignature(nextbit));
i = nextSemicolon + 1;
} else {
i++;
l.add(UnresolvedType.forSignature(sig.substring(start, i)));
}
}
UnresolvedType[] paramTypes = l.toArray(new UnresolvedType[0]);
UnresolvedType returnType = UnresolvedType.forSignature(sig.substring(i + 1, sig.length()));
return new Object[] { returnType, paramTypes };
} else {
UnresolvedType returnType = UnresolvedType.forSignature(sig.substring(2));
return new Object[] { returnType, UnresolvedType.NONE };
}
}
// ---- factory methods
public static MemberImpl field(String declaring, int mods, String name, String signature) {
return field(declaring, mods, UnresolvedType.forSignature(signature), name);
}
// OPTIMIZE do we need to call this? unless necessary the signatureToTypes()
// call smacks of laziness on the behalf of the caller of this method
public static MemberImpl method(UnresolvedType declaring, int mods, String name, String signature) {
Object[] pair = signatureToTypes(signature);
return method(declaring, mods, (UnresolvedType) pair[0], name, (UnresolvedType[]) pair[1]);
}
public static MemberImpl monitorEnter() {
return new MemberImpl(MONITORENTER, UnresolvedType.OBJECT, Modifier.STATIC, UnresolvedType.VOID, "",
UnresolvedType.ARRAY_WITH_JUST_OBJECT);
}
public static MemberImpl monitorExit() {
return new MemberImpl(MONITOREXIT, UnresolvedType.OBJECT, Modifier.STATIC, UnresolvedType.VOID, "",
UnresolvedType.ARRAY_WITH_JUST_OBJECT);
}
public static Member pointcut(UnresolvedType declaring, String name, String signature) {
Object[] pair = signatureToTypes(signature);
return pointcut(declaring, 0, (UnresolvedType) pair[0], name, (UnresolvedType[]) pair[1]);
}
private static MemberImpl field(String declaring, int mods, UnresolvedType ty, String name) {
return new MemberImpl(FIELD, UnresolvedType.forName(declaring), mods, ty, name, UnresolvedType.NONE);
}
public static MemberImpl method(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) {
return new MemberImpl(
// ??? this calls a method
name.equals("") ? CONSTRUCTOR : METHOD, declTy, mods, rTy, name, paramTys);
}
private static Member pointcut(UnresolvedType declTy, int mods, UnresolvedType rTy, String name, UnresolvedType[] paramTys) {
return new MemberImpl(POINTCUT, declTy, mods, rTy, name, paramTys);
}
public static ResolvedMemberImpl makeExceptionHandlerSignature(UnresolvedType inType, UnresolvedType catchType) {
return new ResolvedMemberImpl(HANDLER, inType, Modifier.STATIC, "", "(" + catchType.getSignature() + ")V");
}
@Override
public final boolean equals(Object other) {
if (!(other instanceof Member)) {
return false;
}
Member o = (Member) other;
return (getKind() == o.getKind() && getName().equals(o.getName()) && getSignature().equals(o.getSignature()) && getDeclaringType()
.equals(o.getDeclaringType()));
}
/**
* @return true if this member equals the one supplied in every respect other than the declaring type
*/
public final boolean equalsApartFromDeclaringType(Object other) {
if (!(other instanceof Member)) {
return false;
}
Member o = (Member) other;
return (getKind() == o.getKind() && getName().equals(o.getName()) && getSignature().equals(o.getSignature()));
}
/**
* Equality is checked based on the underlying signature, so the hash code of a member is based on its kind, name, signature,
* and declaring type. The algorithm for this was taken from page 38 of effective java.
*/
private volatile int hashCode = 0;
@Override
public int hashCode() {
if (hashCode == 0) {
int result = 17;
result = 37 * result + getKind().hashCode();
result = 37 * result + getName().hashCode();
result = 37 * result + getSignature().hashCode();
result = 37 * result + getDeclaringType().hashCode();
hashCode = result;
}
return hashCode;
}
public int compareTo(Member other) {
Member o = other;
int i = getName().compareTo(o.getName());
if (i != 0) {
return i;
}
return getSignature().compareTo(o.getSignature());
}
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append(returnType.getName());
buf.append(' ');
if (declaringType == null) {
buf.append("");
} else {
buf.append(declaringType.getName());
}
buf.append('.');
buf.append(name);
if (kind != FIELD) {
buf.append("(");
if (parameterTypes.length != 0) {
buf.append(parameterTypes[0]);
for (int i = 1, len = parameterTypes.length; i < len; i++) {
buf.append(", ");
buf.append(parameterTypes[i].getName());
}
}
buf.append(")");
}
return buf.toString();
}
public MemberKind getKind() {
return kind;
}
public UnresolvedType getDeclaringType() {
return declaringType;
}
public UnresolvedType getReturnType() {
return returnType;
}
public UnresolvedType getGenericReturnType() {
return getReturnType();
}
public UnresolvedType[] getGenericParameterTypes() {
return getParameterTypes();
}
public final UnresolvedType getType() {
return returnType;
}
public String getName() {
return name;
}
public UnresolvedType[] getParameterTypes() {
return parameterTypes;
}
public String getSignature() {
return erasedSignature;
}
public int getArity() {
return parameterTypes.length;
}
public String getParameterSignature() {
if (paramSignature == null) {
StringBuilder sb = new StringBuilder("(");
for (UnresolvedType parameterType : parameterTypes) {
sb.append(parameterType.getSignature());
}
paramSignature = sb.append(")").toString();
}
return paramSignature;
}
// OPTIMIZE see next line. Why the hell are they in here if we only know it
// once resolution has occurred...
// ---- things we know only with resolution
public int getModifiers(World world) {
ResolvedMember resolved = resolve(world);
if (resolved == null) {
reportDidntFindMember(world);
return 0;
}
return resolved.getModifiers();
}
public UnresolvedType[] getExceptions(World world) {
ResolvedMember resolved = resolve(world);
if (resolved == null) {
reportDidntFindMember(world);
return UnresolvedType.NONE;
}
return resolved.getExceptions();
}
public final boolean isStatic() {
return Modifier.isStatic(modifiers);
}
public final boolean isInterface() {
return Modifier.isInterface(modifiers);
}
public final boolean isPrivate() {
return Modifier.isPrivate(modifiers);
}
public boolean canBeParameterized() {
return false;
}
public int getModifiers() {
return modifiers;
}
public AnnotationAJ[] getAnnotations() {
throw new UnsupportedOperationException("You should resolve this member '" + this
+ "' and call getAnnotations() on the result...");
}
// ---- fields 'n' stuff
public Collection getDeclaringTypes(World world) {
ResolvedType myType = getDeclaringType().resolve(world);
Collection ret = new HashSet<>();
if (kind == CONSTRUCTOR) {
// this is wrong if the member doesn't exist, but that doesn't
// matter
ret.add(myType);
} else if (Modifier.isStatic(modifiers) || kind == FIELD) {
walkUpStatic(ret, myType);
} else {
walkUp(ret, myType);
}
return ret;
}
private boolean walkUp(Collection acc, ResolvedType curr) {
if (acc.contains(curr)) {
return true;
}
boolean b = false;
for (Iterator i = curr.getDirectSupertypes(); i.hasNext();) {
b |= walkUp(acc, i.next());
}
if (!b && curr.isParameterizedType()) {
b = walkUp(acc, curr.getGenericType());
}
if (!b) {
b = curr.lookupMemberNoSupers(this) != null;
}
if (b) {
acc.add(curr);
}
return b;
}
private boolean walkUpStatic(Collection acc, ResolvedType curr) {
if (curr.lookupMemberNoSupers(this) != null) {
acc.add(curr);
return true;
} else {
boolean b = false;
for (Iterator i = curr.getDirectSupertypes(); i.hasNext();) {
b |= walkUpStatic(acc, i.next());
}
if (!b && curr.isParameterizedType()) {
b = walkUpStatic(acc, curr.getGenericType());
}
if (b) {
acc.add(curr);
}
return b;
}
}
public String[] getParameterNames(World world) {
ResolvedMember resolved = resolve(world);
if (resolved == null) {
reportDidntFindMember(world);
return null;
}
return resolved.getParameterNames();
}
/**
* All the signatures that a join point with this member as its signature has.
*/
public JoinPointSignatureIterator getJoinPointSignatures(World inAWorld) {
if (joinPointSignatures == null) {
joinPointSignatures = new JoinPointSignatureIterator(this, inAWorld);
}
joinPointSignatures.reset();
return joinPointSignatures;
}
/**
* Raises an [Xlint:cantFindType] message if the declaring type cannot be found or an [Xlint:unresolvableMember] message if the
* type can be found (bug 149908)
*/
private void reportDidntFindMember(World world) {
if (reportedCantFindDeclaringType || reportedUnresolvableMember) {
return;
}
ResolvedType rType = getDeclaringType().resolve(world);
if (rType.isMissing()) {
world.getLint().cantFindType.signal(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE, rType.getName()), null);
reportedCantFindDeclaringType = true;
} else {
world.getLint().unresolvableMember.signal(getName(), null);
reportedUnresolvableMember = true;
}
}
public void wipeJoinpointSignatures() {
joinPointSignatures = null;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy