From e60f463f95845f92f62f02958f25505e4d401e5a Mon Sep 17 00:00:00 2001 From: aclement Date: Fri, 19 Mar 2010 15:42:00 +0000 Subject: [PATCH] 44365: is() support in type patterns --- .../patterns/AbstractPatternNodeVisitor.java | 4 + .../weaver/patterns/PatternNodeVisitor.java | 1 + .../weaver/patterns/PatternParser.java | 105 ++++++++++++++ .../patterns/TypeCategoryTypePattern.java | 129 ++++++++++++++++++ .../aspectj/weaver/patterns/TypePattern.java | 13 +- .../weaver/patterns/DumpPointcutVisitor.java | 5 + 6 files changed, 252 insertions(+), 5 deletions(-) create mode 100644 org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypeCategoryTypePattern.java diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java index 14234438c..6558c3c21 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java @@ -464,4 +464,8 @@ public abstract class AbstractPatternNodeVisitor implements PatternNodeVisitor { public Object visit(HasMemberTypePattern node, Object data) { return node; } + + public Object visit(TypeCategoryTypePattern node, Object data) { + return node; + } } diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternNodeVisitor.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternNodeVisitor.java index 3fedd718e..336a33e51 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternNodeVisitor.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternNodeVisitor.java @@ -44,6 +44,7 @@ public interface PatternNodeVisitor { Object visit(WildTypePattern node, Object data); Object visit(TypePatternList node, Object data); Object visit(HasMemberTypePattern node, Object data); + Object visit(TypeCategoryTypePattern node, Object data); // Pointcuts Object visit(AndPointcut node, Object data); diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java index 93dfeee51..48d6c9674 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java @@ -868,6 +868,42 @@ public class PatternParser { } } + // // Check for a type category + // IToken token = tokenSource.peek(); + // if (token.isIdentifier()) { + // String category = token.getString(); + // TypeCategoryTypePattern typeIsPattern = null; + // if (category.equals("isClass")) { + // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.CLASS); + // } else if (category.equals("isAspect")) { + // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ASPECT); + // } else if (category.equals("isInterface")) { + // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INTERFACE); + // } else if (category.equals("isInner")) { + // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INNER); + // } else if (category.equals("isAnonymous")) { + // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANONYMOUS); + // } else if (category.equals("isEnum")) { + // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ENUM); + // } else if (category.equals("isAnnotation")) { + // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANNOTATION); + // } + // if (typeIsPattern != null) { + // tokenSource.next(); + // typeIsPattern.setLocation(tokenSource.getSourceContext(), token.getStart(), token.getEnd()); + // return typeIsPattern; + // } + // } + if (maybeEatIdentifier("is")) { + int pos = tokenSource.getIndex() - 1; + TypePattern typeIsPattern = parseIsTypePattern(); + if (typeIsPattern != null) { + return typeIsPattern; + } + // rewind as if we never tried to parse it as a typeIs + tokenSource.setIndex(pos); + } + List names = parseDottedNamePattern(); int dim = 0; @@ -914,6 +950,75 @@ public class PatternParser { return ret; } + /** + * Attempt to parse a typeIs() construct. If it cannot be parsed we just return null and that should cause the caller + * to reset their position and attempt to consume it in another way. This means we won't have problems here: execution(* + * typeIs(..)) because someone has decided to call a method the same as our construct. + * + * @return a TypeIsTypePattern or null if could not be parsed + */ + public TypePattern parseIsTypePattern() { + int startPos = tokenSource.peek(-1).getStart(); // that will be the start of the 'typeIs' + if (!maybeEatAdjacent("(")) { + return null; + } + IToken token = tokenSource.next(); + TypeCategoryTypePattern typeIsPattern = null; + if (token.isIdentifier()) { + String category = token.getString(); + if (category.equals("ClassType")) { + typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.CLASS); + } else if (category.equals("AspectType")) { + typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ASPECT); + } else if (category.equals("InterfaceType")) { + typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INTERFACE); + } else if (category.equals("InnerType")) { + typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INNER); + } else if (category.equals("AnonymousType")) { + typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANONYMOUS); + } else if (category.equals("EnumType")) { + typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ENUM); + } else if (category.equals("AnnotationType")) { + typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANNOTATION); + } + } + if (typeIsPattern == null) { + throw new ParserException("ClassType/AspectType/InterfaceType/InnerType/EnumType/AnnotationType/AnonymousType", token); + } + if (!maybeEat(")")) { + throw new ParserException(")", tokenSource.peek()); + } + int endPos = tokenSource.peek(-1).getEnd(); + typeIsPattern.setLocation(tokenSource.getSourceContext(), startPos, endPos); + return typeIsPattern; + } + + // if (names.size() == 1 && !names.get(0).isAny()) { + // if (maybeEatAdjacent("(")) { + // if (maybeEat(")")) { + // // likely to be one of isClass()/isInterface()/isInner()/isAnonymous()/isAspect() + // if (names.size() == 1) { + // NamePattern np = names.get(0); + // String simpleName = np.maybeGetSimpleName(); + // if (simpleName != null) { + + // return new TypeCategoryTypePattern(TypeCategoryTypePattern.ANNOTATION, np); + // } else { + // throw new ParserException( + // "not a supported type category, supported are isClass/isInterface/isEnum/isAnnotation/isInner/isAnonymous", + // tokenSource.peek(-3)); + // } + // } + // int stop = 1; + // // return new WildTypePattern(names, includeSubtypes, dim + (isVarArgs ? 1 : 0), endPos, isVarArgs, + // // typeParameters); + // } + // } else { + // throw new ParserException("category type pattern is missing closing parentheses", tokenSource.peek(-2)); + // } + // } + // } + public TypePattern parseHasFieldTypePattern() { int startPos = tokenSource.peek(-1).getStart(); eat("("); diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypeCategoryTypePattern.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypeCategoryTypePattern.java new file mode 100644 index 000000000..06c51dbf2 --- /dev/null +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypeCategoryTypePattern.java @@ -0,0 +1,129 @@ +/* ******************************************************************* + * Copyright (c) 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 org.aspectj.weaver.patterns; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; + +import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.ISourceContext; +import org.aspectj.weaver.ResolvedType; +import org.aspectj.weaver.VersionedDataInputStream; +import org.aspectj.weaver.World; + +/** + * A TypeCategoryTypePattern matches on the category of a type, one of class/interface/aspect/inner/anonymous/enum/annotation, and + * these are specified in the pointcut via isClass() isInterface() isAspect() isInner() isAnonymous() isEnum() isAnnotation(). + * + * @author Andy Clement + * @since 1.6.9 + */ +public class TypeCategoryTypePattern extends TypePattern { + + public static final int CLASS = 1; + public static final int INTERFACE = 2; + public static final int ASPECT = 3; + public static final int INNER = 4; + public static final int ANONYMOUS = 5; + public static final int ENUM = 6; + public static final int ANNOTATION = 7; + + private int category; + + private int VERSION = 1; + + public TypeCategoryTypePattern(int category) { + super(false); + this.category = category; + } + + @Override + protected boolean matchesExactly(ResolvedType type) { + return isRightCategory(type); + } + + @Override + protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) { + return isRightCategory(type); + } + + @Override + public FuzzyBoolean matchesInstanceof(ResolvedType type) { + return FuzzyBoolean.fromBoolean(isRightCategory(type)); + } + + @Override + public TypePattern parameterizeWith(Map typeVariableMap, World w) { + return this; + } + + @Override + public Object accept(PatternNodeVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof TypeCategoryTypePattern)) { + return false; + } + TypeCategoryTypePattern o = (TypeCategoryTypePattern) other; + return o.category == category; + } + + // TODO is sourcelocation part of the identity or just a 'nice to have' - if important it should be in hashcode/equals + // TODO but if that is the case it needs addressing for all type patterns + + @Override + public int hashCode() { + return category * 37; + } + + @Override + public void write(DataOutputStream s) throws IOException { + s.writeByte(TypePattern.TYPE_CATEGORY); + s.writeInt(VERSION); + s.writeInt(category); + writeLocation(s); + } + + public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException { + int version = s.readInt(); + int category = s.readInt(); + TypeCategoryTypePattern tp = new TypeCategoryTypePattern(category); + tp.readLocation(context, s); + return tp; + } + + /** + * @return true if the supplied type is of the category specified for this type pattern + */ + private boolean isRightCategory(ResolvedType type) { + switch (category) { + case CLASS: + return type.isClass(); + case INTERFACE: + return type.isInterface(); + case ASPECT: + return type.isAspect(); + case ANONYMOUS: + return type.isAnonymous(); + case INNER: + return type.isNested(); + case ENUM: + return type.isEnum(); + case ANNOTATION: + return type.isAnnotation(); + } + return false; + } + +} diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypePattern.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypePattern.java index eb2020234..f77352fcc 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypePattern.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypePattern.java @@ -300,6 +300,7 @@ public abstract class TypePattern extends PatternNode { public static final byte NO_KEY = 9; public static final byte ANY_WITH_ANNO = 10; public static final byte HAS_MEMBER = 11; + public static final byte TYPE_CATEGORY = 12; public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException { byte key = s.readByte(); @@ -326,6 +327,8 @@ public abstract class TypePattern extends PatternNode { return AnyWithAnnotationTypePattern.read(s, context); case HAS_MEMBER: return HasMemberTypePattern.read(s, context); + case TYPE_CATEGORY: + return TypeCategoryTypePattern.read(s, context); } throw new BCException("unknown TypePattern kind: " + key); } @@ -335,15 +338,15 @@ public abstract class TypePattern extends PatternNode { } /** - * For quickly recognizing the pattern '!void' - */ + * For quickly recognizing the pattern '!void' + */ public boolean isBangVoid() { return false; } - /** - * for quickly recognizing the pattern 'void' - */ + /** + * for quickly recognizing the pattern 'void' + */ public boolean isVoid() { return false; } diff --git a/org.aspectj.matcher/testsrc/org/aspectj/weaver/patterns/DumpPointcutVisitor.java b/org.aspectj.matcher/testsrc/org/aspectj/weaver/patterns/DumpPointcutVisitor.java index 621e5f30e..665f4bdda 100644 --- a/org.aspectj.matcher/testsrc/org/aspectj/weaver/patterns/DumpPointcutVisitor.java +++ b/org.aspectj.matcher/testsrc/org/aspectj/weaver/patterns/DumpPointcutVisitor.java @@ -512,6 +512,11 @@ public class DumpPointcutVisitor implements PatternNodeVisitor { return null; } + public Object visit(TypeCategoryTypePattern node, Object data) { + append(node); + return null; + } + public static void check(String s) { check(Pointcut.fromString(s), false); } -- 2.39.5