From 5d5fc3b6c16a1cba718352101a7a231f1c784b04 Mon Sep 17 00:00:00 2001 From: Pavel Vojtechovsky Date: Sun, 12 Mar 2017 21:26:08 +0100 Subject: [PATCH] feature: CtMethod#isOverriding(CtMethod) --- .../spoon/reflect/declaration/CtMethod.java | 6 ++ .../filter/OverriddenMethodFilter.java | 5 +- .../filter/OverridingMethodFilter.java | 5 +- .../reflect/declaration/CtMethodImpl.java | 18 +++++ .../java/spoon/test/filters/FilterTest.java | 1 + .../MethodOverriddingTest.java | 74 +++++++++++++++++++ .../test/method_overriding/testclasses/A.java | 24 ++++++ .../test/method_overriding/testclasses/B.java | 32 ++++++++ .../test/method_overriding/testclasses/C.java | 30 ++++++++ .../test/method_overriding/testclasses/D.java | 24 ++++++ .../method_overriding/testclasses/IA.java | 5 ++ 11 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 src/test/java/spoon/test/method_overriding/MethodOverriddingTest.java create mode 100644 src/test/java/spoon/test/method_overriding/testclasses/A.java create mode 100644 src/test/java/spoon/test/method_overriding/testclasses/B.java create mode 100644 src/test/java/spoon/test/method_overriding/testclasses/C.java create mode 100644 src/test/java/spoon/test/method_overriding/testclasses/D.java create mode 100644 src/test/java/spoon/test/method_overriding/testclasses/IA.java diff --git a/src/main/java/spoon/reflect/declaration/CtMethod.java b/src/main/java/spoon/reflect/declaration/CtMethod.java index 158b31ac766..078a9c075f6 100644 --- a/src/main/java/spoon/reflect/declaration/CtMethod.java +++ b/src/main/java/spoon/reflect/declaration/CtMethod.java @@ -29,6 +29,12 @@ public interface CtMethod extends CtExecutable, CtTypeMember, CtFormalType */ boolean isSameSignature(CtMethod thatMethod, boolean canTypeErasure); + /** + * @param superMethod to be checked method + * @return true if this method overrides `superMethod` + */ + boolean isOverriding(CtMethod superMethod); + /** * Checks if the method is a default method. Default method can be in interfaces from * Java 8: http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html. diff --git a/src/main/java/spoon/reflect/visitor/filter/OverriddenMethodFilter.java b/src/main/java/spoon/reflect/visitor/filter/OverriddenMethodFilter.java index e8cb9231fa6..d3e2cb87165 100644 --- a/src/main/java/spoon/reflect/visitor/filter/OverriddenMethodFilter.java +++ b/src/main/java/spoon/reflect/visitor/filter/OverriddenMethodFilter.java @@ -40,8 +40,7 @@ public OverriddenMethodFilter(CtMethod method) { public boolean matches(CtMethod element) { final CtType expectedParent = method.getParent(CtType.class); final CtType currentParent = element.getParent(CtType.class); - return expectedParent.isSubtypeOf(currentParent.getReference()) // - && !currentParent.equals(expectedParent) // - && method.getReference().isOverriding(element.getReference()); + return !currentParent.equals(expectedParent) // + && method.isOverriding(element); } } diff --git a/src/main/java/spoon/reflect/visitor/filter/OverridingMethodFilter.java b/src/main/java/spoon/reflect/visitor/filter/OverridingMethodFilter.java index 24723bb3695..3c7af59bd0c 100644 --- a/src/main/java/spoon/reflect/visitor/filter/OverridingMethodFilter.java +++ b/src/main/java/spoon/reflect/visitor/filter/OverridingMethodFilter.java @@ -40,8 +40,7 @@ public OverridingMethodFilter(CtMethod method) { public boolean matches(CtMethod element) { final CtType expectedParent = method.getParent(CtType.class); final CtType currentParent = element.getParent(CtType.class); - return currentParent.isSubtypeOf(expectedParent.getReference()) // - && !currentParent.equals(expectedParent) // - && element.getReference().isOverriding(method.getReference()); + return !currentParent.equals(expectedParent) // + && element.isOverriding(method); } } diff --git a/src/main/java/spoon/support/reflect/declaration/CtMethodImpl.java b/src/main/java/spoon/support/reflect/declaration/CtMethodImpl.java index 95d35868831..03e1528727a 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtMethodImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtMethodImpl.java @@ -252,6 +252,24 @@ public boolean isSameSignature(CtMethod thatMethod, boolean canTypeErasure) { return true; } + @Override + public boolean isOverriding(CtMethod superMethod) { + if (this == superMethod) { + return true; + } + if (isSameSignature(superMethod, true) == false) { + return false; + } + CtType thisDeclType = getDeclaringType(); + CtType superDeclType = superMethod.getDeclaringType(); + if (thisDeclType == superDeclType) { + //if two different methods are declared in the same type then they cannot override + return false; + } + //methods override if thisDeclType is subtype of superDeclType + return thisDeclType.isSubtypeOf(superDeclType.getReference()); + } + /** * adapt all CtTypeParameterReference to targetType * @param types list of to be adapted types diff --git a/src/test/java/spoon/test/filters/FilterTest.java b/src/test/java/spoon/test/filters/FilterTest.java index 28c9f90b9fe..544e984d12a 100644 --- a/src/test/java/spoon/test/filters/FilterTest.java +++ b/src/test/java/spoon/test/filters/FilterTest.java @@ -538,6 +538,7 @@ class Context { // actual evaluation q.forEach((CtMethod method) -> { assertTrue(context.method.getReference().isOverriding(method.getReference())); + assertTrue(context.method.isOverriding(method)); context.count++; }); // sanity check diff --git a/src/test/java/spoon/test/method_overriding/MethodOverriddingTest.java b/src/test/java/spoon/test/method_overriding/MethodOverriddingTest.java new file mode 100644 index 00000000000..fd788f3d29a --- /dev/null +++ b/src/test/java/spoon/test/method_overriding/MethodOverriddingTest.java @@ -0,0 +1,74 @@ +package spoon.test.method_overriding; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; + +import org.junit.Test; + +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.factory.Factory; +import spoon.reflect.visitor.filter.TypeFilter; +import spoon.testing.utils.ModelUtils; + +import static org.junit.Assert.*; + +public class MethodOverriddingTest { + + @Test + public void testMethodOverride() { + checkMethodOverride((m1, m2)->m1.isOverriding(m2)); + } + @Test + public void testMethodOverrideByReference() { + checkMethodOverride((m1, m2)->m1.getReference().isOverriding(m2.getReference())); + } + + private void checkMethodOverride(BiFunction, CtMethod, Boolean> isOverriding) { + Factory factory = ModelUtils.build(new File("src/test/java/spoon/test/method_overriding/testclasses").listFiles()); + Map> methodsByName = new HashMap<>(); + factory.getModel().getRootPackage().filterChildren(new TypeFilter<>(CtMethod.class)).forEach((CtMethod m)->{ + List methods = methodsByName.get(m.getSimpleName()); + if(methods==null) { + methods = new ArrayList<>(); + methodsByName.put(m.getSimpleName(), methods); + } + methods.add(m); + }); + for (Map.Entry> e : methodsByName.entrySet()) { + combine(e.getValue(), 0, isOverriding); + } + } + + private void combine(List value, int start, BiFunction, CtMethod, Boolean> isOverriding) { + CtMethod m1 = value.get(start); + if(start+1, CtMethod, Boolean> isOverriding) { + assertTrue(descr(m1)+" overriding "+descr(m2), isOverriding.apply(m1, m2)); + assertFalse(descr(m2)+" NOT overriding "+descr(m1), isOverriding.apply(m2, m1)); + } + private void checkNotOverride(CtMethod m1, CtMethod m2, BiFunction, CtMethod, Boolean> isOverriding) { + assertFalse(descr(m1)+" NOT overriding "+descr(m2), isOverriding.apply(m1, m2)); + assertFalse(descr(m2)+" NOT overriding "+descr(m1), isOverriding.apply(m2, m1)); + } + + private String descr(CtMethod m) { + return m.getDeclaringType().getSimpleName()+"#"+m.getSimpleName(); + } +} diff --git a/src/test/java/spoon/test/method_overriding/testclasses/A.java b/src/test/java/spoon/test/method_overriding/testclasses/A.java new file mode 100644 index 00000000000..806f083d6a2 --- /dev/null +++ b/src/test/java/spoon/test/method_overriding/testclasses/A.java @@ -0,0 +1,24 @@ +package spoon.test.method_overriding.testclasses; + +import java.util.List; + +public class A { + + public A() { + } + + A m1(C c){ + return null; + } + + > T m2(C c){ + return null; + } + + void m3(List c){ + } + void m4(List> c){ + } + void m5(U u) { + } +} diff --git a/src/test/java/spoon/test/method_overriding/testclasses/B.java b/src/test/java/spoon/test/method_overriding/testclasses/B.java new file mode 100644 index 00000000000..8e400c69652 --- /dev/null +++ b/src/test/java/spoon/test/method_overriding/testclasses/B.java @@ -0,0 +1,32 @@ +package spoon.test.method_overriding.testclasses; + +import java.util.List; + +public class B extends A { + + public B() { + } + + @Override + B m1(C c){ + return null; + } + + @Override + > T m2(C c){ + return null; + } + + @Override + void m3(List c){ + } + + @Override + void m5(S u) { + super.m5(u); + } + + @Override + void m4(List> c) { + } +} diff --git a/src/test/java/spoon/test/method_overriding/testclasses/C.java b/src/test/java/spoon/test/method_overriding/testclasses/C.java new file mode 100644 index 00000000000..7c5b9599265 --- /dev/null +++ b/src/test/java/spoon/test/method_overriding/testclasses/C.java @@ -0,0 +1,30 @@ +package spoon.test.method_overriding.testclasses; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.util.List; + +public class C extends B { + + public C() { + } + + @Override + B m1(C c){ + return null; + } + + @Override + B m2(C c){ + return null; + } + @Override + void m4(List> c){ + } + + @Override + void m5(InputStream u) { + super.m5(u); + } + +} diff --git a/src/test/java/spoon/test/method_overriding/testclasses/D.java b/src/test/java/spoon/test/method_overriding/testclasses/D.java new file mode 100644 index 00000000000..de6abf6a520 --- /dev/null +++ b/src/test/java/spoon/test/method_overriding/testclasses/D.java @@ -0,0 +1,24 @@ +package spoon.test.method_overriding.testclasses; + +import java.util.List; + +public class D extends B { + + public D() { + } + + @Override + B m1(C c){ + return null; + } + + @Override + D m2(C c){ + return null; + } + + @Override + void m4(List> c){ + } + +} diff --git a/src/test/java/spoon/test/method_overriding/testclasses/IA.java b/src/test/java/spoon/test/method_overriding/testclasses/IA.java new file mode 100644 index 00000000000..c9faf955ef9 --- /dev/null +++ b/src/test/java/spoon/test/method_overriding/testclasses/IA.java @@ -0,0 +1,5 @@ +package spoon.test.method_overriding.testclasses; + +public interface IA { + +}