public Object visit(TypeVariablePatternList node, Object data) { | public Object visit(TypeVariablePatternList node, Object data) { | ||||
return node; | return node; | ||||
} | } | ||||
public Object visit(HasMemberTypePattern node, Object data) { | |||||
return node; | |||||
} | |||||
} | } |
/* ******************************************************************* | |||||
* Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors: | |||||
* Adrian Colyer Initial implementation | |||||
* ******************************************************************/ | |||||
package org.aspectj.weaver.patterns; | |||||
import java.io.DataOutputStream; | |||||
import java.io.IOException; | |||||
import java.lang.reflect.Modifier; | |||||
import java.util.Iterator; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import org.aspectj.util.FuzzyBoolean; | |||||
import org.aspectj.weaver.ConcreteTypeMunger; | |||||
import org.aspectj.weaver.ISourceContext; | |||||
import org.aspectj.weaver.Member; | |||||
import org.aspectj.weaver.ResolvedType; | |||||
import org.aspectj.weaver.VersionedDataInputStream; | |||||
import org.aspectj.weaver.World; | |||||
/** | |||||
* @author colyer | |||||
* Matches types that have a certain method / constructor / field | |||||
* Currently only allowed within declare parents and declare @type | |||||
*/ | |||||
public class HasMemberTypePattern extends TypePattern { | |||||
private SignaturePattern signaturePattern; | |||||
public HasMemberTypePattern(SignaturePattern aSignaturePattern) { | |||||
super(false,false); | |||||
this.signaturePattern = aSignaturePattern; | |||||
} | |||||
protected boolean matchesExactly(ResolvedType type) { | |||||
if (signaturePattern.getKind() == Member.FIELD) { | |||||
return hasField(type); | |||||
} else { | |||||
return hasMethod(type); | |||||
} | |||||
} | |||||
private boolean hasField(ResolvedType type) { | |||||
// TODO what about ITDs | |||||
World world = type.getWorld(); | |||||
for (Iterator iter = type.getFields(); iter.hasNext();) { | |||||
Member field = (Member) iter.next(); | |||||
if (signaturePattern.matches(field, type.getWorld(), false)) { | |||||
if (field.getDeclaringType().resolve(world) != type) { | |||||
if (Modifier.isPrivate(field.getModifiers())) continue; | |||||
} | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
private boolean hasMethod(ResolvedType type) { | |||||
// TODO what about ITDs | |||||
World world = type.getWorld(); | |||||
for (Iterator iter = type.getMethods(); iter.hasNext();) { | |||||
Member method = (Member) iter.next(); | |||||
if (signaturePattern.matches(method, type.getWorld(), false)) { | |||||
if (method.getDeclaringType().resolve(world) != type) { | |||||
if (Modifier.isPrivate(method.getModifiers())) continue; | |||||
} | |||||
return true; | |||||
} | |||||
} | |||||
// try itds before we give up | |||||
List mungers = type.getInterTypeMungersIncludingSupers(); | |||||
for (Iterator iter = mungers.iterator(); iter.hasNext();) { | |||||
ConcreteTypeMunger munger = (ConcreteTypeMunger) iter.next(); | |||||
Member member = munger.getSignature(); | |||||
if (signaturePattern.matches(member, type.getWorld(), false)) { | |||||
if (!Modifier.isPublic(member.getModifiers())) continue; | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) { | |||||
return matchesExactly(type); | |||||
} | |||||
public FuzzyBoolean matchesInstanceof(ResolvedType type) { | |||||
throw new UnsupportedOperationException("hasmethod/field do not support instanceof matching"); | |||||
} | |||||
public FuzzyBoolean matchesInstanceof(Class toMatch) { | |||||
return FuzzyBoolean.NO; | |||||
} | |||||
protected boolean matchesExactly(Class toMatch) { | |||||
return false; | |||||
} | |||||
public TypePattern parameterizeWith(Map typeVariableMap) { | |||||
HasMemberTypePattern ret = new HasMemberTypePattern(signaturePattern.parameterizeWith(typeVariableMap)); | |||||
ret.copyLocationFrom(this); | |||||
return ret; | |||||
} | |||||
public boolean equals(Object obj) { | |||||
if (!(obj instanceof HasMemberTypePattern)) return false; | |||||
if (this == obj) return true; | |||||
return signaturePattern.equals(((HasMemberTypePattern)obj).signaturePattern); | |||||
} | |||||
public int hashCode() { | |||||
return signaturePattern.hashCode(); | |||||
} | |||||
public String toString() { | |||||
StringBuffer buff = new StringBuffer(); | |||||
if (signaturePattern.getKind() == Member.FIELD) { | |||||
buff.append("hasfield("); | |||||
} else { | |||||
buff.append("hasmethod("); | |||||
} | |||||
buff.append(signaturePattern.toString()); | |||||
buff.append(")"); | |||||
return buff.toString(); | |||||
} | |||||
public void write(DataOutputStream s) throws IOException { | |||||
s.writeByte(TypePattern.HAS_MEMBER); | |||||
signaturePattern.write(s); | |||||
writeLocation(s); | |||||
} | |||||
public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException { | |||||
SignaturePattern sp = SignaturePattern.read(s, context); | |||||
HasMemberTypePattern ret = new HasMemberTypePattern(sp); | |||||
ret.readLocation(context,s); | |||||
return ret; | |||||
} | |||||
public Object accept(PatternNodeVisitor visitor, Object data) { | |||||
return visitor.visit(this, data); | |||||
} | |||||
} |
/* ******************************************************************* | |||||
* Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html | |||||
* | |||||
* Contributors: | |||||
* Adrian Colyer Initial implementation | |||||
* ******************************************************************/ | |||||
package org.aspectj.weaver.patterns; | |||||
/** | |||||
* @author colyer | |||||
* usage : new HasMemberTypePatternFinder(pattern).hasMemberTypePattern() | |||||
*/ | |||||
public class HasMemberTypePatternFinder extends AbstractPatternNodeVisitor { | |||||
private boolean hasMemberTypePattern = false; | |||||
public HasMemberTypePatternFinder(TypePattern aPattern) { | |||||
aPattern.traverse(this, null); | |||||
} | |||||
public Object visit(HasMemberTypePattern node, Object data) { | |||||
hasMemberTypePattern = true; | |||||
return null; | |||||
} | |||||
public boolean hasMemberTypePattern() { return hasMemberTypePattern; } | |||||
} |
public Object visit(TypeVariablePatternList node, Object data) { | public Object visit(TypeVariablePatternList node, Object data) { | ||||
return node; | return node; | ||||
} | } | ||||
public Object visit(HasMemberTypePattern node, Object data) { | |||||
return node; | |||||
} | |||||
} | } |
Object visit(OrTypePattern node, Object data); | Object visit(OrTypePattern node, Object data); | ||||
Object visit(WildTypePattern node, Object data); | Object visit(WildTypePattern node, Object data); | ||||
Object visit(TypePatternList node, Object data); | Object visit(TypePatternList node, Object data); | ||||
Object visit(HasMemberTypePattern node, Object data); | |||||
// Pointcuts | // Pointcuts | ||||
Object visit(AndPointcut node, Object data); | Object visit(AndPointcut node, Object data); | ||||
return null; | return null; | ||||
} | } | ||||
public Object visit(HasMemberTypePattern node, Object data) { | |||||
append(node); | |||||
return null; | |||||
} | |||||
public static void check(String s) { | public static void check(String s) { | ||||
check(Pointcut.fromString(s), false); | check(Pointcut.fromString(s), false); | ||||
} | } |
private ITokenSource tokenSource; | private ITokenSource tokenSource; | ||||
private ISourceContext sourceContext; | private ISourceContext sourceContext; | ||||
private static final boolean HASMEMBER_PATTERNS_ENABLED = false; | |||||
/** not thread-safe, but this class is not intended to be... */ | |||||
private boolean allowHasTypePatterns = false; | |||||
/** | /** | ||||
* Constructor for PatternParser. | * Constructor for PatternParser. | ||||
} | } | ||||
public DeclareAnnotation parseDeclareAtType() { | public DeclareAnnotation parseDeclareAtType() { | ||||
return new DeclareAnnotation(DeclareAnnotation.AT_TYPE,parseTypePattern()); | |||||
if (HASMEMBER_PATTERNS_ENABLED) allowHasTypePatterns = true; | |||||
TypePattern p = parseTypePattern(); | |||||
allowHasTypePatterns = false; | |||||
return new DeclareAnnotation(DeclareAnnotation.AT_TYPE,p); | |||||
} | } | ||||
public DeclareAnnotation parseDeclareAtMethod(boolean isMethod) { | public DeclareAnnotation parseDeclareAtMethod(boolean isMethod) { | ||||
* String[] typeParameters = maybeParseSimpleTypeVariableList(); | * String[] typeParameters = maybeParseSimpleTypeVariableList(); | ||||
*/ | */ | ||||
eat(":"); | eat(":"); | ||||
if (HASMEMBER_PATTERNS_ENABLED) allowHasTypePatterns = true; | |||||
TypePattern p = parseTypePattern(false); | TypePattern p = parseTypePattern(false); | ||||
allowHasTypePatterns = false; | |||||
IToken t = tokenSource.next(); | IToken t = tokenSource.next(); | ||||
if (!(t.getString().equals("extends") || t.getString().equals("implements"))) { | if (!(t.getString().equals("extends") || t.getString().equals("implements"))) { | ||||
throw new ParserException("extends or implements", t); | throw new ParserException("extends or implements", t); | ||||
public TypePattern parseSingleTypePattern(boolean insideTypeParameters) { | public TypePattern parseSingleTypePattern(boolean insideTypeParameters) { | ||||
if (insideTypeParameters && maybeEat("?")) return parseGenericsWildcardTypePattern(); | if (insideTypeParameters && maybeEat("?")) return parseGenericsWildcardTypePattern(); | ||||
if (allowHasTypePatterns) { | |||||
if (maybeEatIdentifier("hasmethod")) return parseHasMethodTypePattern(); | |||||
if (maybeEatIdentifier("hasfield")) return parseHasFieldTypePattern(); | |||||
} | |||||
List names = parseDottedNamePattern(); | List names = parseDottedNamePattern(); | ||||
return new WildTypePattern(names, includeSubtypes, dim+(isVarArgs?1:0), endPos,isVarArgs,typeParameters); | return new WildTypePattern(names, includeSubtypes, dim+(isVarArgs?1:0), endPos,isVarArgs,typeParameters); | ||||
} | } | ||||
public TypePattern parseHasMethodTypePattern() { | |||||
int startPos = tokenSource.peek(-1).getStart(); | |||||
eat("("); | |||||
SignaturePattern sp = parseMethodOrConstructorSignaturePattern(); | |||||
eat(")"); | |||||
int endPos = tokenSource.peek(-1).getEnd(); | |||||
HasMemberTypePattern ret = new HasMemberTypePattern(sp); | |||||
ret.setLocation(sourceContext, startPos, endPos); | |||||
return ret; | |||||
} | |||||
public TypePattern parseHasFieldTypePattern() { | |||||
int startPos = tokenSource.peek(-1).getStart(); | |||||
eat("("); | |||||
SignaturePattern sp = parseFieldSignaturePattern(); | |||||
eat(")"); | |||||
int endPos = tokenSource.peek(-1).getEnd(); | |||||
HasMemberTypePattern ret = new HasMemberTypePattern(sp); | |||||
ret.setLocation(sourceContext, startPos, endPos); | |||||
return ret; | |||||
} | |||||
public TypePattern parseGenericsWildcardTypePattern() { | public TypePattern parseGenericsWildcardTypePattern() { | ||||
List names = new ArrayList(); | List names = new ArrayList(); | ||||
names.add(new NamePattern("?")); | names.add(new NamePattern("?")); |
public static final byte AND = 8; | public static final byte AND = 8; | ||||
public static final byte NO_KEY = 9; | public static final byte NO_KEY = 9; | ||||
public static final byte ANY_WITH_ANNO = 10; | public static final byte ANY_WITH_ANNO = 10; | ||||
public static final byte HAS_MEMBER = 11; | |||||
public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException { | public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException { | ||||
byte key = s.readByte(); | byte key = s.readByte(); | ||||
case OR: return OrTypePattern.read(s, context); | case OR: return OrTypePattern.read(s, context); | ||||
case AND: return AndTypePattern.read(s, context); | case AND: return AndTypePattern.read(s, context); | ||||
case ANY_WITH_ANNO: return AnyWithAnnotationTypePattern.read(s,context); | case ANY_WITH_ANNO: return AnyWithAnnotationTypePattern.read(s,context); | ||||
case HAS_MEMBER: return HasMemberTypePattern.read(s,context); | |||||
} | } | ||||
throw new BCException("unknown TypePattern kind: " + key); | throw new BCException("unknown TypePattern kind: " + key); | ||||
} | } |