From 24e6e0b7941765953635b2a82684a8babc106d75 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Wed, 21 Feb 2018 14:34:19 +0100 Subject: [PATCH 01/26] add unique path to element getter --- .../spoon/reflect/declaration/CtElement.java | 8 ++ .../reflect/path/CtElementPathBuilder.java | 67 +++++++++++++++ .../reflect/path/CtPathStringBuilder.java | 8 +- .../path/impl/CtUniqueRolePathElement.java | 76 +++++++++++++++++ .../reflect/declaration/CtElementImpl.java | 8 ++ .../spoon/test/path/UniqueRolePathTest.java | 82 +++++++++++++++++++ 6 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 src/main/java/spoon/reflect/path/CtElementPathBuilder.java create mode 100644 src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java create mode 100644 src/test/java/spoon/test/path/UniqueRolePathTest.java diff --git a/src/main/java/spoon/reflect/declaration/CtElement.java b/src/main/java/spoon/reflect/declaration/CtElement.java index 2488f2b310c..b79419679ca 100644 --- a/src/main/java/spoon/reflect/declaration/CtElement.java +++ b/src/main/java/spoon/reflect/declaration/CtElement.java @@ -19,6 +19,8 @@ import spoon.processing.FactoryAccessor; import spoon.reflect.code.CtComment; import spoon.reflect.cu.SourcePosition; +import spoon.reflect.path.CtPath; +import spoon.reflect.path.CtPathException; import spoon.reflect.path.CtRole; import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.CtVisitable; @@ -349,4 +351,10 @@ List getAnnotatedChildren( * @param value to be assigned to this field. */ E setValueByRole(CtRole role, T value); + + /** + * Gets a unique path from models root to the CtElement. + */ + CtPath getPath() throws CtPathException; + } diff --git a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java new file mode 100644 index 00000000000..85c80634289 --- /dev/null +++ b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java @@ -0,0 +1,67 @@ +package spoon.reflect.path; + +import spoon.reflect.declaration.CtElement; +import spoon.reflect.declaration.CtNamedElement; +import spoon.reflect.path.impl.CtPathElement; +import spoon.reflect.path.impl.CtPathImpl; +import spoon.reflect.path.impl.CtUniqueRolePathElement; +import spoon.reflect.reference.CtReference; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class CtElementPathBuilder { + public CtPath fromElement(CtElement el, CtElement root) throws CtPathException { + CtPathImpl path = new CtPathImpl(); + CtElement cur = el; + while(cur != root) { + CtElement parent = cur.getParent(); + CtRole role = cur.getRoleInParent(); + if(parent == null || role == null) throw new CtPathException(); + CtPathElement pathElement = new CtUniqueRolePathElement(role); + if(parent.getValueByRole(role) instanceof List) { + //Element needs to be differentiated from its brothers + List list = parent.getValueByRole(role); + //Assumes that List's order is deterministic. + int index = 0; + for(Object o : list) { + if(o == cur) break; + index++; + } + pathElement.addArgument("index", index + ""); + } else if (parent.getValueByRole(role) instanceof Set){ + if(!(cur instanceof CtNamedElement) && !(cur instanceof CtReference)) throw new CtPathException(); + //Element needs to be differentiated from its brothers + Set set = parent.getValueByRole(role); + String name = null; + for(Object o : set) { + if(o == cur) { + if(cur instanceof CtNamedElement) + name = ((CtNamedElement) cur).getSimpleName(); + else name = ((CtReference) cur).getSimpleName(); + break; + } + } + if(name == null) throw new CtPathException(); + else pathElement.addArgument("name", name); + + } else if (parent.getValueByRole(role) instanceof Map){ + Map map = parent.getValueByRole(role); + String key = null; + for(Object o : map.keySet()) { + if(map.get(o) == cur) { + key = (String) o; + break; + } + } + if(key == null) throw new CtPathException(); + else pathElement.addArgument("key", key); + } + cur = parent; + path.addFirst(pathElement); + } + return path; + } +} diff --git a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java index 96559ab0c18..e4beefeab46 100644 --- a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java +++ b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java @@ -16,11 +16,7 @@ */ package spoon.reflect.path; -import spoon.reflect.path.impl.CtNamedPathElement; -import spoon.reflect.path.impl.CtPathElement; -import spoon.reflect.path.impl.CtPathImpl; -import spoon.reflect.path.impl.CtRolePathElement; -import spoon.reflect.path.impl.CtTypedNameElement; +import spoon.reflect.path.impl.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -81,6 +77,8 @@ public CtPath fromString(String pathStr) throws CtPathException { pathElement = new CtTypedNameElement(load(matcher.group(2))); } else if (CtRolePathElement.STRING.equals(kind)) { pathElement = new CtRolePathElement(CtRole.fromName(matcher.group(2))); + } else if (CtUniqueRolePathElement.STRING.equals(kind)) { + pathElement = new CtRolePathElement(CtRole.fromName(matcher.group(2))); } String args = matcher.group(4); diff --git a/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java new file mode 100644 index 00000000000..646c9b137be --- /dev/null +++ b/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java @@ -0,0 +1,76 @@ +package spoon.reflect.path.impl; + +import spoon.reflect.declaration.CtElement; +import spoon.reflect.declaration.CtNamedElement; +import spoon.reflect.path.CtPathException; +import spoon.reflect.path.CtRole; +import spoon.reflect.reference.CtReference; + +import java.util.*; + +public class CtUniqueRolePathElement extends CtRolePathElement { + public static final String STRING = "@"; + + public CtUniqueRolePathElement(CtRole role) { + super(role); + } + + @Override + public String toString() { + return STRING + getRole().toString() + getParamString(); + } + + public CtElement getFromSet(Set set, String name) throws CtPathException { + for(Object o: set) { + if(o instanceof CtNamedElement) { + if (((CtNamedElement) o).getSimpleName().equals(name)) return (CtElement) o; + } else if(o instanceof CtReference) { + if (((CtReference) o).getSimpleName().equals(name)) return (CtElement) o; + } else { + throw new CtPathException(); + } + } + throw new CtPathException(); + } + + @Override + public Collection getElements(Collection roots) { + Collection matchs = new LinkedList<>(); + for (CtElement root : roots) { + //if(root.getValueByRole(getRole()) instanceof Collection) { + if(root.getValueByRole(getRole()) instanceof List) { + if(getArguments().containsKey("index")) { + int index = Integer.parseInt(getArguments().get("index")); + matchs.add((CtElement) ((List) root.getValueByRole(getRole())).get(index)); + } else { + //Either trhow an exception or add the collection to matches + //matchs.add(el); + } + } else if(root.getValueByRole(getRole()) instanceof Set) { + if(getArguments().containsKey("name")) { + String name = getArguments().get("name"); + try { + matchs.add(getFromSet((Set) root.getValueByRole(getRole()), name)); + } catch (Exception e) { + System.err.println("[ERROR] Element not found for name: " + name); + } + } else { + //Either trhow an exception or add the collection to matches + //matchs.add(el); + } + } else if(root.getValueByRole(getRole()) instanceof Map) { + if(getArguments().containsKey("key")) { + String name = getArguments().get("key"); + matchs.add((CtElement) ((Map) root.getValueByRole(getRole())).get(name)); + } else { + //Either trhow an exception or add the collection to matches + //matchs.add(el); + } + } else { + CtElement el = root.getValueByRole(getRole()); + matchs.add(el); + } + } + return matchs; + } +} diff --git a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java index a0c67b854a8..09f437ef6a6 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java @@ -17,6 +17,7 @@ package spoon.support.reflect.declaration; import org.apache.log4j.Logger; +import spoon.reflect.CtModelImpl; import spoon.reflect.annotations.MetamodelPropertyField; import spoon.reflect.code.CtComment; import spoon.reflect.code.CtJavaDoc; @@ -31,6 +32,9 @@ import spoon.reflect.factory.FactoryImpl; import spoon.reflect.meta.RoleHandler; import spoon.reflect.meta.impl.RoleHandlerHelper; +import spoon.reflect.path.CtElementPathBuilder; +import spoon.reflect.path.CtPath; +import spoon.reflect.path.CtPathException; import spoon.reflect.path.CtRole; import spoon.reflect.declaration.CtImport; import spoon.reflect.reference.CtReference; @@ -536,4 +540,8 @@ public E setValueByRole(CtRole role, T value) { rh.setValue(this, value); return (E) this; } + + public CtPath getPath() throws CtPathException { + return new CtElementPathBuilder().fromElement(this, getParent(CtModelImpl.CtRootPackage.class)); + } } diff --git a/src/test/java/spoon/test/path/UniqueRolePathTest.java b/src/test/java/spoon/test/path/UniqueRolePathTest.java new file mode 100644 index 00000000000..27f46baa98c --- /dev/null +++ b/src/test/java/spoon/test/path/UniqueRolePathTest.java @@ -0,0 +1,82 @@ +package spoon.test.path; + +import org.junit.BeforeClass; +import org.junit.Test; +import spoon.Launcher; +import spoon.MavenLauncher; +import spoon.reflect.CtModel; +import spoon.reflect.CtModelImpl; +import spoon.reflect.declaration.CtElement; +import spoon.reflect.declaration.CtPackage; +import spoon.reflect.path.CtElementPathBuilder; +import spoon.reflect.path.CtPath; +import spoon.reflect.path.CtPathException; +import spoon.reflect.path.CtPathStringBuilder; +import spoon.reflect.visitor.filter.TypeFilter; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class UniqueRolePathTest { + static Launcher launcher; + static CtPackage rootPackage; + + /** + * load model once into static variable and use it for more read-only tests + */ + @BeforeClass + public static void loadModel() { + // we have to remove the test-classes folder + // so that the precondition of --source-classpath is not violated + // (target/test-classes contains src/test/resources which itself contains Java files) + StringBuilder classpath = new StringBuilder(); + for (String classpathEntry : System.getProperty("java.class.path").split(File.pathSeparator)) { + if (!classpathEntry.contains("test-classes")) { + classpath.append(classpathEntry); + classpath.append(File.pathSeparator); + } + } + String systemClassPath = classpath.substring(0, classpath.length() - 1); + + launcher = new Launcher(); + + launcher.run(new String[] { + "-i", "src/main/java", + "-o", "target/spooned", + "--destination","target/spooned-build", + "--source-classpath", systemClassPath, + "--compile", // compiling Spoon code itself on the fly + "--compliance", "8", + "--level", "OFF" + }); + + rootPackage = launcher.getFactory().Package().getRootPackage(); + } + @Test + public void testElementToPathToElementEquivalency() {//} throws CtPathException { + System.out.println("coucou");; + CtModel model = launcher.getModel(); + List l = new ArrayList(); + l.add(rootPackage); + + for(Object o : model.getElements(new TypeFilter(CtElement.class))) { + CtElement element = (CtElement) o; + if(element.getParent(CtModelImpl.CtRootPackage.class) == rootPackage) { + try { + CtPath path = new CtElementPathBuilder().fromElement(element, model.getRootPackage()); + System.out.println("Path: " + path); + Collection returnedElements = path.evaluateOn(l); + assertEquals(returnedElements.size(), 1); + CtElement actualElement = (CtElement) returnedElements.toArray()[0]; + assertEquals(element, actualElement); + } catch (Exception e) { + System.out.println("error"); + } + } + } + } +} From 516338488d7facf2987acc5db59376abeb30e0ef Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Wed, 21 Feb 2018 14:53:45 +0100 Subject: [PATCH 02/26] refactor test unique path --- src/test/java/spoon/test/main/MainTest.java | 35 ++++++-- .../spoon/test/path/UniqueRolePathTest.java | 82 ------------------- 2 files changed, 29 insertions(+), 88 deletions(-) delete mode 100644 src/test/java/spoon/test/path/UniqueRolePathTest.java diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index ff5a096d7de..f9e7bab4480 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -23,6 +23,9 @@ import spoon.reflect.declaration.CtType; import spoon.reflect.declaration.CtTypeParameter; import spoon.reflect.declaration.ParentNotInitializedException; +import spoon.reflect.path.CtElementPathBuilder; +import spoon.reflect.path.CtPath; +import spoon.reflect.path.CtPathException; import spoon.reflect.path.CtRole; import spoon.reflect.reference.CtArrayTypeReference; import spoon.reflect.reference.CtExecutableReference; @@ -40,13 +43,9 @@ import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Set; +import java.util.*; +import static junit.framework.TestCase.fail; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -439,6 +438,30 @@ public void scan(CtRole role, CtElement element) { }); } + @Test + public void testElementToPathToElementEquivalency() { + rootPackage.accept(new CtScanner() { + @Override + public void scan(CtRole role, CtElement element) { + if (element != null) { + CtPath path = null; + try { + path = element.getPath(); + } catch (CtPathException e) { + fail(); + } + List list = new LinkedList(); + list.add(rootPackage); + Collection returnedElements = path.evaluateOn(list); + assertEquals(returnedElements.size(), 1); + CtElement actualElement = (CtElement) returnedElements.toArray()[0]; + assertEquals(element, actualElement); + } + super.scan(role, element); + } + }); + } + @Test public void testTest() throws Exception { // the tests should be spoonable diff --git a/src/test/java/spoon/test/path/UniqueRolePathTest.java b/src/test/java/spoon/test/path/UniqueRolePathTest.java deleted file mode 100644 index 27f46baa98c..00000000000 --- a/src/test/java/spoon/test/path/UniqueRolePathTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package spoon.test.path; - -import org.junit.BeforeClass; -import org.junit.Test; -import spoon.Launcher; -import spoon.MavenLauncher; -import spoon.reflect.CtModel; -import spoon.reflect.CtModelImpl; -import spoon.reflect.declaration.CtElement; -import spoon.reflect.declaration.CtPackage; -import spoon.reflect.path.CtElementPathBuilder; -import spoon.reflect.path.CtPath; -import spoon.reflect.path.CtPathException; -import spoon.reflect.path.CtPathStringBuilder; -import spoon.reflect.visitor.filter.TypeFilter; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static org.junit.Assert.assertEquals; - -public class UniqueRolePathTest { - static Launcher launcher; - static CtPackage rootPackage; - - /** - * load model once into static variable and use it for more read-only tests - */ - @BeforeClass - public static void loadModel() { - // we have to remove the test-classes folder - // so that the precondition of --source-classpath is not violated - // (target/test-classes contains src/test/resources which itself contains Java files) - StringBuilder classpath = new StringBuilder(); - for (String classpathEntry : System.getProperty("java.class.path").split(File.pathSeparator)) { - if (!classpathEntry.contains("test-classes")) { - classpath.append(classpathEntry); - classpath.append(File.pathSeparator); - } - } - String systemClassPath = classpath.substring(0, classpath.length() - 1); - - launcher = new Launcher(); - - launcher.run(new String[] { - "-i", "src/main/java", - "-o", "target/spooned", - "--destination","target/spooned-build", - "--source-classpath", systemClassPath, - "--compile", // compiling Spoon code itself on the fly - "--compliance", "8", - "--level", "OFF" - }); - - rootPackage = launcher.getFactory().Package().getRootPackage(); - } - @Test - public void testElementToPathToElementEquivalency() {//} throws CtPathException { - System.out.println("coucou");; - CtModel model = launcher.getModel(); - List l = new ArrayList(); - l.add(rootPackage); - - for(Object o : model.getElements(new TypeFilter(CtElement.class))) { - CtElement element = (CtElement) o; - if(element.getParent(CtModelImpl.CtRootPackage.class) == rootPackage) { - try { - CtPath path = new CtElementPathBuilder().fromElement(element, model.getRootPackage()); - System.out.println("Path: " + path); - Collection returnedElements = path.evaluateOn(l); - assertEquals(returnedElements.size(), 1); - CtElement actualElement = (CtElement) returnedElements.toArray()[0]; - assertEquals(element, actualElement); - } catch (Exception e) { - System.out.println("error"); - } - } - } - } -} From d3bd277128e38597c58a935e23ff5464bcce3cd7 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Wed, 21 Feb 2018 16:15:28 +0100 Subject: [PATCH 03/26] refactor: remove unecessary exception for CtElement.getPath() --- src/main/java/spoon/reflect/path/impl/CtPathElement.java | 1 + src/main/java/spoon/reflect/path/impl/CtRolePathElement.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/spoon/reflect/path/impl/CtPathElement.java b/src/main/java/spoon/reflect/path/impl/CtPathElement.java index 8bae085dbf2..f33358573b0 100644 --- a/src/main/java/spoon/reflect/path/impl/CtPathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtPathElement.java @@ -17,6 +17,7 @@ package spoon.reflect.path.impl; import spoon.reflect.declaration.CtElement; +import spoon.reflect.path.CtPathException; import java.util.Collection; diff --git a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java index 5885d5a1b3d..f598e5518f4 100644 --- a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java @@ -20,6 +20,7 @@ import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtExecutable; import spoon.reflect.declaration.CtField; +import spoon.reflect.path.CtPathException; import spoon.reflect.path.CtRole; import spoon.reflect.visitor.CtInheritanceScanner; From b1b806f4c422ea8c1663b951d8d4ce808c6c3b29 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Wed, 21 Feb 2018 16:16:01 +0100 Subject: [PATCH 04/26] refactor: remove unecessary exception for CtElement.getPath() --- src/main/java/spoon/reflect/declaration/CtElement.java | 2 +- .../spoon/support/reflect/declaration/CtElementImpl.java | 8 ++++++-- src/test/java/spoon/test/main/MainTest.java | 8 +++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/spoon/reflect/declaration/CtElement.java b/src/main/java/spoon/reflect/declaration/CtElement.java index b79419679ca..56603fa1f41 100644 --- a/src/main/java/spoon/reflect/declaration/CtElement.java +++ b/src/main/java/spoon/reflect/declaration/CtElement.java @@ -355,6 +355,6 @@ List getAnnotatedChildren( /** * Gets a unique path from models root to the CtElement. */ - CtPath getPath() throws CtPathException; + CtPath getPath(); } diff --git a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java index 09f437ef6a6..2594c6993d3 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java @@ -541,7 +541,11 @@ public E setValueByRole(CtRole role, T value) { return (E) this; } - public CtPath getPath() throws CtPathException { - return new CtElementPathBuilder().fromElement(this, getParent(CtModelImpl.CtRootPackage.class)); + public CtPath getPath() { + try { + return new CtElementPathBuilder().fromElement(this, getParent(CtModelImpl.CtRootPackage.class)); + } catch (CtPathException e) { + } + return null; } } diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index f9e7bab4480..23226a5f6e9 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -445,11 +445,9 @@ public void testElementToPathToElementEquivalency() { public void scan(CtRole role, CtElement element) { if (element != null) { CtPath path = null; - try { - path = element.getPath(); - } catch (CtPathException e) { - fail(); - } + + path = element.getPath(); + List list = new LinkedList(); list.add(rootPackage); Collection returnedElements = path.evaluateOn(list); From 64a27589ac3d9cb33f36c4dbb040e386622f6ac4 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Wed, 21 Feb 2018 17:42:44 +0100 Subject: [PATCH 05/26] fix(CtPathStringBuilder): Now supports CtUniqueRolePath --- .../reflect/path/CtPathStringBuilder.java | 5 ++-- src/test/java/spoon/test/main/MainTest.java | 29 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java index e4beefeab46..3f980e33a66 100644 --- a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java +++ b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java @@ -26,7 +26,7 @@ */ public class CtPathStringBuilder { - private final Pattern pathPattern = Pattern.compile("([/.#])([^/.#\\[]+)(\\[([^/.#]*)\\])?"); + private final Pattern pathPattern = Pattern.compile("([/.#@])([^/.#@\\[]+)(\\[([^/.#@]*)\\])?"); private final Pattern argumentPattern = Pattern.compile("(\\w+)=([^=\\]]+)"); @@ -62,6 +62,7 @@ private Class load(String name) throws CtPathException { * . : match with the given name * # : match with a CtPathRole * / : match with a element type (for example, to match all classes, use /CtClass + * @ : match with a CtUniqueRolePath */ public CtPath fromString(String pathStr) throws CtPathException { Matcher matcher = pathPattern.matcher(pathStr); @@ -78,7 +79,7 @@ public CtPath fromString(String pathStr) throws CtPathException { } else if (CtRolePathElement.STRING.equals(kind)) { pathElement = new CtRolePathElement(CtRole.fromName(matcher.group(2))); } else if (CtUniqueRolePathElement.STRING.equals(kind)) { - pathElement = new CtRolePathElement(CtRole.fromName(matcher.group(2))); + pathElement = new CtUniqueRolePathElement(CtRole.fromName(matcher.group(2))); } String args = matcher.group(4); diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index 23226a5f6e9..f3b86a75e63 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -23,10 +23,7 @@ import spoon.reflect.declaration.CtType; import spoon.reflect.declaration.CtTypeParameter; import spoon.reflect.declaration.ParentNotInitializedException; -import spoon.reflect.path.CtElementPathBuilder; -import spoon.reflect.path.CtPath; -import spoon.reflect.path.CtPathException; -import spoon.reflect.path.CtRole; +import spoon.reflect.path.*; import spoon.reflect.reference.CtArrayTypeReference; import spoon.reflect.reference.CtExecutableReference; import spoon.reflect.reference.CtFieldReference; @@ -444,16 +441,20 @@ public void testElementToPathToElementEquivalency() { @Override public void scan(CtRole role, CtElement element) { if (element != null) { - CtPath path = null; - - path = element.getPath(); - - List list = new LinkedList(); - list.add(rootPackage); - Collection returnedElements = path.evaluateOn(list); - assertEquals(returnedElements.size(), 1); - CtElement actualElement = (CtElement) returnedElements.toArray()[0]; - assertEquals(element, actualElement); + CtPath path = element.getPath(); + String pathStr = path.toString(); + try { + CtPath pathRead = new CtPathStringBuilder().fromString(pathStr); + + List list = new LinkedList<>(); + list.add(rootPackage); + Collection returnedElements = pathRead.evaluateOn(list); + assertEquals(returnedElements.size(), 1); + CtElement actualElement = (CtElement) returnedElements.toArray()[0]; + assertEquals(element, actualElement); + } catch (CtPathException e) { + fail(); + } } super.scan(role, element); } From eda3e7cc874aaff0caa9539e7d9853f9686caf7a Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Wed, 21 Feb 2018 17:55:10 +0100 Subject: [PATCH 06/26] doc(MainTest.testElementToPathToElementEquivalency): adds contract info --- .../reflect/path/impl/CtUniqueRolePathElement.java | 12 +----------- src/test/java/spoon/test/main/MainTest.java | 9 ++++++--- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java index 646c9b137be..7ad0039c04b 100644 --- a/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java @@ -37,34 +37,24 @@ public CtElement getFromSet(Set set, String name) throws CtPathException { public Collection getElements(Collection roots) { Collection matchs = new LinkedList<>(); for (CtElement root : roots) { - //if(root.getValueByRole(getRole()) instanceof Collection) { if(root.getValueByRole(getRole()) instanceof List) { if(getArguments().containsKey("index")) { int index = Integer.parseInt(getArguments().get("index")); matchs.add((CtElement) ((List) root.getValueByRole(getRole())).get(index)); - } else { - //Either trhow an exception or add the collection to matches - //matchs.add(el); } } else if(root.getValueByRole(getRole()) instanceof Set) { if(getArguments().containsKey("name")) { String name = getArguments().get("name"); try { - matchs.add(getFromSet((Set) root.getValueByRole(getRole()), name)); + matchs.add(getFromSet(root.getValueByRole(getRole()), name)); } catch (Exception e) { System.err.println("[ERROR] Element not found for name: " + name); } - } else { - //Either trhow an exception or add the collection to matches - //matchs.add(el); } } else if(root.getValueByRole(getRole()) instanceof Map) { if(getArguments().containsKey("key")) { String name = getArguments().get("key"); matchs.add((CtElement) ((Map) root.getValueByRole(getRole())).get(name)); - } else { - //Either trhow an exception or add the collection to matches - //matchs.add(el); } } else { CtElement el = root.getValueByRole(getRole()); diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index f3b86a75e63..087e0eb7eea 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -437,6 +437,10 @@ public void scan(CtRole role, CtElement element) { @Test public void testElementToPathToElementEquivalency() { + + List list = new LinkedList<>(); + list.add(rootPackage); + rootPackage.accept(new CtScanner() { @Override public void scan(CtRole role, CtElement element) { @@ -445,12 +449,11 @@ public void scan(CtRole role, CtElement element) { String pathStr = path.toString(); try { CtPath pathRead = new CtPathStringBuilder().fromString(pathStr); - - List list = new LinkedList<>(); - list.add(rootPackage); Collection returnedElements = pathRead.evaluateOn(list); + //contract: CtUniqueRolePathElement.evaluateOn() returns a unique elements if provided only a list of one inputs assertEquals(returnedElements.size(), 1); CtElement actualElement = (CtElement) returnedElements.toArray()[0]; + //contract: Element -> Path -> String -> Path -> Element leads to the original element assertEquals(element, actualElement); } catch (CtPathException e) { fail(); From afc30dd857e5f0e42a8b1b5c5fce389ac0b9189e Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Thu, 22 Feb 2018 11:48:10 +0100 Subject: [PATCH 07/26] refactor(MainTest): cosmetic --- src/test/java/spoon/test/main/MainTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index 087e0eb7eea..685c3dbf47d 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -454,7 +454,7 @@ public void scan(CtRole role, CtElement element) { assertEquals(returnedElements.size(), 1); CtElement actualElement = (CtElement) returnedElements.toArray()[0]; //contract: Element -> Path -> String -> Path -> Element leads to the original element - assertEquals(element, actualElement); + assertSame(element, actualElement); } catch (CtPathException e) { fail(); } From 3c69d39d578558f435574eb9a07ac7d9061352bf Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Fri, 23 Feb 2018 16:37:04 +0100 Subject: [PATCH 08/26] doc(CtElementPathBuilder): add missing javadoc --- .../spoon/reflect/path/CtElementPathBuilder.java | 14 ++++++++++++++ .../reflect/path/impl/CtUniqueRolePathElement.java | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java index 85c80634289..c84323385e6 100644 --- a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java +++ b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java @@ -12,7 +12,21 @@ import java.util.Map; import java.util.Set; +/** + * This builder allow to create some CtPath from CtElements + * + * Created by nharrand on 21/02/2018. + */ public class CtElementPathBuilder { + /** + * Build path to a CtElement el, from one of its parent. + * + * @throws CtPathException is thrown when root is not a parent of el. + * + * @param el : the element to which the CtPath leads to + * @param root : Starting point of the CtPath + * @return CtPath from root to el + */ public CtPath fromElement(CtElement el, CtElement root) throws CtPathException { CtPathImpl path = new CtPathImpl(); CtElement cur = el; diff --git a/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java index 7ad0039c04b..57eec533cc4 100644 --- a/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java @@ -8,6 +8,11 @@ import java.util.*; +/** + * A CtPathElement that define all roles for matching a unique CtElement from a given root. + * + * Created by nharrand on 21/02/2018. + */ public class CtUniqueRolePathElement extends CtRolePathElement { public static final String STRING = "@"; From be56d3474f732977dceabf1047530a1eeab295dd Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Fri, 23 Feb 2018 17:14:03 +0100 Subject: [PATCH 09/26] refactor: fix coding style --- .../spoon/reflect/declaration/CtElement.java | 1 - .../reflect/path/CtElementPathBuilder.java | 133 ++++++++++-------- .../reflect/path/CtPathStringBuilder.java | 8 +- .../reflect/path/impl/CtPathElement.java | 1 - .../reflect/path/impl/CtRolePathElement.java | 1 - .../path/impl/CtUniqueRolePathElement.java | 111 ++++++++------- 6 files changed, 140 insertions(+), 115 deletions(-) diff --git a/src/main/java/spoon/reflect/declaration/CtElement.java b/src/main/java/spoon/reflect/declaration/CtElement.java index 56603fa1f41..4b81c074576 100644 --- a/src/main/java/spoon/reflect/declaration/CtElement.java +++ b/src/main/java/spoon/reflect/declaration/CtElement.java @@ -20,7 +20,6 @@ import spoon.reflect.code.CtComment; import spoon.reflect.cu.SourcePosition; import spoon.reflect.path.CtPath; -import spoon.reflect.path.CtPathException; import spoon.reflect.path.CtRole; import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.CtVisitable; diff --git a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java index c84323385e6..11f9ab94d91 100644 --- a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java +++ b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java @@ -7,7 +7,6 @@ import spoon.reflect.path.impl.CtUniqueRolePathElement; import spoon.reflect.reference.CtReference; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -18,64 +17,78 @@ * Created by nharrand on 21/02/2018. */ public class CtElementPathBuilder { - /** - * Build path to a CtElement el, from one of its parent. - * - * @throws CtPathException is thrown when root is not a parent of el. - * - * @param el : the element to which the CtPath leads to - * @param root : Starting point of the CtPath - * @return CtPath from root to el - */ - public CtPath fromElement(CtElement el, CtElement root) throws CtPathException { - CtPathImpl path = new CtPathImpl(); - CtElement cur = el; - while(cur != root) { - CtElement parent = cur.getParent(); - CtRole role = cur.getRoleInParent(); - if(parent == null || role == null) throw new CtPathException(); - CtPathElement pathElement = new CtUniqueRolePathElement(role); - if(parent.getValueByRole(role) instanceof List) { - //Element needs to be differentiated from its brothers - List list = parent.getValueByRole(role); - //Assumes that List's order is deterministic. - int index = 0; - for(Object o : list) { - if(o == cur) break; - index++; - } - pathElement.addArgument("index", index + ""); - } else if (parent.getValueByRole(role) instanceof Set){ - if(!(cur instanceof CtNamedElement) && !(cur instanceof CtReference)) throw new CtPathException(); - //Element needs to be differentiated from its brothers - Set set = parent.getValueByRole(role); - String name = null; - for(Object o : set) { - if(o == cur) { - if(cur instanceof CtNamedElement) - name = ((CtNamedElement) cur).getSimpleName(); - else name = ((CtReference) cur).getSimpleName(); - break; - } - } - if(name == null) throw new CtPathException(); - else pathElement.addArgument("name", name); + /** + * Build path to a CtElement el, from one of its parent. + * + * @throws CtPathException is thrown when root is not a parent of el. + * + * @param el : the element to which the CtPath leads to + * @param root : Starting point of the CtPath + * @return CtPath from root to el + */ + public CtPath fromElement(CtElement el, CtElement root) throws CtPathException { + CtPathImpl path = new CtPathImpl(); + CtElement cur = el; + while (cur != root) { + CtElement parent = cur.getParent(); + CtRole role = cur.getRoleInParent(); + if (parent == null || role == null) { + throw new CtPathException(); + } + CtPathElement pathElement = new CtUniqueRolePathElement(role); + if (parent.getValueByRole(role) instanceof List) { + //Element needs to be differentiated from its brothers + List list = parent.getValueByRole(role); + //Assumes that List's order is deterministic. + int index = 0; + for (Object o : list) { + if (o == cur) { + break; + } + index++; + } + pathElement.addArgument("index", index + ""); + } else if (parent.getValueByRole(role) instanceof Set) { + if (!(cur instanceof CtNamedElement) && !(cur instanceof CtReference)) { + throw new CtPathException(); + } + //Element needs to be differentiated from its brothers + Set set = parent.getValueByRole(role); + String name = null; + for (Object o : set) { + if (o == cur) { + if (cur instanceof CtNamedElement) { + name = ((CtNamedElement) cur).getSimpleName(); + } else { + name = ((CtReference) cur).getSimpleName(); + } + break; + } + } + if (name == null) { + throw new CtPathException(); + } else { + pathElement.addArgument("name", name); + } - } else if (parent.getValueByRole(role) instanceof Map){ - Map map = parent.getValueByRole(role); - String key = null; - for(Object o : map.keySet()) { - if(map.get(o) == cur) { - key = (String) o; - break; - } - } - if(key == null) throw new CtPathException(); - else pathElement.addArgument("key", key); - } - cur = parent; - path.addFirst(pathElement); - } - return path; - } + } else if (parent.getValueByRole(role) instanceof Map) { + Map map = parent.getValueByRole(role); + String key = null; + for (Object o : map.keySet()) { + if (map.get(o) == cur) { + key = (String) o; + break; + } + } + if (key == null) { + throw new CtPathException(); + } else { + pathElement.addArgument("key", key); + } + } + cur = parent; + path.addFirst(pathElement); + } + return path; + } } diff --git a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java index 3f980e33a66..e4dfdfd70ed 100644 --- a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java +++ b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java @@ -16,7 +16,13 @@ */ package spoon.reflect.path; -import spoon.reflect.path.impl.*; + +import spoon.reflect.path.impl.CtNamedPathElement; +import spoon.reflect.path.impl.CtPathElement; +import spoon.reflect.path.impl.CtPathImpl; +import spoon.reflect.path.impl.CtTypedNameElement; +import spoon.reflect.path.impl.CtUniqueRolePathElement; +import spoon.reflect.path.impl.CtRolePathElement; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/spoon/reflect/path/impl/CtPathElement.java b/src/main/java/spoon/reflect/path/impl/CtPathElement.java index f33358573b0..8bae085dbf2 100644 --- a/src/main/java/spoon/reflect/path/impl/CtPathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtPathElement.java @@ -17,7 +17,6 @@ package spoon.reflect.path.impl; import spoon.reflect.declaration.CtElement; -import spoon.reflect.path.CtPathException; import java.util.Collection; diff --git a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java index f598e5518f4..5885d5a1b3d 100644 --- a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java @@ -20,7 +20,6 @@ import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtExecutable; import spoon.reflect.declaration.CtField; -import spoon.reflect.path.CtPathException; import spoon.reflect.path.CtRole; import spoon.reflect.visitor.CtInheritanceScanner; diff --git a/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java index 57eec533cc4..ca31d27d3e2 100644 --- a/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java @@ -6,7 +6,12 @@ import spoon.reflect.path.CtRole; import spoon.reflect.reference.CtReference; -import java.util.*; +import java.util.List; +import java.util.LinkedList; +import java.util.Set; +import java.util.Map; +import java.util.Collection; + /** * A CtPathElement that define all roles for matching a unique CtElement from a given root. @@ -14,58 +19,62 @@ * Created by nharrand on 21/02/2018. */ public class CtUniqueRolePathElement extends CtRolePathElement { - public static final String STRING = "@"; + public static final String STRING = "@"; - public CtUniqueRolePathElement(CtRole role) { - super(role); - } + public CtUniqueRolePathElement(CtRole role) { + super(role); + } - @Override - public String toString() { - return STRING + getRole().toString() + getParamString(); - } + @Override + public String toString() { + return STRING + getRole().toString() + getParamString(); + } - public CtElement getFromSet(Set set, String name) throws CtPathException { - for(Object o: set) { - if(o instanceof CtNamedElement) { - if (((CtNamedElement) o).getSimpleName().equals(name)) return (CtElement) o; - } else if(o instanceof CtReference) { - if (((CtReference) o).getSimpleName().equals(name)) return (CtElement) o; - } else { - throw new CtPathException(); - } - } - throw new CtPathException(); - } + public CtElement getFromSet(Set set, String name) throws CtPathException { + for (Object o: set) { + if (o instanceof CtNamedElement) { + if (((CtNamedElement) o).getSimpleName().equals(name)) { + return (CtElement) o; + } + } else if (o instanceof CtReference) { + if (((CtReference) o).getSimpleName().equals(name)) { + return (CtElement) o; + } + } else { + throw new CtPathException(); + } + } + throw new CtPathException(); + } - @Override - public Collection getElements(Collection roots) { - Collection matchs = new LinkedList<>(); - for (CtElement root : roots) { - if(root.getValueByRole(getRole()) instanceof List) { - if(getArguments().containsKey("index")) { - int index = Integer.parseInt(getArguments().get("index")); - matchs.add((CtElement) ((List) root.getValueByRole(getRole())).get(index)); - } - } else if(root.getValueByRole(getRole()) instanceof Set) { - if(getArguments().containsKey("name")) { - String name = getArguments().get("name"); - try { - matchs.add(getFromSet(root.getValueByRole(getRole()), name)); - } catch (Exception e) { - System.err.println("[ERROR] Element not found for name: " + name); - } - } - } else if(root.getValueByRole(getRole()) instanceof Map) { - if(getArguments().containsKey("key")) { - String name = getArguments().get("key"); - matchs.add((CtElement) ((Map) root.getValueByRole(getRole())).get(name)); - } - } else { - CtElement el = root.getValueByRole(getRole()); - matchs.add(el); - } - } - return matchs; - } + @Override + public Collection getElements(Collection roots) { + Collection matchs = new LinkedList<>(); + for (CtElement root : roots) { + if (root.getValueByRole(getRole()) instanceof List) { + if (getArguments().containsKey("index")) { + int index = Integer.parseInt(getArguments().get("index")); + matchs.add((CtElement) ((List) root.getValueByRole(getRole())).get(index)); + } + } else if (root.getValueByRole(getRole()) instanceof Set) { + if (getArguments().containsKey("name")) { + String name = getArguments().get("name"); + try { + matchs.add(getFromSet(root.getValueByRole(getRole()), name)); + } catch (Exception e) { + System.err.println("[ERROR] Element not found for name: " + name); + } + } + } else if (root.getValueByRole(getRole()) instanceof Map) { + if (getArguments().containsKey("key")) { + String name = getArguments().get("key"); + matchs.add((CtElement) ((Map) root.getValueByRole(getRole())).get(name)); + } + } else { + CtElement el = root.getValueByRole(getRole()); + matchs.add(el); + } + } + return matchs; + } } From 1e604a765102cf230a7dc5ca14a245e1b0112e10 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Fri, 23 Feb 2018 17:42:01 +0100 Subject: [PATCH 10/26] fix: MainTest merging error --- src/test/java/spoon/test/main/MainTest.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index 2182dca5668..09ef4e9228c 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -41,7 +41,15 @@ import java.io.PrintWriter; import java.io.StringWriter; -import java.util.*; +import java.util.List; +import java.util.LinkedList; +import java.util.Set; +import java.util.HashSet; +import java.util.Deque; +import java.util.ArrayDeque; +import java.util.Map; +import java.util.IdentityHashMap; +import java.util.Collection; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -463,7 +471,7 @@ public void scan(CtRole role, CtElement element) { }); } - + @Test public void testElementIsContainedInAttributeOfItsParent() { rootPackage.accept(new CtScanner() { @Override From 14e0c2c38b44288ce0d14070b6e89dd585c040cd Mon Sep 17 00:00:00 2001 From: Martin Monperrus Date: Fri, 23 Feb 2018 19:00:28 +0100 Subject: [PATCH 11/26] Update CtPathStringBuilder.java --- src/main/java/spoon/reflect/path/CtPathStringBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java index e4dfdfd70ed..cbeccb99efd 100644 --- a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java +++ b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java @@ -68,7 +68,7 @@ private Class load(String name) throws CtPathException { * . : match with the given name * # : match with a CtPathRole * / : match with a element type (for example, to match all classes, use /CtClass - * @ : match with a CtUniqueRolePath + * "at" sign : match with a CtUniqueRolePath */ public CtPath fromString(String pathStr) throws CtPathException { Matcher matcher = pathPattern.matcher(pathStr); From aa826b8dba2e5a3444b2e472c398c6b9961981a2 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Sat, 24 Feb 2018 18:15:46 +0100 Subject: [PATCH 12/26] refactor(CtRolePathElement): Replace old behavior by new one from CtUniqueRolePathElement --- doc/path.md | 2 +- .../reflect/path/CtElementPathBuilder.java | 4 +- .../reflect/path/CtPathStringBuilder.java | 5 +- .../reflect/path/impl/CtRolePathElement.java | 115 +++++++++--------- .../path/impl/CtUniqueRolePathElement.java | 80 ------------ src/test/java/spoon/test/main/MainTest.java | 13 +- src/test/java/spoon/test/path/PathTest.java | 12 +- 7 files changed, 76 insertions(+), 155 deletions(-) delete mode 100644 src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java diff --git a/doc/path.md b/doc/path.md index 93efbf2fc20..621c257bc0d 100644 --- a/doc/path.md +++ b/doc/path.md @@ -30,7 +30,7 @@ For instance, if we want the first statement in the body of method `foo`, declar in the class `spoon.test.path.Foo`. ```java -new CtPathStringBuilder().fromString(".spoon.test.path.Foo.foo#body[index=0]"); +new CtPathStringBuilder().fromString(".spoon.test.path.Foo.foo#body#statement[index=0]"); ``` ## CtPathBuilder diff --git a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java index 11f9ab94d91..50fa3bbd38b 100644 --- a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java +++ b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java @@ -4,7 +4,7 @@ import spoon.reflect.declaration.CtNamedElement; import spoon.reflect.path.impl.CtPathElement; import spoon.reflect.path.impl.CtPathImpl; -import spoon.reflect.path.impl.CtUniqueRolePathElement; +import spoon.reflect.path.impl.CtRolePathElement; import spoon.reflect.reference.CtReference; import java.util.List; @@ -35,7 +35,7 @@ public CtPath fromElement(CtElement el, CtElement root) throws CtPathException { if (parent == null || role == null) { throw new CtPathException(); } - CtPathElement pathElement = new CtUniqueRolePathElement(role); + CtPathElement pathElement = new CtRolePathElement(role); if (parent.getValueByRole(role) instanceof List) { //Element needs to be differentiated from its brothers List list = parent.getValueByRole(role); diff --git a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java index cbeccb99efd..072697623b9 100644 --- a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java +++ b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java @@ -21,7 +21,6 @@ import spoon.reflect.path.impl.CtPathElement; import spoon.reflect.path.impl.CtPathImpl; import spoon.reflect.path.impl.CtTypedNameElement; -import spoon.reflect.path.impl.CtUniqueRolePathElement; import spoon.reflect.path.impl.CtRolePathElement; import java.util.regex.Matcher; @@ -32,7 +31,7 @@ */ public class CtPathStringBuilder { - private final Pattern pathPattern = Pattern.compile("([/.#@])([^/.#@\\[]+)(\\[([^/.#@]*)\\])?"); + private final Pattern pathPattern = Pattern.compile("([/.#])([^/.#\\[]+)(\\[([^/.#]*)\\])?"); private final Pattern argumentPattern = Pattern.compile("(\\w+)=([^=\\]]+)"); @@ -84,8 +83,6 @@ public CtPath fromString(String pathStr) throws CtPathException { pathElement = new CtTypedNameElement(load(matcher.group(2))); } else if (CtRolePathElement.STRING.equals(kind)) { pathElement = new CtRolePathElement(CtRole.fromName(matcher.group(2))); - } else if (CtUniqueRolePathElement.STRING.equals(kind)) { - pathElement = new CtUniqueRolePathElement(CtRole.fromName(matcher.group(2))); } String args = matcher.group(4); diff --git a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java index 5885d5a1b3d..bd41b831886 100644 --- a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java @@ -16,15 +16,22 @@ */ package spoon.reflect.path.impl; +import spoon.SpoonException; import spoon.reflect.code.CtIf; import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtExecutable; import spoon.reflect.declaration.CtField; +import spoon.reflect.declaration.CtNamedElement; +import spoon.reflect.path.CtPathException; import spoon.reflect.path.CtRole; +import spoon.reflect.reference.CtReference; import spoon.reflect.visitor.CtInheritanceScanner; import java.util.Collection; import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * A CtPathElement that define some roles for matching. @@ -40,60 +47,6 @@ public class CtRolePathElement extends AbstractPathElement public static final String STRING = "#"; - private class RoleVisitor extends CtInheritanceScanner { - private Collection matchs = new LinkedList<>(); - - private RoleVisitor() { - } - - @Override - public void scanCtExecutable(CtExecutable e) { - super.scanCtExecutable(e); - - switch (role) { - case BODY: - if (e.getBody() != null) { - if (getArguments().containsKey("index") - && e.getBody() - .getStatements() - .size() > Integer.parseInt( - getArguments().get("index"))) { - matchs.add(e.getBody().getStatements().get(Integer - .parseInt(getArguments().get("index")))); - } else { - matchs.addAll(e.getBody().getStatements()); - } - } - } - - } - - @Override - public void visitCtField(CtField e) { - super.visitCtField(e); - - if (role == CtRole.DEFAULT_EXPRESSION && e.getDefaultExpression() != null) { - matchs.add(e.getDefaultExpression()); - } - } - - @Override - public void visitCtIf(CtIf e) { - super.visitCtIf(e); - - switch (role) { - case THEN: - if (e.getThenStatement() != null) { - matchs.add(e.getThenStatement()); - } - case ELSE: - if (e.getElseStatement() != null) { - matchs.add(e.getElseStatement()); - } - } - } - } - private final CtRole role; public CtRolePathElement(CtRole role) { @@ -106,14 +59,58 @@ public CtRole getRole() { @Override public String toString() { - return STRING + role.toString() + getParamString(); + return STRING + getRole().toString() + getParamString(); + } + + public CtElement getFromSet(Set set, String name) throws CtPathException { + for (Object o: set) { + if (o instanceof CtNamedElement) { + if (((CtNamedElement) o).getSimpleName().equals(name)) { + return (CtElement) o; + } + } else if (o instanceof CtReference) { + if (((CtReference) o).getSimpleName().equals(name)) { + return (CtElement) o; + } + } else { + throw new CtPathException(); + } + } + throw new CtPathException(); } @Override public Collection getElements(Collection roots) { - RoleVisitor visitor = new RoleVisitor(); - visitor.scan(roots); - return visitor.matchs; + Collection matchs = new LinkedList<>(); + for (CtElement root : roots) { + CtRole role = null; + try { + if (root.getValueByRole(getRole()) instanceof List) { + if (getArguments().containsKey("index")) { + int index = Integer.parseInt(getArguments().get("index")); + matchs.add((CtElement) ((List) root.getValueByRole(getRole())).get(index)); + } + } else if (root.getValueByRole(getRole()) instanceof Set) { + if (getArguments().containsKey("name")) { + String name = getArguments().get("name"); + try { + matchs.add(getFromSet(root.getValueByRole(getRole()), name)); + } catch (CtPathException e) { + //System.err.println("[ERROR] Element not found for name: " + name); + //No element found for name. + } + } + } else if (root.getValueByRole(getRole()) instanceof Map) { + if (getArguments().containsKey("key")) { + String name = getArguments().get("key"); + matchs.add((CtElement) ((Map) root.getValueByRole(getRole())).get(name)); + } + } else { + CtElement el = root.getValueByRole(getRole()); + matchs.add(el); + } + } catch (SpoonException e) {} + } + return matchs; } - } diff --git a/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java deleted file mode 100644 index ca31d27d3e2..00000000000 --- a/src/main/java/spoon/reflect/path/impl/CtUniqueRolePathElement.java +++ /dev/null @@ -1,80 +0,0 @@ -package spoon.reflect.path.impl; - -import spoon.reflect.declaration.CtElement; -import spoon.reflect.declaration.CtNamedElement; -import spoon.reflect.path.CtPathException; -import spoon.reflect.path.CtRole; -import spoon.reflect.reference.CtReference; - -import java.util.List; -import java.util.LinkedList; -import java.util.Set; -import java.util.Map; -import java.util.Collection; - - -/** - * A CtPathElement that define all roles for matching a unique CtElement from a given root. - * - * Created by nharrand on 21/02/2018. - */ -public class CtUniqueRolePathElement extends CtRolePathElement { - public static final String STRING = "@"; - - public CtUniqueRolePathElement(CtRole role) { - super(role); - } - - @Override - public String toString() { - return STRING + getRole().toString() + getParamString(); - } - - public CtElement getFromSet(Set set, String name) throws CtPathException { - for (Object o: set) { - if (o instanceof CtNamedElement) { - if (((CtNamedElement) o).getSimpleName().equals(name)) { - return (CtElement) o; - } - } else if (o instanceof CtReference) { - if (((CtReference) o).getSimpleName().equals(name)) { - return (CtElement) o; - } - } else { - throw new CtPathException(); - } - } - throw new CtPathException(); - } - - @Override - public Collection getElements(Collection roots) { - Collection matchs = new LinkedList<>(); - for (CtElement root : roots) { - if (root.getValueByRole(getRole()) instanceof List) { - if (getArguments().containsKey("index")) { - int index = Integer.parseInt(getArguments().get("index")); - matchs.add((CtElement) ((List) root.getValueByRole(getRole())).get(index)); - } - } else if (root.getValueByRole(getRole()) instanceof Set) { - if (getArguments().containsKey("name")) { - String name = getArguments().get("name"); - try { - matchs.add(getFromSet(root.getValueByRole(getRole()), name)); - } catch (Exception e) { - System.err.println("[ERROR] Element not found for name: " + name); - } - } - } else if (root.getValueByRole(getRole()) instanceof Map) { - if (getArguments().containsKey("key")) { - String name = getArguments().get("key"); - matchs.add((CtElement) ((Map) root.getValueByRole(getRole())).get(name)); - } - } else { - CtElement el = root.getValueByRole(getRole()); - matchs.add(el); - } - } - return matchs; - } -} diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index 09ef4e9228c..e56a718baa9 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -23,7 +23,10 @@ import spoon.reflect.declaration.CtType; import spoon.reflect.declaration.CtTypeParameter; import spoon.reflect.declaration.ParentNotInitializedException; -import spoon.reflect.path.*; +import spoon.reflect.path.CtPath; +import spoon.reflect.path.CtPathException; +import spoon.reflect.path.CtPathStringBuilder; +import spoon.reflect.path.CtRole; import spoon.reflect.reference.CtArrayTypeReference; import spoon.reflect.reference.CtExecutableReference; import spoon.reflect.reference.CtFieldReference; @@ -41,6 +44,7 @@ import java.io.PrintWriter; import java.io.StringWriter; +import java.util.Arrays; import java.util.List; import java.util.LinkedList; import java.util.Set; @@ -447,11 +451,10 @@ public void scan(CtRole role, CtElement element) { @Test public void testElementToPathToElementEquivalency() { - List list = new LinkedList<>(); - list.add(rootPackage); + List list = Arrays.asList(rootPackage); rootPackage.accept(new CtScanner() { @Override - public void scan(CtRole role, CtElement element) { + public void scan(CtElement element) { if (element != null) { CtPath path = element.getPath(); String pathStr = path.toString(); @@ -464,7 +467,7 @@ public void scan(CtRole role, CtElement element) { //contract: Element -> Path -> String -> Path -> Element leads to the original element assertSame(element, actualElement); } catch (CtPathException e) { - fail("Path is either incorreclty generated or incorrectly read"); + fail("Path is either incorrectly generated or incorrectly read"); } } } diff --git a/src/test/java/spoon/test/path/PathTest.java b/src/test/java/spoon/test/path/PathTest.java index 3d6561d8f24..edfdbb91bf2 100644 --- a/src/test/java/spoon/test/path/PathTest.java +++ b/src/test/java/spoon/test/path/PathTest.java @@ -18,6 +18,8 @@ import java.util.Arrays; import java.util.Collection; +import java.util.LinkedList; +import java.util.List; import java.util.Set; import static org.junit.Assert.assertArrayEquals; @@ -83,7 +85,7 @@ public void testBuilder() { public void testPathFromString() throws Exception { // match the first statement of Foo.foo() method equals( - new CtPathStringBuilder().fromString(".spoon.test.path.Foo.foo#body[index=0]"), + new CtPathStringBuilder().fromString(".spoon.test.path.Foo.foo#body#statement[index=0]"), factory.Package().get("spoon.test.path").getType("Foo").getMethod("foo").getBody() .getStatement(0)); @@ -103,7 +105,9 @@ public void testPathFromString() throws Exception { @Test public void testWildcards() throws Exception { // get the first statements of all Foo methods - equals(new CtPathStringBuilder().fromString(".spoon.test.path.Foo.*#body[index=0]"), + List list = new LinkedList<>(); + list.add(factory.getModel().getRootPackage()); + equals(new CtPathStringBuilder().fromString(".spoon.test.path.Foo.*#body#statement[index=0]"), ((CtClass) factory.Package().get("spoon.test.path").getType("Foo")).getConstructor().getBody() .getStatement(0), factory.Package().get("spoon.test.path").getType("Foo").getMethod("foo").getBody() @@ -130,10 +134,10 @@ public void testRoles() throws Exception { @Test public void toStringTest() throws Exception { comparePath(".spoon.test.path.Foo/CtMethod"); - comparePath(".spoon.test.path.Foo.foo#body[index=0]"); + comparePath(".spoon.test.path.Foo.foo#body#statement[index=0]"); comparePath(".spoon.test.path.Foo.bar/CtParameter"); comparePath(".spoon.test.path.Foo.toto#defaultExpression"); - comparePath(".spoon.test.path.Foo.*#body[index=0]"); + comparePath(".spoon.test.path.Foo.*#body#statement[index=0]"); comparePath(".**/CtIf#else"); comparePath(".**#else"); } From 786521764b2583830eb092d951ff5b9e4add406b Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Sat, 24 Feb 2018 18:20:04 +0100 Subject: [PATCH 13/26] refactor(CtRolePathElement): fix coding style --- .../java/spoon/reflect/path/impl/CtRolePathElement.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java index bd41b831886..7d86be4b1d2 100644 --- a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java @@ -17,15 +17,11 @@ package spoon.reflect.path.impl; import spoon.SpoonException; -import spoon.reflect.code.CtIf; import spoon.reflect.declaration.CtElement; -import spoon.reflect.declaration.CtExecutable; -import spoon.reflect.declaration.CtField; import spoon.reflect.declaration.CtNamedElement; import spoon.reflect.path.CtPathException; import spoon.reflect.path.CtRole; import spoon.reflect.reference.CtReference; -import spoon.reflect.visitor.CtInheritanceScanner; import java.util.Collection; import java.util.LinkedList; @@ -83,7 +79,6 @@ public CtElement getFromSet(Set set, String name) throws CtPathException { public Collection getElements(Collection roots) { Collection matchs = new LinkedList<>(); for (CtElement root : roots) { - CtRole role = null; try { if (root.getValueByRole(getRole()) instanceof List) { if (getArguments().containsKey("index")) { @@ -109,7 +104,7 @@ public Collection getElements(Collection roots) { CtElement el = root.getValueByRole(getRole()); matchs.add(el); } - } catch (SpoonException e) {} + } catch (SpoonException e) { } //When no element are found for a given role, return empty list. } return matchs; } From 45d6820e5ff3d329ab507382791bdec0f1137c00 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Sat, 24 Feb 2018 18:34:24 +0100 Subject: [PATCH 14/26] doc(CtPathStringBuilder): fix javadoc --- src/main/java/spoon/reflect/path/CtPathStringBuilder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java index 072697623b9..9578258803f 100644 --- a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java +++ b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java @@ -67,7 +67,6 @@ private Class load(String name) throws CtPathException { * . : match with the given name * # : match with a CtPathRole * / : match with a element type (for example, to match all classes, use /CtClass - * "at" sign : match with a CtUniqueRolePath */ public CtPath fromString(String pathStr) throws CtPathException { Matcher matcher = pathPattern.matcher(pathStr); From 8bc9df38f63e2487158f7977c8b3e3baf1361a13 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Sun, 25 Feb 2018 10:24:39 +0100 Subject: [PATCH 15/26] fix(CtElementImpl.getPath()): unsilence exception. --- .../java/spoon/support/reflect/declaration/CtElementImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java index 2594c6993d3..653d6b2d8bc 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java @@ -17,6 +17,7 @@ package spoon.support.reflect.declaration; import org.apache.log4j.Logger; +import spoon.SpoonException; import spoon.reflect.CtModelImpl; import spoon.reflect.annotations.MetamodelPropertyField; import spoon.reflect.code.CtComment; @@ -545,7 +546,7 @@ public CtPath getPath() { try { return new CtElementPathBuilder().fromElement(this, getParent(CtModelImpl.CtRootPackage.class)); } catch (CtPathException e) { + throw new SpoonException(); } - return null; } } From a7290f4d18e5e9edfa85fd4a476a36101c45d24d Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Sun, 25 Feb 2018 17:50:22 +0100 Subject: [PATCH 16/26] refactor(CtRolePathElement,CtElementPathBuilder): uses RoleHandlerHelper --- .../reflect/path/CtElementPathBuilder.java | 86 +++++++++---------- .../reflect/path/impl/CtRolePathElement.java | 43 ++++++++-- 2 files changed, 77 insertions(+), 52 deletions(-) diff --git a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java index 50fa3bbd38b..4f407c51acf 100644 --- a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java +++ b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java @@ -2,6 +2,8 @@ import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtNamedElement; +import spoon.reflect.meta.RoleHandler; +import spoon.reflect.meta.impl.RoleHandlerHelper; import spoon.reflect.path.impl.CtPathElement; import spoon.reflect.path.impl.CtPathImpl; import spoon.reflect.path.impl.CtRolePathElement; @@ -9,7 +11,6 @@ import java.util.List; import java.util.Map; -import java.util.Set; /** * This builder allow to create some CtPath from CtElements @@ -32,59 +33,50 @@ public CtPath fromElement(CtElement el, CtElement root) throws CtPathException { while (cur != root) { CtElement parent = cur.getParent(); CtRole role = cur.getRoleInParent(); - if (parent == null || role == null) { + RoleHandler roleHandler = RoleHandlerHelper.getOptionalRoleHandler(parent.getClass(), role); + if (role == null || roleHandler == null) { throw new CtPathException(); } CtPathElement pathElement = new CtRolePathElement(role); - if (parent.getValueByRole(role) instanceof List) { - //Element needs to be differentiated from its brothers - List list = parent.getValueByRole(role); - //Assumes that List's order is deterministic. - int index = 0; - for (Object o : list) { - if (o == cur) { - break; - } - index++; - } - pathElement.addArgument("index", index + ""); - } else if (parent.getValueByRole(role) instanceof Set) { - if (!(cur instanceof CtNamedElement) && !(cur instanceof CtReference)) { - throw new CtPathException(); - } - //Element needs to be differentiated from its brothers - Set set = parent.getValueByRole(role); - String name = null; - for (Object o : set) { - if (o == cur) { - if (cur instanceof CtNamedElement) { - name = ((CtNamedElement) cur).getSimpleName(); - } else { - name = ((CtReference) cur).getSimpleName(); - } - break; + switch (roleHandler.getContainerKind()) { + case SINGLE: + break; + + case LIST: + //Element needs to be differentiated from its brothers + List list = roleHandler.asList(parent); + //Assumes that List's order is deterministic. + int index = list.indexOf(cur); + pathElement.addArgument("index", index + ""); + break; + + case SET: + String name; + if (cur instanceof CtNamedElement) { + name = ((CtNamedElement) cur).getSimpleName(); + } else if (cur instanceof CtReference) { + name = ((CtReference) cur).getSimpleName(); + } else { + throw new CtPathException(); } - } - if (name == null) { - throw new CtPathException(); - } else { pathElement.addArgument("name", name); - } + break; - } else if (parent.getValueByRole(role) instanceof Map) { - Map map = parent.getValueByRole(role); - String key = null; - for (Object o : map.keySet()) { - if (map.get(o) == cur) { - key = (String) o; - break; + case MAP: + Map map = roleHandler.asMap(parent); + String key = null; + for (Object o : map.keySet()) { + if (map.get(o) == cur) { + key = (String) o; + break; + } + } + if (key == null) { + throw new CtPathException(); + } else { + pathElement.addArgument("key", key); } - } - if (key == null) { - throw new CtPathException(); - } else { - pathElement.addArgument("key", key); - } + break; } cur = parent; path.addFirst(pathElement); diff --git a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java index 7d86be4b1d2..5de5cb95563 100644 --- a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java @@ -16,17 +16,16 @@ */ package spoon.reflect.path.impl; -import spoon.SpoonException; import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtNamedElement; +import spoon.reflect.meta.RoleHandler; +import spoon.reflect.meta.impl.RoleHandlerHelper; import spoon.reflect.path.CtPathException; import spoon.reflect.path.CtRole; import spoon.reflect.reference.CtReference; import java.util.Collection; import java.util.LinkedList; -import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -79,7 +78,41 @@ public CtElement getFromSet(Set set, String name) throws CtPathException { public Collection getElements(Collection roots) { Collection matchs = new LinkedList<>(); for (CtElement root : roots) { - try { + RoleHandler roleHandler = RoleHandlerHelper.getOptionalRoleHandler(root.getClass(), getRole()); + if (roleHandler != null) { + switch (roleHandler.getContainerKind()) { + case SINGLE: + matchs.add(roleHandler.getValue(root)); + break; + + case LIST: + if (getArguments().containsKey("index")) { + int index = Integer.parseInt(getArguments().get("index")); + matchs.add((CtElement) roleHandler.asList(root).get(index)); + } + break; + + case SET: + if (getArguments().containsKey("name")) { + String name = getArguments().get("name"); + try { + matchs.add(getFromSet(roleHandler.asSet(root), name)); + } catch (CtPathException e) { + //System.err.println("[ERROR] Element not found for name: " + name); + //No element found for name. + } + } + break; + + case MAP: + if (getArguments().containsKey("key")) { + String name = getArguments().get("key"); + matchs.add((CtElement) roleHandler.asMap(root).get(name)); + } + break; + } + } + /*try { if (root.getValueByRole(getRole()) instanceof List) { if (getArguments().containsKey("index")) { int index = Integer.parseInt(getArguments().get("index")); @@ -104,7 +137,7 @@ public Collection getElements(Collection roots) { CtElement el = root.getValueByRole(getRole()); matchs.add(el); } - } catch (SpoonException e) { } //When no element are found for a given role, return empty list. + } catch (SpoonException e) { } //When no element are found for a given role, return empty list.*/ } return matchs; } From b2266ae2c18bb2bd209477aea81f4b87402424cd Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Sun, 25 Feb 2018 17:59:30 +0100 Subject: [PATCH 17/26] refactor(CtRolePathElement): remove old commented implem --- .../reflect/path/impl/CtRolePathElement.java | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java index 5de5cb95563..a6d943c80a8 100644 --- a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java @@ -112,32 +112,6 @@ public Collection getElements(Collection roots) { break; } } - /*try { - if (root.getValueByRole(getRole()) instanceof List) { - if (getArguments().containsKey("index")) { - int index = Integer.parseInt(getArguments().get("index")); - matchs.add((CtElement) ((List) root.getValueByRole(getRole())).get(index)); - } - } else if (root.getValueByRole(getRole()) instanceof Set) { - if (getArguments().containsKey("name")) { - String name = getArguments().get("name"); - try { - matchs.add(getFromSet(root.getValueByRole(getRole()), name)); - } catch (CtPathException e) { - //System.err.println("[ERROR] Element not found for name: " + name); - //No element found for name. - } - } - } else if (root.getValueByRole(getRole()) instanceof Map) { - if (getArguments().containsKey("key")) { - String name = getArguments().get("key"); - matchs.add((CtElement) ((Map) root.getValueByRole(getRole())).get(name)); - } - } else { - CtElement el = root.getValueByRole(getRole()); - matchs.add(el); - } - } catch (SpoonException e) { } //When no element are found for a given role, return empty list.*/ } return matchs; } From 1aaef217f2cf2b56722e5441561a6a6a07eabd04 Mon Sep 17 00:00:00 2001 From: Martin Monperrus Date: Sun, 25 Feb 2018 22:35:25 +0100 Subject: [PATCH 18/26] Update path.md --- doc/path.md | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/doc/path.md b/doc/path.md index 621c257bc0d..18bd415a89e 100644 --- a/doc/path.md +++ b/doc/path.md @@ -6,18 +6,27 @@ keywords: quering, query, path, ast, elements `CtPath` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/path/CtPath.html)) defines the path to a `CtElement` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/declaration/CtElement.html)) -in a model respectively to another element. A `CtPath` can also be used -to make a query to get elements and is based on three concepts: -names of elements, types of elements and roles of code elements. +in a model. For example, `.spoon.test.path.Foo.foo#body#statement[index=0]` represents the first statement of the body of method foo. -A role is a relation between two AST nodes, encoded as an AST node field. -For instance, a "then" branch in a if/then/else is a role (and not an node). +A `CtPath`is based on: names of elements (eg `foo`), and roles of elements with respect to their parent (eg `body`). +A role is a relation between two AST nodes. +For instance, a "then" branch in a if/then/else is a role (and not an node). All roles can be found in `CtRole`. In addition, each getter or setter in the metamodel is annotated with its role. -To build a path, you have two possibilities: `CtPathBuilder` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/path/CtPathBuilder.html)) -and `CtPathStringBuilder` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/path/CtPathStringBuilder.html)). -`CtPathBuilder` defines a fluent api to build your path. -`CtPathStringBuilder` creates a path object from a string according to a +To build a path, there are several possibilities: + +* method `getPath` in `CtElement` +* `CtPathStringBuilder` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/path/CtPathStringBuilder.html)). +it creates a path object from a string according to a syntax inspired from XPath and CSS selectors. +* the low-level `CtPathBuilder` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/path/CtPathBuilder.html)), it defines a fluent api to build your path. + +To evaluate a path, ie getting the elements represented by it, use `evaluateOn(List)` + +```java +path = new CtPathStringBuilder().fromString(".spoon.test.path.Foo.foo#body#statement[index=0]"); +List l = path.evaluateOn(root) +``` + ## CtPathStringBuilder @@ -69,4 +78,4 @@ in your project according to the rest of your path request. ``` new CtPathBuilder().recursiveWildcard().name("toto") new CtPathBuilder().name("toto").recursiveWildcard() -``` \ No newline at end of file +``` From d846e6f739836c21d3ce6be7e629c2dccf9a7584 Mon Sep 17 00:00:00 2001 From: Martin Monperrus Date: Sun, 25 Feb 2018 22:38:59 +0100 Subject: [PATCH 19/26] Update CtElement.java --- src/main/java/spoon/reflect/declaration/CtElement.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/spoon/reflect/declaration/CtElement.java b/src/main/java/spoon/reflect/declaration/CtElement.java index 4b81c074576..51f95629093 100644 --- a/src/main/java/spoon/reflect/declaration/CtElement.java +++ b/src/main/java/spoon/reflect/declaration/CtElement.java @@ -352,7 +352,7 @@ List getAnnotatedChildren( E setValueByRole(CtRole role, T value); /** - * Gets a unique path from models root to the CtElement. + * Return the path from the model root to this CtElement, eg `.spoon.test.path.Foo.foo#body#statement[index=0]` */ CtPath getPath(); From 047f9147f47e59bf87e1a63a24bf6f42a3974794 Mon Sep 17 00:00:00 2001 From: Martin Monperrus Date: Sun, 25 Feb 2018 23:03:49 +0100 Subject: [PATCH 20/26] adds super.scan because the diff coverage is strange see https://coveralls.io/builds/15690018/source?filename=src%2Fmain%2Fjava%2Fspoon%2Freflect%2Fpath%2FCtElementPathBuilder.java#L38 --- src/test/java/spoon/test/main/MainTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index e56a718baa9..f4be66e311d 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -470,6 +470,7 @@ public void scan(CtElement element) { fail("Path is either incorrectly generated or incorrectly read"); } } + super.scan(element); } }); } From b1f227605e424744b600dd563f8f81d7bb60d2be Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Sun, 25 Feb 2018 23:53:42 +0100 Subject: [PATCH 21/26] fix(CtElementPathBuilder): List.indexOf rely on equality not identity --- .../java/spoon/reflect/path/CtElementPathBuilder.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java index 4f407c51acf..019575f8f08 100644 --- a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java +++ b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java @@ -46,7 +46,15 @@ public CtPath fromElement(CtElement el, CtElement root) throws CtPathException { //Element needs to be differentiated from its brothers List list = roleHandler.asList(parent); //Assumes that List's order is deterministic. - int index = list.indexOf(cur); + //Can't be replaced by list.indexOf(cur) + //Because objects must be the same (and not just equals) + int index = 0; + for (Object o : list) { + if (o == cur) { + break; + } + index++; + } pathElement.addArgument("index", index + ""); break; From 786d41198ba00360520846063d371ac6b9617953 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Mon, 26 Feb 2018 00:30:43 +0100 Subject: [PATCH 22/26] refactor(CtElementPathBuilder): fix coding style --- src/main/java/spoon/reflect/path/CtElementPathBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java index 019575f8f08..df9728db0eb 100644 --- a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java +++ b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java @@ -49,7 +49,7 @@ public CtPath fromElement(CtElement el, CtElement root) throws CtPathException { //Can't be replaced by list.indexOf(cur) //Because objects must be the same (and not just equals) int index = 0; - for (Object o : list) { + for (Object o : list) { if (o == cur) { break; } From 8f82a94aea602d25d4618c3c944f21ed8cd47fbe Mon Sep 17 00:00:00 2001 From: Martin Monperrus Date: Mon, 26 Feb 2018 11:32:40 +0100 Subject: [PATCH 23/26] simplify api of evaluateOn --- src/main/java/spoon/reflect/path/CtPath.java | 9 +++------ src/main/java/spoon/reflect/path/impl/CtPathImpl.java | 6 +++--- src/test/java/spoon/test/main/MainTest.java | 3 +-- src/test/java/spoon/test/path/PathTest.java | 4 ++-- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/spoon/reflect/path/CtPath.java b/src/main/java/spoon/reflect/path/CtPath.java index dd2f3a37e24..98dbfc724a1 100644 --- a/src/main/java/spoon/reflect/path/CtPath.java +++ b/src/main/java/spoon/reflect/path/CtPath.java @@ -21,16 +21,13 @@ import java.util.Collection; /** - * A CtPath allow top define the path to a CtElement in the Spoon Model. + * A CtPath allows to define the path to a CtElement in the Spoon model, eg ".spoon.test.path.Foo.foo#body#statement[index=0]" */ public interface CtPath { /** - * Search some element matching this CtPatch from given nodes. - * - * @param startNode - * @return + * Search for elements matching this CtPatch from start nodes given as parameters. */ - Collection evaluateOn(Collection startNode); + Collection evaluateOn(CtElement... startNode); } diff --git a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java index ac9b821c9e2..f9c2542e608 100644 --- a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java +++ b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java @@ -19,7 +19,7 @@ import spoon.reflect.declaration.CtElement; import spoon.reflect.path.CtPath; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -36,8 +36,8 @@ public List getElements() { } @Override - public Collection evaluateOn(Collection startNode) { - Collection filtered = new ArrayList<>(startNode); + public Collection evaluateOn(CtElement... startNode) { + Collection filtered = Arrays.asList(startNode); for (CtPathElement element : elements) { filtered = element.getElements(filtered); } diff --git a/src/test/java/spoon/test/main/MainTest.java b/src/test/java/spoon/test/main/MainTest.java index f4be66e311d..5ccfa2359ff 100644 --- a/src/test/java/spoon/test/main/MainTest.java +++ b/src/test/java/spoon/test/main/MainTest.java @@ -451,7 +451,6 @@ public void scan(CtRole role, CtElement element) { @Test public void testElementToPathToElementEquivalency() { - List list = Arrays.asList(rootPackage); rootPackage.accept(new CtScanner() { @Override public void scan(CtElement element) { @@ -460,7 +459,7 @@ public void scan(CtElement element) { String pathStr = path.toString(); try { CtPath pathRead = new CtPathStringBuilder().fromString(pathStr); - Collection returnedElements = pathRead.evaluateOn(list); + Collection returnedElements = pathRead.evaluateOn(rootPackage); //contract: CtUniqueRolePathElement.evaluateOn() returns a unique elements if provided only a list of one inputs assertEquals(returnedElements.size(), 1); CtElement actualElement = (CtElement) returnedElements.toArray()[0]; diff --git a/src/test/java/spoon/test/path/PathTest.java b/src/test/java/spoon/test/path/PathTest.java index edfdbb91bf2..486890c6a6e 100644 --- a/src/test/java/spoon/test/path/PathTest.java +++ b/src/test/java/spoon/test/path/PathTest.java @@ -45,13 +45,13 @@ public void setup() throws Exception { } private void equals(CtPath path, CtElement... elements) { - Collection result = path.evaluateOn(Arrays.asList(factory.Package().getRootPackage())); + Collection result = path.evaluateOn(factory.Package().getRootPackage()); assertEquals(elements.length, result.size()); assertArrayEquals(elements, result.toArray(new CtElement[0])); } private void equalsSet(CtPath path, Set elements) { - Collection result = path.evaluateOn(Arrays.asList(factory.Package().getRootPackage())); + Collection result = path.evaluateOn(factory.Package().getRootPackage()); assertEquals(elements.size(), result.size()); assertTrue(result.containsAll(elements)); } From 8cfc1adeff6331dc05d73a316ab6d78d2cc54e7d Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Mon, 26 Feb 2018 15:49:31 +0100 Subject: [PATCH 24/26] fix(CtRolePathElement): the evaluation of a path that leads nowhere returns an empty collection. Add test for such events --- .../reflect/path/CtElementPathBuilder.java | 5 ++- .../reflect/path/impl/CtRolePathElement.java | 14 ++++++-- .../reflect/declaration/CtElementImpl.java | 2 +- src/test/java/spoon/test/path/Foo.java | 4 +++ src/test/java/spoon/test/path/PathTest.java | 36 +++++++++++++++++++ 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java index df9728db0eb..d5bd8bc72f2 100644 --- a/src/main/java/spoon/reflect/path/CtElementPathBuilder.java +++ b/src/main/java/spoon/reflect/path/CtElementPathBuilder.java @@ -33,8 +33,11 @@ public CtPath fromElement(CtElement el, CtElement root) throws CtPathException { while (cur != root) { CtElement parent = cur.getParent(); CtRole role = cur.getRoleInParent(); + if (role == null) { + throw new CtPathException(); + } RoleHandler roleHandler = RoleHandlerHelper.getOptionalRoleHandler(parent.getClass(), role); - if (role == null || roleHandler == null) { + if (roleHandler == null) { throw new CtPathException(); } CtPathElement pathElement = new CtRolePathElement(role); diff --git a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java index a6d943c80a8..74961572333 100644 --- a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java @@ -82,13 +82,19 @@ public Collection getElements(Collection roots) { if (roleHandler != null) { switch (roleHandler.getContainerKind()) { case SINGLE: - matchs.add(roleHandler.getValue(root)); + if (roleHandler.getValue(root) != null) { + matchs.add(roleHandler.getValue(root)); + } break; case LIST: if (getArguments().containsKey("index")) { int index = Integer.parseInt(getArguments().get("index")); - matchs.add((CtElement) roleHandler.asList(root).get(index)); + if (index < roleHandler.asList(root).size()) { + matchs.add((CtElement) roleHandler.asList(root).get(index)); + } + } else { + matchs.addAll(roleHandler.asList(root)); } break; @@ -107,7 +113,9 @@ public Collection getElements(Collection roots) { case MAP: if (getArguments().containsKey("key")) { String name = getArguments().get("key"); - matchs.add((CtElement) roleHandler.asMap(root).get(name)); + if (roleHandler.asMap(root).containsKey(name)) { + matchs.add((CtElement) roleHandler.asMap(root).get(name)); + } } break; } diff --git a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java index 653d6b2d8bc..73f534526db 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java @@ -546,7 +546,7 @@ public CtPath getPath() { try { return new CtElementPathBuilder().fromElement(this, getParent(CtModelImpl.CtRootPackage.class)); } catch (CtPathException e) { - throw new SpoonException(); + throw new SpoonException(e); } } } diff --git a/src/test/java/spoon/test/path/Foo.java b/src/test/java/spoon/test/path/Foo.java index 7cb37f85328..24f9493e147 100644 --- a/src/test/java/spoon/test/path/Foo.java +++ b/src/test/java/spoon/test/path/Foo.java @@ -18,8 +18,12 @@ void foo() { } } + @java.lang.SuppressWarnings("unchecked") void bar(int i, int j) { int x = 3; x = x + 1; + if (i > 5) { + x += 1; + } } } \ No newline at end of file diff --git a/src/test/java/spoon/test/path/PathTest.java b/src/test/java/spoon/test/path/PathTest.java index 486890c6a6e..9fff59008ce 100644 --- a/src/test/java/spoon/test/path/PathTest.java +++ b/src/test/java/spoon/test/path/PathTest.java @@ -10,6 +10,7 @@ import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtMethod; import spoon.reflect.factory.Factory; +import spoon.reflect.path.CtElementPathBuilder; import spoon.reflect.path.CtPath; import spoon.reflect.path.CtPathBuilder; import spoon.reflect.path.CtPathException; @@ -25,6 +26,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * Created by nicolas on 10/06/2015. @@ -102,6 +104,40 @@ public void testPathFromString() throws Exception { equals(new CtPathStringBuilder().fromString(".spoon.test.path.Foo.toto#defaultExpression"), literal); } + @Test + public void testIncorrectPathFromString() throws Exception { + // match the else part of the if in Foo.bar() method which does not exist (Test non existing unique element) + Collection results = new CtPathStringBuilder().fromString(".spoon.test.path.Foo.bar#body#statement[index=2]#else") + .evaluateOn(factory.getModel().getRootPackage()); + assertEquals(results.size(), 0); + // match the third statement of Foo.foo() method which does not exist (Test non existing element of a list) + results = new CtPathStringBuilder().fromString(".spoon.test.path.Foo.foo#body#statement[index=3]") + .evaluateOn(factory.getModel().getRootPackage()); + assertEquals(results.size(), 0); + // match an non existing package (Test non existing element of a set) + results = new CtPathStringBuilder().fromString("#subPackage[name=nonExistingPackage]") + .evaluateOn(factory.getModel().getRootPackage()); + assertEquals(results.size(), 0); + //match a non existing field of an annotation (Test non existing element of a map) + results = new CtPathStringBuilder().fromString(".spoon.test.path.Foo.bar##annotation[index=0]#value[key=misspelled]") + .evaluateOn(factory.getModel().getRootPackage()); + assertEquals(results.size(), 0); + } + + @Test + public void testGetPathFromNonParent() throws Exception { + CtMethod fooMethod = (CtMethod) new CtPathStringBuilder().fromString(".spoon.test.path.Foo.foo") + .evaluateOn(factory.getModel().getRootPackage()).iterator().next(); + CtMethod barMethod = (CtMethod) new CtPathStringBuilder().fromString(".spoon.test.path.Foo.bar") + .evaluateOn(factory.getModel().getRootPackage()).iterator().next(); + try { + new CtElementPathBuilder().fromElement(fooMethod,barMethod); + fail("No path should be found to .spoon.test.path.Foo.foo from .spoon.test.path.Foo.bar"); + } catch (CtPathException e) { + + } + } + @Test public void testWildcards() throws Exception { // get the first statements of all Foo methods From 67ec78bbfea873e74510794e9d533eff51432984 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Mon, 26 Feb 2018 17:11:15 +0100 Subject: [PATCH 25/26] fix(CtRolePathElement): extends unspecified index behavior to sets and maps. add tests --- .../reflect/path/impl/CtRolePathElement.java | 6 ++++++ src/test/java/spoon/test/path/PathTest.java | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java index 74961572333..cc13042b733 100644 --- a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.LinkedList; +import java.util.Map; import java.util.Set; /** @@ -107,6 +108,8 @@ public Collection getElements(Collection roots) { //System.err.println("[ERROR] Element not found for name: " + name); //No element found for name. } + } else { + matchs.addAll(roleHandler.asSet(root)); } break; @@ -116,6 +119,9 @@ public Collection getElements(Collection roots) { if (roleHandler.asMap(root).containsKey(name)) { matchs.add((CtElement) roleHandler.asMap(root).get(name)); } + } else { + Map map = roleHandler.asMap(root); + matchs.addAll(map.values()); } break; } diff --git a/src/test/java/spoon/test/path/PathTest.java b/src/test/java/spoon/test/path/PathTest.java index 9fff59008ce..b7a145a2bf5 100644 --- a/src/test/java/spoon/test/path/PathTest.java +++ b/src/test/java/spoon/test/path/PathTest.java @@ -104,6 +104,23 @@ public void testPathFromString() throws Exception { equals(new CtPathStringBuilder().fromString(".spoon.test.path.Foo.toto#defaultExpression"), literal); } + @Test + public void testMultiPathFromString() throws Exception { + // When role match a list but no index is provided, all of them must be returned + Collection results = new CtPathStringBuilder().fromString(".spoon.test.path.Foo.foo#body#statement") + .evaluateOn(factory.getModel().getRootPackage()); + assertEquals(results.size(), 3); + // When role match a set but no name is provided, all of them must be returned + results = new CtPathStringBuilder().fromString("#subPackage") + .evaluateOn(factory.getModel().getRootPackage()); + assertEquals(results.size(), 1); + // When role match a map but no key is provided, all of them must be returned + results = new CtPathStringBuilder().fromString(".spoon.test.path.Foo.bar##annotation[index=0]#value") + .evaluateOn(factory.getModel().getRootPackage()); + assertEquals(results.size(), 1); + + } + @Test public void testIncorrectPathFromString() throws Exception { // match the else part of the if in Foo.bar() method which does not exist (Test non existing unique element) From 7ee992176b01e138e1d5d4f07d9f53247c04eba6 Mon Sep 17 00:00:00 2001 From: Nicolas Harrand Date: Mon, 26 Feb 2018 18:18:34 +0100 Subject: [PATCH 26/26] fix(CtRolePathElement): replace exception throwing with return null when element is not found in set --- .../spoon/reflect/path/impl/CtRolePathElement.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java index cc13042b733..a0bf27b3f8d 100644 --- a/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java +++ b/src/main/java/spoon/reflect/path/impl/CtRolePathElement.java @@ -58,7 +58,7 @@ public String toString() { return STRING + getRole().toString() + getParamString(); } - public CtElement getFromSet(Set set, String name) throws CtPathException { + private CtElement getFromSet(Set set, String name) throws CtPathException { for (Object o: set) { if (o instanceof CtNamedElement) { if (((CtNamedElement) o).getSimpleName().equals(name)) { @@ -72,7 +72,8 @@ public CtElement getFromSet(Set set, String name) throws CtPathException { throw new CtPathException(); } } - throw new CtPathException(); + //Element is not found in set. + return null; } @Override @@ -103,7 +104,10 @@ public Collection getElements(Collection roots) { if (getArguments().containsKey("name")) { String name = getArguments().get("name"); try { - matchs.add(getFromSet(roleHandler.asSet(root), name)); + CtElement match = getFromSet(roleHandler.asSet(root), name); + if (match != null) { + matchs.add(match); + } } catch (CtPathException e) { //System.err.println("[ERROR] Element not found for name: " + name); //No element found for name.