@@ -404,4 +404,8 @@ public abstract class AbstractPatternNodeVisitor implements PatternNodeVisitor { | |||
public Object visit(TypeVariablePatternList node, Object data) { | |||
return node; | |||
} | |||
public Object visit(HasMemberTypePattern node, Object data) { | |||
return node; | |||
} | |||
} |
@@ -0,0 +1,151 @@ | |||
/* ******************************************************************* | |||
* 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); | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
/* ******************************************************************* | |||
* 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; } | |||
} |
@@ -239,4 +239,8 @@ public class IdentityPointcutVisitor implements PatternNodeVisitor { | |||
public Object visit(TypeVariablePatternList node, Object data) { | |||
return node; | |||
} | |||
public Object visit(HasMemberTypePattern node, Object data) { | |||
return node; | |||
} | |||
} |
@@ -44,6 +44,7 @@ public interface PatternNodeVisitor { | |||
Object visit(OrTypePattern node, Object data); | |||
Object visit(WildTypePattern node, Object data); | |||
Object visit(TypePatternList node, Object data); | |||
Object visit(HasMemberTypePattern node, Object data); | |||
// Pointcuts | |||
Object visit(AndPointcut node, Object data); | |||
@@ -559,6 +560,11 @@ public interface PatternNodeVisitor { | |||
return null; | |||
} | |||
public Object visit(HasMemberTypePattern node, Object data) { | |||
append(node); | |||
return null; | |||
} | |||
public static void check(String s) { | |||
check(Pointcut.fromString(s), false); | |||
} |
@@ -28,6 +28,10 @@ public class PatternParser { | |||
private ITokenSource tokenSource; | |||
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. | |||
@@ -154,7 +158,10 @@ public class PatternParser { | |||
} | |||
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) { | |||
@@ -189,7 +196,9 @@ public class PatternParser { | |||
* String[] typeParameters = maybeParseSimpleTypeVariableList(); | |||
*/ | |||
eat(":"); | |||
if (HASMEMBER_PATTERNS_ENABLED) allowHasTypePatterns = true; | |||
TypePattern p = parseTypePattern(false); | |||
allowHasTypePatterns = false; | |||
IToken t = tokenSource.next(); | |||
if (!(t.getString().equals("extends") || t.getString().equals("implements"))) { | |||
throw new ParserException("extends or implements", t); | |||
@@ -678,6 +687,10 @@ public class PatternParser { | |||
public TypePattern parseSingleTypePattern(boolean insideTypeParameters) { | |||
if (insideTypeParameters && maybeEat("?")) return parseGenericsWildcardTypePattern(); | |||
if (allowHasTypePatterns) { | |||
if (maybeEatIdentifier("hasmethod")) return parseHasMethodTypePattern(); | |||
if (maybeEatIdentifier("hasfield")) return parseHasFieldTypePattern(); | |||
} | |||
List names = parseDottedNamePattern(); | |||
@@ -707,6 +720,28 @@ public class PatternParser { | |||
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() { | |||
List names = new ArrayList(); | |||
names.add(new NamePattern("?")); |
@@ -328,6 +328,7 @@ public abstract class TypePattern extends PatternNode { | |||
public static final byte AND = 8; | |||
public static final byte NO_KEY = 9; | |||
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 { | |||
byte key = s.readByte(); | |||
@@ -342,6 +343,7 @@ public abstract class TypePattern extends PatternNode { | |||
case OR: return OrTypePattern.read(s, context); | |||
case AND: return AndTypePattern.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); | |||
} |