]> source.dussan.org Git - aspectj.git/commitdiff
44365: is() support in type patterns
authoraclement <aclement>
Fri, 19 Mar 2010 15:42:00 +0000 (15:42 +0000)
committeraclement <aclement>
Fri, 19 Mar 2010 15:42:00 +0000 (15:42 +0000)
org.aspectj.matcher/src/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java
org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternNodeVisitor.java
org.aspectj.matcher/src/org/aspectj/weaver/patterns/PatternParser.java
org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypeCategoryTypePattern.java [new file with mode: 0644]
org.aspectj.matcher/src/org/aspectj/weaver/patterns/TypePattern.java
org.aspectj.matcher/testsrc/org/aspectj/weaver/patterns/DumpPointcutVisitor.java

index 14234438c5b760006bfd0b141b30c96449631492..6558c3c21bd3edacef211931487454442f15ca20 100644 (file)
@@ -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;
+       }
 }
index 3fedd718ead39a01fa8c89a7e5884130288e0a66..336a33e51618fab465a90125e792efaa30393ef7 100644 (file)
@@ -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);
index 93dfeee51635396c6359b40ecc383040a96682d2..48d6c9674c5da02226b564fceafc9a134c7adfda 100644 (file)
@@ -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<NamePattern> names = parseDottedNamePattern();
 
                int dim = 0;
@@ -914,6 +950,75 @@ public class PatternParser {
                return ret;
        }
 
+       /**
+        * Attempt to parse a typeIs(<category>) 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 (file)
index 0000000..06c51db
--- /dev/null
@@ -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;
+       }
+
+}
index eb20202346836416223fb894e4b30cb07e72c198..f77352fcc67915497696ee2205ffbbb41bbf589d 100644 (file)
@@ -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;
        }
index 621e5f30e49288970213fad0576c5c6bf21985c0..665f4bdda55800efaeb82f31cc7eeee0ec0fbf11 100644 (file)
@@ -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);
        }