From 1c74d72fe4fe63b16f09e9613b7afd2c9510d64c Mon Sep 17 00:00:00 2001 From: Pavel Vojtechovsky Date: Wed, 11 Jan 2017 20:34:35 +0100 Subject: [PATCH 1/5] remove unused imports --- src/test/java/spoon/test/template/TemplateTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/spoon/test/template/TemplateTest.java b/src/test/java/spoon/test/template/TemplateTest.java index b08bbd410f9..a686f96393a 100644 --- a/src/test/java/spoon/test/template/TemplateTest.java +++ b/src/test/java/spoon/test/template/TemplateTest.java @@ -19,7 +19,6 @@ import spoon.reflect.visitor.filter.NameFilter; import spoon.support.compiler.FileSystemFile; import spoon.support.template.Parameters; -import spoon.template.Substitution; import spoon.template.TemplateMatcher; import spoon.test.template.testclasses.SecurityCheckerTemplate; @@ -28,7 +27,6 @@ import java.rmi.Remote; import java.util.ArrayList; import java.util.Date; -import java.util.LinkedList; import java.util.List; import static org.junit.Assert.assertEquals; From 5b107d8f32526eea36a29d1973e2aead4b728096 Mon Sep 17 00:00:00 2001 From: Pavel Vojtechovsky Date: Wed, 11 Jan 2017 20:36:26 +0100 Subject: [PATCH 2/5] TemplateMatcher implemented as Filter --- .../java/spoon/template/TemplateMatcher.java | 43 +++++++------------ 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/src/main/java/spoon/template/TemplateMatcher.java b/src/main/java/spoon/template/TemplateMatcher.java index 59ae1ca216e..83aa37cab8f 100644 --- a/src/main/java/spoon/template/TemplateMatcher.java +++ b/src/main/java/spoon/template/TemplateMatcher.java @@ -37,6 +37,7 @@ import spoon.reflect.reference.CtTypeParameterReference; import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.CtScanner; +import spoon.reflect.visitor.Filter; import spoon.reflect.visitor.Query; import spoon.reflect.visitor.filter.InvocationFilter; import spoon.support.template.DefaultParameterMatcher; @@ -58,7 +59,7 @@ /** * This class defines an engine for matching a template to pieces of code. */ -public class TemplateMatcher { +public class TemplateMatcher implements Filter { private List> getMethods(CtClass> root) { CtExecutableReference methodRef = root.getFactory().Executable() @@ -132,6 +133,7 @@ private List> getVarargs(CtClass> root * Constructs a matcher for a given template. * */ + @SuppressWarnings("unchecked") public TemplateMatcher(CtElement templateRoot) { this.templateType = templateRoot.getParent(CtClass.class); this.templateRoot = templateRoot; @@ -139,7 +141,10 @@ public TemplateMatcher(CtElement templateRoot) { typeVariables = getTemplateTypeParameters(templateType); names = getTemplateNameParameters(templateType); varArgs = getVarargs(templateType, variables); - this.templateType = templateType; + //check that template matches itself + if (helperMatch(this.templateRoot, this.templateRoot) == false) { + throw new SpoonException("TemplateMatcher was unable to find itself, it certainly indicates a bug. Please revise your template or report an issue."); + } } private boolean addMatch(Object template, Object target) { @@ -177,31 +182,7 @@ private CtElement checkListStatements(List teList) { * @return the matched elements */ public List find(final CtElement targetRoot) { - CtScanner scanner = new CtScanner() { - @Override - public void scan(CtElement element) { - if (match(element, templateRoot)) { - finds.add(element); - // matches.clear(); - } - super.scan(element); - } - }; - - scanner.scan(templateRoot); - if (!finds.contains(templateRoot)) { - throw new SpoonException("TemplateMatcher was unable to find itself, it certainly indicates a bug. Please revise your template or report an issue."); - } - finds.clear(); - - scanner.scan(targetRoot); - - // This case can occur when we are scanning the entire package for example see TemplateTest#testTemplateMatcherWithWholePackage - if (finds.contains(templateRoot)) { - finds.remove(templateRoot); - } - - return (List) finds; + return (List) targetRoot.filterChildren(this).list(); } /** @@ -476,7 +457,13 @@ private boolean isCurrentTemplate(Object object, CtElement inMulti) { * @return true if matches * @see #getMatches() */ - private boolean match(CtElement targetRoot, CtElement templateRoot) { + @Override + public boolean matches(CtElement targetRoot) { + if (targetRoot == templateRoot) { + // This case can occur when we are scanning the entire package for example see TemplateTest#testTemplateMatcherWithWholePackage + // Correct template matches itself of course, but client does not want that + return false; + } return helperMatch(targetRoot, templateRoot); } From 47ecfdf9c539872b400556dc7703f47b91f00177 Mon Sep 17 00:00:00 2001 From: Pavel Vojtechovsky Date: Wed, 11 Jan 2017 22:17:54 +0100 Subject: [PATCH 3/5] explicitly use TemplateMatcher as Filter of a query --- src/test/java/spoon/test/template/TemplateTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/java/spoon/test/template/TemplateTest.java b/src/test/java/spoon/test/template/TemplateTest.java index a686f96393a..a8ba53e4581 100644 --- a/src/test/java/spoon/test/template/TemplateTest.java +++ b/src/test/java/spoon/test/template/TemplateTest.java @@ -416,6 +416,7 @@ public void testTemplateMatcherMatchTwoSnippets() throws Exception { CtIf templateRoot = (CtIf) templateMethod.getBody().getStatement(0); TemplateMatcher matcher = new TemplateMatcher(templateRoot); + //match using legacy TemplateMatcher#find method List matches = matcher.find(factory.getModel().getRootPackage()); assertEquals(2, matches.size()); @@ -424,5 +425,15 @@ public void testTemplateMatcherMatchTwoSnippets() throws Exception { CtElement match2 = matches.get(1); assertTrue(match1.equals(match2)); + + //match using TemplateMatcher#matches method and query filter + matches = factory.getModel().getRootPackage().filterChildren(matcher).list(); + + assertEquals(2, matches.size()); + + match1 = matches.get(0); + match2 = matches.get(1); + + assertTrue(match1.equals(match2)); } } From f611c7f16f6e65e53908ad4de9cad47f5264666b Mon Sep 17 00:00:00 2001 From: Pavel Vojtechovsky Date: Thu, 12 Jan 2017 15:31:41 +0100 Subject: [PATCH 4/5] documentation added --- doc/matcher.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/matcher.md b/doc/matcher.md index 66c92e27359..a1b64f33eac 100644 --- a/doc/matcher.md +++ b/doc/matcher.md @@ -30,7 +30,7 @@ To define a template matcher one must: 1. specify the "holes" of the template matcher 1. write the matcher in a dedicated method -1. instantiate TemplateMatcher and call method `find`. +1. instantiate TemplateMatcher and call method `find` or use it as Filter of a query. Taking again the same example. @@ -53,9 +53,9 @@ CtClass templateKlass = factory.Class().get(CheckBoundMatcher.class); CtIf templateRoot = (CtIf) ((CtMethod) templateKlass.getElements(new NameFilter("matcher1")).get(0)).getBody().getStatement(0); TemplateMatcher matcher = new TemplateMatcher(templateRoot); for (CtElement elems : matcher.find(aPackage)) { ... }; - +//or TemplateMatcher as a Filter of query +aPackage.filterChildren(matcher).forEach((CtElement elem)->{ ... }); ``` For named elements, a wildcard can be specified: if the named element (eg a method) to be matched is called `f` and the template matcher class contains a template parameter called `f` (of type Object), all methods starting by `f` will be matched. - From 89ef107cc98cb009d9442cb7f739122c429d6ae3 Mon Sep 17 00:00:00 2001 From: Pavel Vojtechovsky Date: Thu, 12 Jan 2017 15:43:18 +0100 Subject: [PATCH 5/5] fix the type cast --- src/main/java/spoon/template/TemplateMatcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/spoon/template/TemplateMatcher.java b/src/main/java/spoon/template/TemplateMatcher.java index 83aa37cab8f..8445c46b6a5 100644 --- a/src/main/java/spoon/template/TemplateMatcher.java +++ b/src/main/java/spoon/template/TemplateMatcher.java @@ -182,7 +182,7 @@ private CtElement checkListStatements(List teList) { * @return the matched elements */ public List find(final CtElement targetRoot) { - return (List) targetRoot.filterChildren(this).list(); + return targetRoot.filterChildren(this).list(); } /**