You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by cc...@apache.org on 2015/10/07 21:26:46 UTC

[26/37] incubator-groovy git commit: ASTMatcher: First bits of work for wildcard matching

ASTMatcher: First bits of work for wildcard matching


Project: http://git-wip-us.apache.org/repos/asf/incubator-groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-groovy/commit/1cd27ea2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-groovy/tree/1cd27ea2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-groovy/diff/1cd27ea2

Branch: refs/heads/master
Commit: 1cd27ea261a9eb712234e996115dcc5d3f039f53
Parents: 4b7db4c
Author: Cedric Champeau <ce...@gmail.com>
Authored: Fri Oct 17 16:05:26 2014 +0200
Committer: Sergei Egorov <bs...@gmail.com>
Committed: Mon Sep 28 14:33:11 2015 +0300

----------------------------------------------------------------------
 .../groovy/macro/matcher/ASTMatcher.groovy      | 240 ++++++++++---------
 .../groovy/macro/matcher/ASTMatcherTest.groovy  |  30 +++
 2 files changed, 157 insertions(+), 113 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/1cd27ea2/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/ASTMatcher.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/ASTMatcher.groovy b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/ASTMatcher.groovy
index 0020aeb..858924b 100644
--- a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/ASTMatcher.groovy
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/ASTMatcher.groovy
@@ -32,6 +32,8 @@ import org.codehaus.groovy.control.SourceUnit
 @CompileStatic
 class ASTMatcher extends ClassCodeVisitorSupport {
 
+    public static final String WILDCARD = "_";
+
     private Object current = null
     private boolean match = true
 
@@ -66,6 +68,14 @@ class ASTMatcher extends ClassCodeVisitorSupport {
         match = match && value
     }
 
+    private static boolean matchByName(String a, String b) {
+        return a.equals(b) || WILDCARD.equals(a) || WILDCARD.equals(b);
+    }
+
+    private static boolean isWildcardExpression(Object exp) {
+        return exp instanceof VariableExpression && WILDCARD.equals(exp.getName());
+    }
+
     /**
      * Locates all nodes in the given AST which match the pattern AST.
      * This operation can cost a lot, because it tries to match a sub-tree
@@ -81,10 +91,14 @@ class ASTMatcher extends ClassCodeVisitorSupport {
         finder.matches
     }
 
-    private void doWithNode(Class expectedClass, Object next, Closure cl) {
+    private void doWithNode(Object search, Object next, Closure cl) {
+        Class expectedClass = search?search.class:Object
         if (expectedClass == null) {
             expectedClass = Object
         }
+        if (isWildcardExpression(search)) {
+            return
+        }
         if (match && (next == null || expectedClass.isAssignableFrom(next.class))) {
             Object old = current
             current = next
@@ -97,12 +111,12 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitClass(final ClassNode node) {
-        doWithNode(ClassNode, current) {
+        doWithNode(node, current) {
             visitAnnotations(node)
-            doWithNode(PackageNode, ((ClassNode) current).package) {
+            doWithNode(node.package, ((ClassNode) current).package) {
                 visitPackage(node.package)
             }
-            doWithNode(ModuleNode, ((ClassNode) current).module) {
+            doWithNode(node.module, ((ClassNode) current).module) {
                 visitImports(node.module)
             }
 
@@ -123,7 +137,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                 def iter = curProps.iterator()
                 // now let's visit the contents of the class
                 for (PropertyNode pn : nodeProps) {
-                    doWithNode(pn.class, iter.next()) {
+                    doWithNode(pn, iter.next()) {
                         visitProperty(pn)
                     }
                 }
@@ -133,7 +147,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                 if (nodeFields.size() == curFields.size()) {
                     iter = curFields.iterator()
                     for (FieldNode fn : nodeFields) {
-                        doWithNode(fn.class, iter.next()) {
+                        doWithNode(fn, iter.next()) {
                             visitField(fn)
                         }
                     }
@@ -143,7 +157,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                     if (nodeConstructors.size() == curConstructors.size()) {
                         iter = curConstructors.iterator()
                         for (ConstructorNode cn : nodeConstructors) {
-                            doWithNode(cn.class, iter.next()) {
+                            doWithNode(cn, iter.next()) {
                                 visitConstructor(cn)
                             }
                         }
@@ -153,7 +167,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                         if (nodeMethods.size() == curMethods.size()) {
                             iter = curMethods.iterator()
                             for (MethodNode mn : nodeMethods) {
-                                doWithNode(mn.class, iter.next()) {
+                                doWithNode(mn, iter.next()) {
                                     visitMethod(mn)
                                 }
                             }
@@ -162,18 +176,18 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                     }
                 }
             }
-            failIfNot(cur.name == node.name)
+            failIfNot(matchByName(cur.name,node.name))
         }
     }
 
     @Override
     protected void visitObjectInitializerStatements(final ClassNode node) {
-        doWithNode(ClassNode, current) {
+        doWithNode(node, current) {
             def initializers = ((ClassNode) current).objectInitializerStatements
             if (initializers.size() == node.objectInitializerStatements.size()) {
                 def iterator = initializers.iterator()
                 for (Statement element : node.objectInitializerStatements) {
-                    doWithNode(element.class, iterator.next()) {
+                    doWithNode(element, iterator.next()) {
                         element.visit(this)
                     }
                 }
@@ -186,7 +200,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
     @Override
     public void visitPackage(final PackageNode node) {
         if (node) {
-            doWithNode(node.class, current) {
+            doWithNode(node, current) {
                 visitAnnotations(node)
                 node.visit(this)
             }
@@ -196,13 +210,13 @@ class ASTMatcher extends ClassCodeVisitorSupport {
     @Override
     public void visitImports(final ModuleNode node) {
         if (node) {
-            doWithNode(ModuleNode, current) {
+            doWithNode(node, current) {
                 ModuleNode module = (ModuleNode) current
                 def imports = module.imports
                 if (imports.size() == node.imports.size()) {
                     def iter = imports.iterator()
                     for (ImportNode importNode : node.imports) {
-                        doWithNode(importNode.class, iter.next()) {
+                        doWithNode(importNode, iter.next()) {
                             visitAnnotations(importNode)
                             importNode.visit(this)
                         }
@@ -215,7 +229,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                 if (imports.size() == node.starImports.size()) {
                     def iter = imports.iterator()
                     for (ImportNode importNode : node.starImports) {
-                        doWithNode(importNode.class, iter.next()) {
+                        doWithNode(importNode, iter.next()) {
                             visitAnnotations(importNode)
                             importNode.visit(this)
                         }
@@ -228,7 +242,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                 if (imports.size() == node.staticImports.size()) {
                     def iter = imports.values().iterator()
                     for (ImportNode importNode : node.staticImports.values()) {
-                        doWithNode(importNode.class, iter.next()) {
+                        doWithNode(importNode, iter.next()) {
                             visitAnnotations(importNode)
                             importNode.visit(this)
                         }
@@ -240,7 +254,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                 if (imports.size() == node.staticStarImports.size()) {
                     def iter = imports.values().iterator()
                     for (ImportNode importNode : node.staticStarImports.values()) {
-                        doWithNode(importNode.class, iter.next()) {
+                        doWithNode(importNode, iter.next()) {
                             visitAnnotations(importNode)
                             importNode.visit(this)
                         }
@@ -254,7 +268,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitAnnotations(final AnnotatedNode node) {
-        doWithNode(AnnotatedNode, current) {
+        doWithNode(node, current) {
             List<AnnotationNode> refAnnotations = node.annotations
             AnnotatedNode cur = (AnnotatedNode) current
             List<AnnotationNode> curAnnotations = cur.annotations
@@ -282,7 +296,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                     for (Map.Entry<String, Expression> member : refEntrySet) {
                         def next = entryIt.next()
                         if (next.key == member.key) {
-                            doWithNode(member.value.class, next.value) {
+                            doWithNode(member.value, next.value) {
                                 member.value.visit(this)
                             }
                         } else {
@@ -298,7 +312,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     protected void visitClassCodeContainer(final Statement code) {
-        doWithNode(Statement, current) {
+        doWithNode(code, current) {
             if (code) {
                 code.visit(this)
             }
@@ -308,24 +322,24 @@ class ASTMatcher extends ClassCodeVisitorSupport {
     @Override
     @CompileStatic(TypeCheckingMode.SKIP)
     public void visitDeclarationExpression(final DeclarationExpression expression) {
-        doWithNode(DeclarationExpression, current) {
+        doWithNode(expression, current) {
             super.visitDeclarationExpression(expression)
         }
     }
 
     @Override
     protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) {
-        doWithNode(MethodNode, current) {
+        doWithNode(node, current) {
             visitAnnotations(node)
             def cur = (MethodNode) current
-            doWithNode(Statement, cur.code) {
+            doWithNode(node.code, cur.code) {
                 visitClassCodeContainer(node.code)
             }
             def params = node.parameters
             def curParams = cur.parameters
             if (params.length == curParams.length) {
                 params.eachWithIndex { Parameter entry, int i ->
-                    doWithNode(entry.class, curParams[i]) {
+                    doWithNode(entry, curParams[i]) {
                         visitAnnotations(entry)
                     }
                 }
@@ -337,10 +351,10 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitField(final FieldNode node) {
-        doWithNode(FieldNode, current) {
+        doWithNode(node, current) {
             visitAnnotations(node)
             def fieldNode = (FieldNode) current
-            failIfNot(fieldNode.name == node.name)
+            failIfNot(matchByName(fieldNode.name,node.name))
             failIfNot(fieldNode.originType == node.originType)
             failIfNot(fieldNode.modifiers == node.modifiers)
 
@@ -349,7 +363,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
             Expression curInit = fieldNode.initialExpression
             if (init) {
                 if (curInit) {
-                    doWithNode(init.class, curInit) {
+                    doWithNode(init, curInit) {
                         init.visit(this)
                     }
                 } else {
@@ -363,19 +377,19 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitProperty(final PropertyNode node) {
-        doWithNode(PropertyNode, current) {
+        doWithNode(node, current) {
             PropertyNode pNode = (PropertyNode) current
             visitAnnotations(node)
 
             Statement statement = node.getterBlock
             Statement curStatement = pNode.getterBlock
-            doWithNode(statement?.class, curStatement) {
+            doWithNode(statement, curStatement) {
                 visitClassCodeContainer(statement)
             }
 
             statement = node.setterBlock
             curStatement = pNode.setterBlock
-            doWithNode(statement?.class, curStatement) {
+            doWithNode(statement, curStatement) {
                 visitClassCodeContainer(statement)
             }
 
@@ -383,7 +397,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
             Expression curInit = pNode.initialExpression
             if (init) {
                 if (curInit) {
-                    doWithNode(init.class, curInit) {
+                    doWithNode(init, curInit) {
                         init.visit(this)
                     }
                 } else {
@@ -397,7 +411,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     void visitExpressionStatement(final ExpressionStatement statement) {
-        doWithNode(statement.expression.class, ((ExpressionStatement) current).expression) {
+        doWithNode(statement.expression, ((ExpressionStatement) current).expression) {
             visitStatement(statement)
             statement.expression.visit(this)
         }
@@ -405,12 +419,12 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitBlockStatement(BlockStatement block) {
-        doWithNode(BlockStatement, current) {
+        doWithNode(block, current) {
             def statements = ((BlockStatement) current).statements
             if (statements.size() == block.statements.size()) {
                 def iter = statements.iterator()
                 for (Statement statement : block.statements) {
-                    doWithNode(statement.class, iter.next()) {
+                    doWithNode(statement, iter.next()) {
                         statement.visit(this)
                     }
                 }
@@ -422,18 +436,18 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitMethodCallExpression(final MethodCallExpression call) {
-        doWithNode(MethodCallExpression, current) {
+        doWithNode(call, current) {
             def mce = (MethodCallExpression) current
-            doWithNode(call.objectExpression.class, mce.objectExpression) {
+            doWithNode(call.objectExpression, mce.objectExpression) {
                 call.objectExpression.visit(this)
             }
-            doWithNode(call.method.class, mce.method) {
+            doWithNode(call.method, mce.method) {
                 call.method.visit(this)
             }
-            doWithNode(call.arguments.class, mce.arguments) {
+            doWithNode(call.arguments, mce.arguments) {
                 call.arguments.visit(this)
             }
-            failIfNot((call.methodAsString == mce.methodAsString) &&
+            failIfNot(matchByName(call.methodAsString, mce.methodAsString) &&
                     (call.safe == mce.safe) &&
                     (call.spreadSafe == mce.spreadSafe) &&
                     (call.implicitThis == mce.implicitThis))
@@ -448,7 +462,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
     @Override
     public void visitConstructorCallExpression(final ConstructorCallExpression call) {
         def cur = (ConstructorCallExpression) current
-        doWithNode(call.arguments.class, cur.arguments) {
+        doWithNode(call.arguments, cur.arguments) {
             call.arguments.visit(this)
             failIfNot(call.type == cur.type)
         }
@@ -456,14 +470,14 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitBinaryExpression(final BinaryExpression expression) {
-        doWithNode(BinaryExpression, current) {
+        doWithNode(expression, current) {
             def bin = (BinaryExpression) current
             def leftExpression = expression.getLeftExpression()
-            doWithNode(leftExpression.class, bin.leftExpression) {
+            doWithNode(leftExpression, bin.leftExpression) {
                 leftExpression.visit(this)
             }
             def rightExpression = expression.getRightExpression()
-            doWithNode(rightExpression.class, bin.rightExpression) {
+            doWithNode(rightExpression, bin.rightExpression) {
                 rightExpression.visit(this)
             }
             if (bin.operation.type != expression.operation.type) {
@@ -474,17 +488,17 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitTernaryExpression(final TernaryExpression expression) {
-        doWithNode(TernaryExpression, current) {
+        doWithNode(expression, current) {
             TernaryExpression te = (TernaryExpression) current
-            doWithNode(BooleanExpression, te.booleanExpression) {
+            doWithNode(expression.booleanExpression, te.booleanExpression) {
                 expression.booleanExpression.visit(this)
             }
             def trueExpression = expression.trueExpression
-            doWithNode(trueExpression.class, te.trueExpression) {
+            doWithNode(trueExpression, te.trueExpression) {
                 trueExpression.visit(this)
             }
             def falseExpression = expression.falseExpression
-            doWithNode(falseExpression.class, te.falseExpression) {
+            doWithNode(falseExpression, te.falseExpression) {
                 falseExpression.visit(this)
             }
         }
@@ -492,10 +506,10 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitPostfixExpression(final PostfixExpression expression) {
-        doWithNode(PostfixExpression, current) {
+        doWithNode(expression, current) {
             def origExpr = expression.expression
             def curExpr = (PostfixExpression) current
-            doWithNode(origExpr.class, curExpr.expression) {
+            doWithNode(origExpr, curExpr.expression) {
                 origExpr.visit(this)
                 failIfNot(expression.operation.type == curExpr.operation.type)
             }
@@ -504,10 +518,10 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitPrefixExpression(final PrefixExpression expression) {
-        doWithNode(PrefixExpression, current) {
+        doWithNode(expression, current) {
             def origExpr = expression.expression
             def curExpr = (PrefixExpression) current
-            doWithNode(origExpr.class, curExpr.expression) {
+            doWithNode(origExpr, curExpr.expression) {
                 origExpr.visit(this)
                 failIfNot(expression.operation.type == curExpr.operation.type)
             }
@@ -516,8 +530,8 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitBooleanExpression(final BooleanExpression expression) {
-        doWithNode(BooleanExpression, current) {
-            doWithNode(expression.expression.class, ((BooleanExpression) current).expression) {
+        doWithNode(expression, current) {
+            doWithNode(expression.expression, ((BooleanExpression) current).expression) {
                 expression.expression.visit(this)
             }
         }
@@ -525,10 +539,10 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitNotExpression(final NotExpression expression) {
-        doWithNode(NotExpression, current) {
+        doWithNode(expression, current) {
             def expr = expression.expression
             def cur = ((NotExpression) current).expression
-            doWithNode(expr.class, cur) {
+            doWithNode(expr, cur) {
                 expr.visit(this)
             }
         }
@@ -536,10 +550,10 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitClosureExpression(final ClosureExpression expression) {
-        doWithNode(ClosureExpression, current) {
+        doWithNode(expression, current) {
             def code = expression.code
             def cl = (ClosureExpression) current
-            doWithNode(code.class, cl.code) {
+            doWithNode(code, cl.code) {
                 code.visit(this)
                 checkParameters(expression.parameters, cl.parameters)
             }
@@ -556,8 +570,8 @@ class ASTMatcher extends ClassCodeVisitorSupport {
                 for (int i = 0; i < nodeParams.length && match; i++) {
                     def n = nodeParams[i]
                     def c = curParams[i]
-                    doWithNode(n.class, c) {
-                        failIfNot((n.name == c.name) &&
+                    doWithNode(n, c) {
+                        failIfNot(matchByName(n.name,c.name) &&
                                 (n.originType == c.originType) &&
                                 (n.type == c.originType))
                     }
@@ -570,8 +584,8 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitTupleExpression(final TupleExpression expression) {
-        doWithNode(TupleExpression, current) {
-            doWithNode(List, ((TupleExpression) current).expressions) {
+        doWithNode(expression, current) {
+            doWithNode(expression.expressions, ((TupleExpression) current).expressions) {
                 visitListOfExpressions(expression.expressions)
             }
         }
@@ -579,9 +593,9 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitListExpression(final ListExpression expression) {
-        doWithNode(ListExpression, current) {
+        doWithNode(expression, current) {
             def exprs = expression.expressions
-            doWithNode(exprs.class, ((ListExpression) current).expressions) {
+            doWithNode(exprs, ((ListExpression) current).expressions) {
                 visitListOfExpressions(exprs)
             }
         }
@@ -589,16 +603,16 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitArrayExpression(final ArrayExpression expression) {
-        doWithNode(ArrayExpression, current) {
+        doWithNode(expression, current) {
             def expressions = expression.expressions
             def size = expression.sizeExpression
             def cur = (ArrayExpression) current
             def curExprs = cur.expressions
             def curSize = cur.sizeExpression
-            doWithNode(expressions.class, curExprs) {
+            doWithNode(expressions, curExprs) {
                 visitListOfExpressions(expressions)
             }
-            doWithNode(size.class, curSize) {
+            doWithNode(size, curSize) {
                 visitListOfExpressions(size)
             }
             failIfNot(expression.elementType == cur.elementType)
@@ -607,10 +621,10 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitMapExpression(final MapExpression expression) {
-        doWithNode(MapExpression, current) {
+        doWithNode(expression, current) {
             def entries = expression.mapEntryExpressions
             def curEntries = ((MapExpression) current).mapEntryExpressions
-            doWithNode(entries.class, curEntries) {
+            doWithNode(entries, curEntries) {
                 visitListOfExpressions(entries)
             }
         }
@@ -618,16 +632,16 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitMapEntryExpression(final MapEntryExpression expression) {
-        doWithNode(MapEntryExpression, current) {
+        doWithNode(expression, current) {
             def key = expression.keyExpression
             def value = expression.valueExpression
             def cur = (MapEntryExpression) current
             def curKey = cur.keyExpression
             def curValue = cur.valueExpression
-            doWithNode(key.class, curKey) {
+            doWithNode(key, curKey) {
                 key.visit(this)
             }
-            doWithNode(value.class, curValue) {
+            doWithNode(value, curValue) {
                 value.visit(this)
             }
         }
@@ -635,16 +649,16 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitRangeExpression(final RangeExpression expression) {
-        doWithNode(RangeExpression, current) {
+        doWithNode(expression, current) {
             def from = expression.from
             def to = expression.to
             def cur = (RangeExpression) current
             def curFrom = cur.from
             def curTo = cur.to
-            doWithNode(from.class, curFrom) {
+            doWithNode(from, curFrom) {
                 from.visit(this)
             }
-            doWithNode(to.class, curTo) {
+            doWithNode(to, curTo) {
                 to.visit(this)
             }
         }
@@ -652,9 +666,9 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitSpreadExpression(final SpreadExpression expression) {
-        doWithNode(SpreadExpression, current) {
+        doWithNode(expression, current) {
             def expr = expression.expression
-            doWithNode(expr.class, ((SpreadExpression) current).expression) {
+            doWithNode(expr, ((SpreadExpression) current).expression) {
                 expr.visit(this)
             }
         }
@@ -667,16 +681,16 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitMethodPointerExpression(final MethodPointerExpression expression) {
-        doWithNode(MethodPointerExpression, current) {
+        doWithNode(expression, current) {
             def cur = (MethodPointerExpression) current
             def expr = expression.expression
             def methodName = expression.methodName
             def curExpr = cur.expression
             def curName = cur.methodName
-            doWithNode(expr.class, curExpr) {
+            doWithNode(expr, curExpr) {
                 expr.visit(this)
             }
-            doWithNode(methodName.class, curName) {
+            doWithNode(methodName, curName) {
                 methodName.visit(this)
             }
         }
@@ -684,9 +698,9 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitUnaryMinusExpression(final UnaryMinusExpression expression) {
-        doWithNode(UnaryMinusExpression, current) {
+        doWithNode(expression, current) {
             def expr = expression.expression
-            doWithNode(expr.class, ((UnaryMinusExpression) current).expression) {
+            doWithNode(expr, ((UnaryMinusExpression) current).expression) {
                 expr.visit(this)
             }
         }
@@ -694,9 +708,9 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitUnaryPlusExpression(final UnaryPlusExpression expression) {
-        doWithNode(UnaryPlusExpression, current) {
+        doWithNode(expression, current) {
             def expr = expression.expression
-            doWithNode(expr.class, ((UnaryPlusExpression) current).expression) {
+            doWithNode(expr, ((UnaryPlusExpression) current).expression) {
                 expr.visit(this)
             }
         }
@@ -704,9 +718,9 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitBitwiseNegationExpression(final BitwiseNegationExpression expression) {
-        doWithNode(BitwiseNegationExpression, current) {
+        doWithNode(expression, current) {
             def expr = expression.expression
-            doWithNode(expr.class, ((BitwiseNegationExpression) current).expression) {
+            doWithNode(expr, ((BitwiseNegationExpression) current).expression) {
                 expr.visit(this)
             }
         }
@@ -714,9 +728,9 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitCastExpression(final CastExpression expression) {
-        doWithNode(CastExpression, current) {
+        doWithNode(expression, current) {
             def expr = expression.expression
-            doWithNode(expr.class, ((CastExpression) current).expression) {
+            doWithNode(expr, ((CastExpression) current).expression) {
                 expr.visit(this)
             }
             failIfNot(expression.type == ((CastExpression) current).type)
@@ -726,7 +740,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
     @Override
     @CompileStatic(TypeCheckingMode.SKIP)
     public void visitConstantExpression(final ConstantExpression expression) {
-        doWithNode(ConstantExpression, current) {
+        doWithNode(expression, current) {
             def cur = (ConstantExpression) current
             super.visitConstantExpression(expression)
             failIfNot((expression.type == cur.type) &&
@@ -737,7 +751,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
     @Override
     @CompileStatic(TypeCheckingMode.SKIP)
     public void visitClassExpression(final ClassExpression expression) {
-        doWithNode(ClassExpression, current) {
+        doWithNode(expression, current) {
             super.visitClassExpression(expression)
             def cexp = (ClassExpression) current
             failIfNot(cexp.type == expression.type)
@@ -746,9 +760,9 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitVariableExpression(final VariableExpression expression) {
-        doWithNode(VariableExpression, current) {
+        doWithNode(expression, current) {
             def curVar = (VariableExpression) current
-            failIfNot((expression.name == curVar.name) &&
+            failIfNot(matchByName(expression.name,curVar.name) &&
                     (expression.type == curVar.type) &&
                     (expression.originType == curVar.originType))
         }
@@ -756,12 +770,12 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitPropertyExpression(final PropertyExpression expression) {
-        doWithNode(PropertyExpression, current) {
+        doWithNode(expression, current) {
             def currentPexp = (PropertyExpression) current
-            doWithNode(expression.objectExpression.class, currentPexp.objectExpression) {
+            doWithNode(expression.objectExpression, currentPexp.objectExpression) {
                 expression.objectExpression.visit(this)
             }
-            doWithNode(expression.property.class, currentPexp.property) {
+            doWithNode(expression.property, currentPexp.property) {
                 expression.property.visit(this)
             }
             failIfNot((expression.propertyAsString == currentPexp.propertyAsString) &&
@@ -773,12 +787,12 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitAttributeExpression(final AttributeExpression expression) {
-        doWithNode(AttributeExpression, current) {
+        doWithNode(expression, current) {
             def currentPexp = (AttributeExpression) current
-            doWithNode(expression.objectExpression.class, currentPexp.objectExpression) {
+            doWithNode(expression.objectExpression, currentPexp.objectExpression) {
                 expression.objectExpression.visit(this)
             }
-            doWithNode(expression.property.class, currentPexp.property) {
+            doWithNode(expression.property, currentPexp.property) {
                 expression.property.visit(this)
             }
             failIfNot((expression.propertyAsString == currentPexp.propertyAsString) &&
@@ -795,16 +809,16 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitGStringExpression(final GStringExpression expression) {
-        doWithNode(GStringExpression, current) {
+        doWithNode(expression, current) {
             def cur = (GStringExpression) current
             def strings = expression.strings
             def values = expression.values
             def curStrings = cur.strings
             def curValues = cur.values
-            doWithNode(strings.class, curStrings) {
+            doWithNode(strings, curStrings) {
                 visitListOfExpressions(strings)
             }
-            doWithNode(values.class, curValues) {
+            doWithNode(values, curValues) {
                 visitListOfExpressions(values)
             }
         }
@@ -821,7 +835,7 @@ class ASTMatcher extends ClassCodeVisitorSupport {
         def iter = currentExprs.iterator()
         for (Expression expression : list) {
             def next = iter.next()
-            doWithNode(expression.class, next) {
+            doWithNode(expression, next) {
                 expression.visit(this)
             }
         }
@@ -834,9 +848,9 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     public void visitClosureListExpression(final ClosureListExpression cle) {
-        doWithNode(ClosureListExpression, current) {
+        doWithNode(cle, current) {
             def exprs = cle.expressions
-            doWithNode(exprs.class, ((ClosureListExpression)current).expressions) {
+            doWithNode(exprs, ((ClosureListExpression)current).expressions) {
                 visitListOfExpressions(exprs)
             }
         }
@@ -849,20 +863,20 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     void visitIfElse(final IfStatement ifElse) {
-        doWithNode(IfStatement, current) {
+        doWithNode(ifElse, current) {
             visitStatement(ifElse)
             def cur = (IfStatement) current
             def bool = ifElse.booleanExpression
             def ifBlock = ifElse.ifBlock
             def elseBlock = ifElse.elseBlock
-            doWithNode(bool.class, cur.booleanExpression) {
+            doWithNode(bool, cur.booleanExpression) {
                 bool.visit(this)
             }
-            doWithNode(ifBlock.class, cur.ifBlock) {
+            doWithNode(ifBlock, cur.ifBlock) {
                 ifBlock.visit(this)
             }
             failIfNot(elseBlock && cur.elseBlock || !elseBlock && !cur.elseBlock)
-            doWithNode(elseBlock.class, cur.elseBlock) {
+            doWithNode(elseBlock, cur.elseBlock) {
                 elseBlock.visit(this)
             }
         }
@@ -870,15 +884,15 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     void visitForLoop(final ForStatement forLoop) {
-        doWithNode(ForStatement, current) {
+        doWithNode(forLoop, current) {
             visitStatement(forLoop)
             def cur = (ForStatement) current
             def col = forLoop.collectionExpression
             def block = forLoop.loopBlock
-            doWithNode(col.class, cur.collectionExpression) {
+            doWithNode(col, cur.collectionExpression) {
                 col.visit(this)
             }
-            doWithNode(block.class, cur.loopBlock) {
+            doWithNode(block, cur.loopBlock) {
                 block.visit(this)
             }
         }
@@ -886,15 +900,15 @@ class ASTMatcher extends ClassCodeVisitorSupport {
 
     @Override
     void visitWhileLoop(final WhileStatement loop) {
-        doWithNode(WhileStatement, current) {
+        doWithNode(loop, current) {
             visitStatement(loop)
             def cur = (WhileStatement) current
             def bool = loop.booleanExpression
             def block = loop.loopBlock
-            doWithNode(bool.class, cur.booleanExpression) {
+            doWithNode(bool, cur.booleanExpression) {
                 bool.visit(this)
             }
-            doWithNode(block.class, cur.loopBlock) {
+            doWithNode(block, cur.loopBlock) {
                 block.visit(this)
             }
         }

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/1cd27ea2/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy b/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy
index 9c02e65..e1e88a3 100644
--- a/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy
+++ b/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy
@@ -574,4 +574,34 @@ class ASTMatcherTest extends GroovyTestCase {
         assert !ASTMatcher.matches(ast1, ast3)
         assert !ASTMatcher.matches(ast1, ast4)
     }
+
+    void testWildcardMatchVariable() {
+        def ast1 = macro { a }
+        def ast2 = macro { _ }
+        def ast3 = macro { b }
+        assert ASTMatcher.matches(ast1, ast2)
+        assert ASTMatcher.matches(ast2, ast3)
+    }
+
+    void testWildcardMatchVariableInBinaryExpression() {
+        def ast1 = macro { a+b }
+        def ast2 = macro { _+_ }
+        def ast3 = macro { _+c }
+        def ast4 = macro { c+_ }
+        def ast5 = macro { a+_ }
+        def ast6 = macro { _+b }
+        assert ASTMatcher.matches(ast1, ast2)
+        assert !ASTMatcher.matches(ast1, ast3)
+        assert !ASTMatcher.matches(ast1, ast4)
+        assert ASTMatcher.matches(ast1, ast5)
+        assert ASTMatcher.matches(ast1, ast6)
+    }
+
+    void testWildcardForSubExpression() {
+        def ast1 = macro { a+foo(b) }
+        def ast2 = macro { _+foo(b) }
+        def ast3 = macro { a+_ }
+        //assert ASTMatcher.matches(ast1, ast2)
+        assert ASTMatcher.matches(ast1, ast3)
+    }
 }