Skip to content

Commit

Permalink
feature: CtMethod#isOverriding(CtMethod)
Browse files Browse the repository at this point in the history
  • Loading branch information
pvojtechovsky committed Mar 14, 2017
1 parent 29a7880 commit ed17f5e
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 6 deletions.
6 changes: 6 additions & 0 deletions src/main/java/spoon/reflect/declaration/CtMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ public interface CtMethod<T> extends CtExecutable<T>, 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
18 changes: 18 additions & 0 deletions src/main/java/spoon/support/reflect/declaration/CtMethodImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/test/java/spoon/test/filters/FilterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<?>, CtMethod<?>, Boolean> isOverriding) {
Factory factory = ModelUtils.build(new File("src/test/java/spoon/test/method_overriding/testclasses").listFiles());
Map<String, List<CtMethod>> methodsByName = new HashMap<>();
factory.getModel().getRootPackage().filterChildren(new TypeFilter<>(CtMethod.class)).forEach((CtMethod m)->{
List<CtMethod> methods = methodsByName.get(m.getSimpleName());
if(methods==null) {
methods = new ArrayList<>();
methodsByName.put(m.getSimpleName(), methods);
}
methods.add(m);
});
for (Map.Entry<String, List<CtMethod>> e : methodsByName.entrySet()) {
combine(e.getValue(), 0, isOverriding);
}
}

private void combine(List<CtMethod> value, int start, BiFunction<CtMethod<?>, CtMethod<?>, Boolean> isOverriding) {
CtMethod m1 = value.get(start);
if(start+1<value.size()) {
for (CtMethod m2 : value.subList(start+1, value.size())) {
if(m1.getDeclaringType().isSubtypeOf(m2.getDeclaringType().getReference())) {
checkOverride(m1, m2, isOverriding);
} else if(m2.getDeclaringType().isSubtypeOf(m1.getDeclaringType().getReference())) {
checkOverride(m2, m1, isOverriding);
} else {
checkNotOverride(m1, m2, isOverriding);
}
}
combine(value, start+1, isOverriding);
}
}

private void checkOverride(CtMethod m1, CtMethod m2, BiFunction<CtMethod<?>, 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<?>, 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();
}
}
24 changes: 24 additions & 0 deletions src/test/java/spoon/test/method_overriding/testclasses/A.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package spoon.test.method_overriding.testclasses;

import java.util.List;

public class A<U> {

public A() {
}

A<U> m1(C c){
return null;
}

<T extends A<U>> T m2(C c){
return null;
}

void m3(List<? super C> c){
}
void m4(List<? extends A<U>> c){
}
void m5(U u) {
}
}
32 changes: 32 additions & 0 deletions src/test/java/spoon/test/method_overriding/testclasses/B.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package spoon.test.method_overriding.testclasses;

import java.util.List;

public class B<S, R extends S> extends A<S> {

public B() {
}

@Override
B<S, R> m1(C c){
return null;
}

@Override
<T extends A<S>> 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<S>> c) {
}
}
30 changes: 30 additions & 0 deletions src/test/java/spoon/test/method_overriding/testclasses/C.java
Original file line number Diff line number Diff line change
@@ -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<InputStream, FilterInputStream> {

public C() {
}

@Override
B m1(C c){
return null;
}

@Override
B<InputStream, FilterInputStream> m2(C c){
return null;
}
@Override
void m4(List<? extends A<InputStream>> c){
}

@Override
void m5(InputStream u) {
super.m5(u);
}

}
24 changes: 24 additions & 0 deletions src/test/java/spoon/test/method_overriding/testclasses/D.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package spoon.test.method_overriding.testclasses;

import java.util.List;

public class D extends B<Integer, Integer> {

public D() {
}

@Override
B<Integer, Integer> m1(C c){
return null;
}

@Override
D m2(C c){
return null;
}

@Override
void m4(List<? extends A<Integer>> c){
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package spoon.test.method_overriding.testclasses;

public interface IA {

}

0 comments on commit ed17f5e

Please sign in to comment.