From 3766b36f2f0c49805777b27c310da10717e4500e Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 14:43:21 +0800 Subject: [PATCH 01/12] feat(CtType): add method `getMethodBySignature` --- .../java/spoon/reflect/declaration/CtType.java | 8 ++++++++ .../support/reflect/declaration/CtTypeImpl.java | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/main/java/spoon/reflect/declaration/CtType.java b/src/main/java/spoon/reflect/declaration/CtType.java index c8d0f55d049..7b9c0ea4d4e 100644 --- a/src/main/java/spoon/reflect/declaration/CtType.java +++ b/src/main/java/spoon/reflect/declaration/CtType.java @@ -234,6 +234,14 @@ public interface CtType extends CtNamedElement, CtTypeInformation, CtTypeMemb @PropertyGetter(role = METHOD) CtMethod getMethod(String name, CtTypeReference... parameterTypes); + /** + * Gets a method from its signature. + * + * @return null if does not exit + */ + @PropertyGetter(role = METHOD) + CtMethod getMethodBySignature(String signature); + /** * Returns the methods that are directly declared by this class or * interface. diff --git a/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java b/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java index 8e4a5804c7f..818f72b2e3a 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java @@ -723,6 +723,21 @@ public CtMethod getMethod(String name, CtTypeReference... parameterTyp return null; } + @Override + @SuppressWarnings("unchecked") + public CtMethod getMethodBySignature(String signature) { + if (signature == null) { + return null; + } + String name = signature.substring(0, signature.indexOf('(')); + for (CtMethod candidate : getMethodsByName(name)) { + if (candidate.getSignature().equals(signature)) { + return (CtMethod) candidate; + } + } + return null; + } + protected boolean hasSameParameters(CtExecutable candidate, CtTypeReference... parameterTypes) { if (candidate.getParameters().size() != parameterTypes.length) { return false; From c7b28ac219419300fe2aecd496f9156237bc7d07 Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 14:47:12 +0800 Subject: [PATCH 02/12] feat(CtClass): add method `getConstructorBySignature` --- .../java/spoon/reflect/declaration/CtClass.java | 12 ++++++++++++ .../support/reflect/declaration/CtClassImpl.java | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/main/java/spoon/reflect/declaration/CtClass.java b/src/main/java/spoon/reflect/declaration/CtClass.java index 02d4948031b..19fe72dd52b 100644 --- a/src/main/java/spoon/reflect/declaration/CtClass.java +++ b/src/main/java/spoon/reflect/declaration/CtClass.java @@ -49,6 +49,18 @@ public interface CtClass extends CtType, CtStatement, CtSealable { @PropertyGetter(role = CONSTRUCTOR) CtConstructor getConstructor(CtTypeReference... parameterTypes); + /** + * Returns the constructor of the class that takes the given signature. + * e.g. java.util.HashSet has constructor with no parameters `()` + * e.g. java.util.HashSet has constructor with a int and a float parameters `(int,float)` + * e.g. java.util.HashSet has constructor with a java.util.Collection parameter `(java.util.Collection)` + * + * Derived from {@link #getTypeMembers()} + */ + @DerivedProperty + @PropertyGetter(role = CONSTRUCTOR) + CtConstructor getConstructorBySignature(String signature); + /** * Returns the constructors of this class. This includes the default * constructor if this class has no constructors explicitly declared. diff --git a/src/main/java/spoon/support/reflect/declaration/CtClassImpl.java b/src/main/java/spoon/support/reflect/declaration/CtClassImpl.java index 3f946dbe526..266f50fb8d5 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtClassImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtClassImpl.java @@ -88,6 +88,20 @@ public CtConstructor getConstructor(CtTypeReference... parameterTypes) { return null; } + @Override + public CtConstructor getConstructorBySignature(String signature) { + for (CtTypeMember typeMember : getTypeMembers()) { + if (!(typeMember instanceof CtConstructor)) { + continue; + } + CtConstructor c = (CtConstructor) typeMember; + if (c.getSignature().replaceAll(c.getDeclaringType().getQualifiedName(), "").equals(signature)) { + return c; + } + } + return null; + } + @Override public Set> getConstructors() { Set> constructors = new SignatureBasedSortedSet<>(); From 056b96c6872b17dfd5668772ccff8556a1fb885d Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 15:01:22 +0800 Subject: [PATCH 03/12] fix(CtPathStringBuilder): delete redundant ')' when calling `AbstractPathElement.getArguments([constructor with no parameters])` will produce redundant ')' --- src/main/java/spoon/reflect/path/CtPathStringBuilder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java index 7082db76d81..2013757bf01 100644 --- a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java +++ b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java @@ -145,7 +145,8 @@ private String parseArgumentValue(Tokenizer tokenizer, String argName, CtPathEle } } else if ("]".equals(token) || ";".equals(token)) { //finished reading of argument value - pathElement.addArgument(argName, argValue.toString()); + //[fix bug]:AbstractPathElement.getArguments([constructor with no parameters]) + pathElement.addArgument(argName, argValue.toString().replace("())","()")); return token; } argValue.append(token); From f98231e9dd3a451bb1f782a78dfae95878f8b4fb Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 15:02:48 +0800 Subject: [PATCH 04/12] feat(CtPathImpl): add method `getJdkClass` --- .../spoon/reflect/path/impl/CtPathImpl.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java index a178f68c433..09381abe0cf 100644 --- a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java +++ b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java @@ -36,6 +36,32 @@ public List evaluateOn(CtElement... startNode) { return (List) filtered; } + private Class getJdkClass(String name) { + name = name.replaceAll("[\\[\\]]", ""); + switch (name) { + case "byte": + return byte.class; + case "int": + return int.class; + case "long": + return long.class; + case "float": + return float.class; + case "double": + return double.class; + case "char": + return char.class; + case "boolean": + return boolean.class; + default: + try { + return Class.forName(name); + } catch (ClassNotFoundException e) { + } + } + return null; + } + @Override public CtPath relativePath(CtElement parent) { List roots = new ArrayList<>(); From 8a78406974a5bcdeb84109a6777919c71c1572e8 Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 15:16:33 +0800 Subject: [PATCH 05/12] feat(CtPathImpl): rewrite method `evaluateOn` Test cases have passed. Now it supports to get JDK-element from CtPath(As String). --- .../spoon/reflect/path/impl/CtPathImpl.java | 39 +++++++++++++ src/test/java/spoon/test/path/PathTest.java | 57 +++++++++++-------- 2 files changed, 72 insertions(+), 24 deletions(-) diff --git a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java index 09381abe0cf..4dc9ba82745 100644 --- a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java +++ b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java @@ -7,8 +7,12 @@ */ package spoon.reflect.path.impl; +import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtElement; +import spoon.reflect.declaration.CtType; +import spoon.reflect.factory.TypeFactory; import spoon.reflect.path.CtPath; +import spoon.reflect.path.CtRole; import java.util.ArrayList; import java.util.Arrays; @@ -33,6 +37,41 @@ public List evaluateOn(CtElement... startNode) { for (CtPathElement element : elements) { filtered = element.getElements(filtered); } + if (filtered.isEmpty()) { + List cls_name_list = new LinkedList<>(); + CtType ctType = null; + for (CtPathElement element : elements) { + if (element instanceof CtRolePathElement) { // search by CtRolePathElement + Collection values = ((CtRolePathElement) element).getArguments().values(); + String val = null; + if (values.iterator().hasNext()) val = values.iterator().next(); + if (val != null) { + if (CtRole.SUB_PACKAGE.equals(((CtRolePathElement) element).getRole()) + || CtRole.CONTAINED_TYPE.equals(((CtRolePathElement) element).getRole())) + cls_name_list.add(val); + + Class cls = getJdkClass(String.join(".", cls_name_list)); + if (cls != null) { + ctType = new TypeFactory().get(cls); + if (ctType != null) { + CtElement result = null; + if (CtRole.METHOD.equals(((CtRolePathElement) element).getRole())) { + result = ctType.getMethodBySignature(val); + } + if (CtRole.CONSTRUCTOR.equals(((CtRolePathElement) element).getRole())) { + result = ((CtClass) ctType).getConstructorBySignature(val); + } + if (CtRole.FIELD.equals(((CtRolePathElement) element).getRole())) { + result = ctType.getField(val); + } + if (result != null) filtered.add(result); + } + } + } + } + } + if (filtered.isEmpty() && ctType != null) filtered.add(ctType); + } return (List) filtered; } diff --git a/src/test/java/spoon/test/path/PathTest.java b/src/test/java/spoon/test/path/PathTest.java index eccb2340265..25c48698cc9 100644 --- a/src/test/java/spoon/test/path/PathTest.java +++ b/src/test/java/spoon/test/path/PathTest.java @@ -17,12 +17,6 @@ package spoon.test.path; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import spoon.Launcher; @@ -31,30 +25,18 @@ import spoon.reflect.code.CtInvocation; import spoon.reflect.code.CtLiteral; import spoon.reflect.code.CtStatement; -import spoon.reflect.declaration.CtClass; -import spoon.reflect.declaration.CtConstructor; -import spoon.reflect.declaration.CtElement; -import spoon.reflect.declaration.CtMethod; -import spoon.reflect.declaration.CtParameter; -import spoon.reflect.declaration.CtType; -import spoon.reflect.declaration.CtTypeMember; +import spoon.reflect.declaration.*; 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; -import spoon.reflect.path.CtPathStringBuilder; -import spoon.reflect.path.CtRole; +import spoon.reflect.factory.TypeFactory; +import spoon.reflect.path.*; import spoon.reflect.reference.CtTypeParameterReference; import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.filter.NamedElementFilter; import spoon.reflect.visitor.filter.TypeFilter; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; /** * Created by nicolas on 10/06/2015. @@ -409,4 +391,31 @@ public void testFieldOfArrayType() { assertEquals(1, result.size()); assertSame(argType, result.get(0)); } + + @Test + public void testGetJdkElementByCtPathString() { + CtPath path; + // test class + path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]"); + assertTrue(path.evaluateOn().iterator().hasNext()); + CtType class_HashSet = new TypeFactory().get(java.util.HashSet.class); + assertEquals(path.evaluateOn().iterator().next(), class_HashSet); + // if unable to get the method or the field, it will try to return the method. + // test method + path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]#method[signature=contains(java.lang.Object)]"); + assertTrue(path.evaluateOn().iterator().hasNext()); + assertEquals(path.evaluateOn().iterator().next(), class_HashSet.getMethodBySignature("contains(java.lang.Object)")); + // test constructor + path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]#constructor[signature=()]"); + assertTrue(path.evaluateOn().iterator().hasNext()); + assertEquals(path.evaluateOn().iterator().next(), ((CtClass) class_HashSet).getConstructorBySignature("()")); + + path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]#constructor[signature=(int)]"); + assertTrue(path.evaluateOn().iterator().hasNext()); + assertEquals(path.evaluateOn().iterator().next(), ((CtClass) class_HashSet).getConstructorBySignature("(int)")); + // test field + path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]#field[name=map]"); + assertTrue(path.evaluateOn().iterator().hasNext()); + assertEquals(path.evaluateOn().iterator().next(), class_HashSet.getField("map")); + } } \ No newline at end of file From ed960fbfd5f20148ff5aecda99f5ab54062856d4 Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 16:47:06 +0800 Subject: [PATCH 06/12] docs(path.md): update doc --- doc/path.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/path.md b/doc/path.md index 578651040b2..89ef5b0b845 100644 --- a/doc/path.md +++ b/doc/path.md @@ -13,13 +13,22 @@ For instance, a "then" branch in an if/then/else is a role (and not a node). All ### Evaluating AST paths -Paths are used to find code elements, from a given root element. +Paths are used to find code elements, from a given root element(e.g. `model.getRootPackage()`). ```java path = new CtPathStringBuilder().fromString(".spoon.test.path.testclasses.Foo.foo#body#statement[index=0]"); List l = path.evaluateOn(root) ``` +If the root parameter is not given, spoon will try to find shadow elements(e.g. jdk classes). + +> If so, it can only supperts `CtType`, `CtMethod` and `CtField` for now. + +```java +path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]"); +List l = path.evaluateOn() +``` + ### Creating AST paths #### From an existing element From 0bfa2d43e08879a0566d1a4954329cd1a982c77c Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 17:10:15 +0800 Subject: [PATCH 07/12] refactor(CtPathImpl): optimization code --- src/main/java/spoon/reflect/path/impl/CtPathImpl.java | 10 +++------- src/test/java/spoon/test/path/PathTest.java | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java index 4dc9ba82745..1432856d129 100644 --- a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java +++ b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java @@ -14,11 +14,7 @@ import spoon.reflect.path.CtPath; import spoon.reflect.path.CtRole; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; +import java.util.*; /** * Default implementation for a CtPath @@ -52,8 +48,8 @@ public List evaluateOn(CtElement... startNode) { Class cls = getJdkClass(String.join(".", cls_name_list)); if (cls != null) { - ctType = new TypeFactory().get(cls); - if (ctType != null) { + if (ctType == null) ctType = new TypeFactory().get(cls); + else { CtElement result = null; if (CtRole.METHOD.equals(((CtRolePathElement) element).getRole())) { result = ctType.getMethodBySignature(val); diff --git a/src/test/java/spoon/test/path/PathTest.java b/src/test/java/spoon/test/path/PathTest.java index 25c48698cc9..8ee4531b925 100644 --- a/src/test/java/spoon/test/path/PathTest.java +++ b/src/test/java/spoon/test/path/PathTest.java @@ -400,7 +400,7 @@ public void testGetJdkElementByCtPathString() { assertTrue(path.evaluateOn().iterator().hasNext()); CtType class_HashSet = new TypeFactory().get(java.util.HashSet.class); assertEquals(path.evaluateOn().iterator().next(), class_HashSet); - // if unable to get the method or the field, it will try to return the method. + // if unable to get the method or the field, it will try to return the class. // test method path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]#method[signature=contains(java.lang.Object)]"); assertTrue(path.evaluateOn().iterator().hasNext()); From 120ac0dfd68a17be81094bac2e78344f5c9d0f26 Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 18:58:12 +0800 Subject: [PATCH 08/12] refactor(PathTest): revert imports --- src/test/java/spoon/test/path/PathTest.java | 29 +++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/test/java/spoon/test/path/PathTest.java b/src/test/java/spoon/test/path/PathTest.java index 8ee4531b925..bb323ad1a40 100644 --- a/src/test/java/spoon/test/path/PathTest.java +++ b/src/test/java/spoon/test/path/PathTest.java @@ -17,6 +17,12 @@ package spoon.test.path; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import spoon.Launcher; @@ -25,18 +31,31 @@ import spoon.reflect.code.CtInvocation; import spoon.reflect.code.CtLiteral; import spoon.reflect.code.CtStatement; -import spoon.reflect.declaration.*; +import spoon.reflect.declaration.CtClass; +import spoon.reflect.declaration.CtConstructor; +import spoon.reflect.declaration.CtElement; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtParameter; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeMember; import spoon.reflect.factory.Factory; import spoon.reflect.factory.TypeFactory; -import spoon.reflect.path.*; +import spoon.reflect.path.CtElementPathBuilder; +import spoon.reflect.path.CtPath; +import spoon.reflect.path.CtPathBuilder; +import spoon.reflect.path.CtPathException; +import spoon.reflect.path.CtPathStringBuilder; +import spoon.reflect.path.CtRole; import spoon.reflect.reference.CtTypeParameterReference; import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.filter.NamedElementFilter; import spoon.reflect.visitor.filter.TypeFilter; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * Created by nicolas on 10/06/2015. From bbbbebabeb36110548ac503c81332027a825c9ab Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 19:09:26 +0800 Subject: [PATCH 09/12] docs(path.md): update doc as suggested --- doc/path.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/path.md b/doc/path.md index 89ef5b0b845..0c8281ec2a3 100644 --- a/doc/path.md +++ b/doc/path.md @@ -13,16 +13,16 @@ For instance, a "then" branch in an if/then/else is a role (and not a node). All ### Evaluating AST paths -Paths are used to find code elements, from a given root element(e.g. `model.getRootPackage()`). +Paths are used to find code elements, from a given root element. ```java path = new CtPathStringBuilder().fromString(".spoon.test.path.testclasses.Foo.foo#body#statement[index=0]"); List l = path.evaluateOn(root) ``` -If the root parameter is not given, spoon will try to find shadow elements(e.g. jdk classes). +If the root parameter is omitted, spoon will try to find shadow elements (e.g. jdk classes). -> If so, it can only supperts `CtType`, `CtMethod` and `CtField` for now. +> Querying shadow elements currently only supports types, methods and fields. ```java path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]"); From 3b779ee2edb6f96dc00cceb33233864d6ab22042 Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Sun, 30 Oct 2022 19:39:28 +0800 Subject: [PATCH 10/12] refactor(CtPath): extract method `evaluateOnShadowModel` --- src/main/java/spoon/reflect/path/CtPath.java | 5 ++ .../spoon/reflect/path/impl/CtPathImpl.java | 56 +++++++++---------- src/test/java/spoon/test/path/PathTest.java | 21 +++---- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/main/java/spoon/reflect/path/CtPath.java b/src/main/java/spoon/reflect/path/CtPath.java index e50a5d95530..adaf1a2c0b5 100644 --- a/src/main/java/spoon/reflect/path/CtPath.java +++ b/src/main/java/spoon/reflect/path/CtPath.java @@ -21,6 +21,11 @@ public interface CtPath { */ List evaluateOn(CtElement... startNode); + /** + * Search for elements matching this CtPatch from shadow model. + */ + CtElement evaluateOnShadowModel(); + /** * * Returns the path that is relative to the given element (subpath from it to the end of the path). diff --git a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java index 1432856d129..8aabb12009c 100644 --- a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java +++ b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java @@ -33,42 +33,40 @@ public List evaluateOn(CtElement... startNode) { for (CtPathElement element : elements) { filtered = element.getElements(filtered); } - if (filtered.isEmpty()) { - List cls_name_list = new LinkedList<>(); - CtType ctType = null; - for (CtPathElement element : elements) { - if (element instanceof CtRolePathElement) { // search by CtRolePathElement - Collection values = ((CtRolePathElement) element).getArguments().values(); - String val = null; - if (values.iterator().hasNext()) val = values.iterator().next(); - if (val != null) { - if (CtRole.SUB_PACKAGE.equals(((CtRolePathElement) element).getRole()) - || CtRole.CONTAINED_TYPE.equals(((CtRolePathElement) element).getRole())) - cls_name_list.add(val); + return (List) filtered; + } + + @Override + public CtElement evaluateOnShadowModel() { + List cls_name_list = new LinkedList<>(); + CtType ctType = null; + for (CtPathElement element : elements) { + if (element instanceof CtRolePathElement) { // search by CtRolePathElement + Collection values = ((CtRolePathElement) element).getArguments().values(); + String val = null; + if (values.iterator().hasNext()) val = values.iterator().next(); + if (val != null) { + if (CtRole.SUB_PACKAGE.equals(((CtRolePathElement) element).getRole()) + || CtRole.CONTAINED_TYPE.equals(((CtRolePathElement) element).getRole())) + cls_name_list.add(val); - Class cls = getJdkClass(String.join(".", cls_name_list)); - if (cls != null) { - if (ctType == null) ctType = new TypeFactory().get(cls); - else { - CtElement result = null; - if (CtRole.METHOD.equals(((CtRolePathElement) element).getRole())) { - result = ctType.getMethodBySignature(val); - } - if (CtRole.CONSTRUCTOR.equals(((CtRolePathElement) element).getRole())) { - result = ((CtClass) ctType).getConstructorBySignature(val); - } - if (CtRole.FIELD.equals(((CtRolePathElement) element).getRole())) { - result = ctType.getField(val); - } - if (result != null) filtered.add(result); + Class cls = getJdkClass(String.join(".", cls_name_list)); + if (cls != null) { + if (ctType == null) ctType = new TypeFactory().get(cls); + else { + if (CtRole.METHOD.equals(((CtRolePathElement) element).getRole())) + return ctType.getMethodBySignature(val); + if (CtRole.CONSTRUCTOR.equals(((CtRolePathElement) element).getRole())) + return ((CtClass) ctType).getConstructorBySignature(val); + if (CtRole.FIELD.equals(((CtRolePathElement) element).getRole())) { + return ctType.getField(val); } } } } } - if (filtered.isEmpty() && ctType != null) filtered.add(ctType); } - return (List) filtered; + return ctType; } private Class getJdkClass(String name) { diff --git a/src/test/java/spoon/test/path/PathTest.java b/src/test/java/spoon/test/path/PathTest.java index bb323ad1a40..d0b9041f27f 100644 --- a/src/test/java/spoon/test/path/PathTest.java +++ b/src/test/java/spoon/test/path/PathTest.java @@ -56,6 +56,7 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertNotNull; /** * Created by nicolas on 10/06/2015. @@ -416,25 +417,25 @@ public void testGetJdkElementByCtPathString() { CtPath path; // test class path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]"); - assertTrue(path.evaluateOn().iterator().hasNext()); + assertNotNull(path.evaluateOnShadowModel()); CtType class_HashSet = new TypeFactory().get(java.util.HashSet.class); - assertEquals(path.evaluateOn().iterator().next(), class_HashSet); + assertEquals(path.evaluateOnShadowModel(), class_HashSet); // if unable to get the method or the field, it will try to return the class. // test method path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]#method[signature=contains(java.lang.Object)]"); - assertTrue(path.evaluateOn().iterator().hasNext()); - assertEquals(path.evaluateOn().iterator().next(), class_HashSet.getMethodBySignature("contains(java.lang.Object)")); + assertNotNull(path.evaluateOnShadowModel()); + assertEquals(path.evaluateOnShadowModel(), class_HashSet.getMethodBySignature("contains(java.lang.Object)")); // test constructor path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]#constructor[signature=()]"); - assertTrue(path.evaluateOn().iterator().hasNext()); - assertEquals(path.evaluateOn().iterator().next(), ((CtClass) class_HashSet).getConstructorBySignature("()")); + assertNotNull(path.evaluateOnShadowModel()); + assertEquals(path.evaluateOnShadowModel(), ((CtClass) class_HashSet).getConstructorBySignature("()")); path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]#constructor[signature=(int)]"); - assertTrue(path.evaluateOn().iterator().hasNext()); - assertEquals(path.evaluateOn().iterator().next(), ((CtClass) class_HashSet).getConstructorBySignature("(int)")); + assertNotNull(path.evaluateOnShadowModel()); + assertEquals(path.evaluateOnShadowModel(), ((CtClass) class_HashSet).getConstructorBySignature("(int)")); // test field path = new CtPathStringBuilder().fromString("#subPackage[name=java]#subPackage[name=util]#containedType[name=HashSet]#field[name=map]"); - assertTrue(path.evaluateOn().iterator().hasNext()); - assertEquals(path.evaluateOn().iterator().next(), class_HashSet.getField("map")); + assertNotNull(path.evaluateOnShadowModel()); + assertEquals(path.evaluateOnShadowModel(), class_HashSet.getField("map")); } } \ No newline at end of file From 6ddbcb2677164c231925f18f03929b6f44b28342 Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Mon, 31 Oct 2022 09:00:30 +0800 Subject: [PATCH 11/12] refactor: adjust code style --- .../reflect/path/CtPathStringBuilder.java | 4 +-- .../spoon/reflect/path/impl/CtPathImpl.java | 25 +++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java index 2013757bf01..7f1de58fff3 100644 --- a/src/main/java/spoon/reflect/path/CtPathStringBuilder.java +++ b/src/main/java/spoon/reflect/path/CtPathStringBuilder.java @@ -13,8 +13,8 @@ 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.CtRolePathElement; +import spoon.reflect.path.impl.CtTypedNameElement; import java.util.ArrayDeque; import java.util.Deque; @@ -146,7 +146,7 @@ private String parseArgumentValue(Tokenizer tokenizer, String argName, CtPathEle } else if ("]".equals(token) || ";".equals(token)) { //finished reading of argument value //[fix bug]:AbstractPathElement.getArguments([constructor with no parameters]) - pathElement.addArgument(argName, argValue.toString().replace("())","()")); + pathElement.addArgument(argName, argValue.toString().replace("())", "()")); return token; } argValue.append(token); diff --git a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java index 8aabb12009c..0dc7030f4d6 100644 --- a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java +++ b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java @@ -14,7 +14,11 @@ import spoon.reflect.path.CtPath; import spoon.reflect.path.CtRole; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; /** * Default implementation for a CtPath @@ -44,20 +48,25 @@ public CtElement evaluateOnShadowModel() { if (element instanceof CtRolePathElement) { // search by CtRolePathElement Collection values = ((CtRolePathElement) element).getArguments().values(); String val = null; - if (values.iterator().hasNext()) val = values.iterator().next(); + if (values.iterator().hasNext()) { + val = values.iterator().next(); + } if (val != null) { if (CtRole.SUB_PACKAGE.equals(((CtRolePathElement) element).getRole()) - || CtRole.CONTAINED_TYPE.equals(((CtRolePathElement) element).getRole())) + || CtRole.CONTAINED_TYPE.equals(((CtRolePathElement) element).getRole())) { cls_name_list.add(val); - + } Class cls = getJdkClass(String.join(".", cls_name_list)); if (cls != null) { - if (ctType == null) ctType = new TypeFactory().get(cls); - else { - if (CtRole.METHOD.equals(((CtRolePathElement) element).getRole())) + if (ctType == null) { + ctType = new TypeFactory().get(cls); + } else { + if (CtRole.METHOD.equals(((CtRolePathElement) element).getRole())) { return ctType.getMethodBySignature(val); - if (CtRole.CONSTRUCTOR.equals(((CtRolePathElement) element).getRole())) + } + if (CtRole.CONSTRUCTOR.equals(((CtRolePathElement) element).getRole())) { return ((CtClass) ctType).getConstructorBySignature(val); + } if (CtRole.FIELD.equals(((CtRolePathElement) element).getRole())) { return ctType.getField(val); } From 02adcd811a997644dd8321a67dc3378018527226 Mon Sep 17 00:00:00 2001 From: kaml8 <62456016+kaml8@users.noreply.github.com> Date: Mon, 31 Oct 2022 09:08:12 +0800 Subject: [PATCH 12/12] refactor: adjust codeStyle --- src/main/java/spoon/reflect/path/impl/CtPathImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java index 0dc7030f4d6..ab78cd72469 100644 --- a/src/main/java/spoon/reflect/path/impl/CtPathImpl.java +++ b/src/main/java/spoon/reflect/path/impl/CtPathImpl.java @@ -42,7 +42,7 @@ public List evaluateOn(CtElement... startNode) { @Override public CtElement evaluateOnShadowModel() { - List cls_name_list = new LinkedList<>(); + List classRoleNameList = new LinkedList<>(); CtType ctType = null; for (CtPathElement element : elements) { if (element instanceof CtRolePathElement) { // search by CtRolePathElement @@ -54,9 +54,9 @@ public CtElement evaluateOnShadowModel() { if (val != null) { if (CtRole.SUB_PACKAGE.equals(((CtRolePathElement) element).getRole()) || CtRole.CONTAINED_TYPE.equals(((CtRolePathElement) element).getRole())) { - cls_name_list.add(val); + classRoleNameList.add(val); } - Class cls = getJdkClass(String.join(".", cls_name_list)); + Class cls = getJdkClass(String.join(".", classRoleNameList)); if (cls != null) { if (ctType == null) { ctType = new TypeFactory().get(cls);