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 super C> c){
+ }
+ void m4(List extends A> 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 super C> c){
+ }
+
+ @Override
+ void m5(S u) {
+ super.m5(u);
+ }
+
+ @Override
+ void m4(List extends A> 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 extends A> 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 extends A> 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 {
+
+}