Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix inconsistencies between interface contract and double implementations of getAllExecutables #1019

Merged
merged 1 commit into from
Dec 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,16 @@ public interface CtTypeInformation {
Collection<CtExecutableReference<?>> getDeclaredExecutables();

/**
* Gets the executables declared by this type and by all its supertypes if
* Gets the executables declared by this type and by all its supertypes (static/instance methods, constructors, anonymous static blocks) if
* applicable. This method returns:
*
* <ul>
* <li>static, instance and default executables</li>
* <li>Overridden methods</li>
* <li>static, instance and default methods</li>
* <li>constructors</li>
* </ul>
*
* If a method is overridden twice in the hierarchy, it counts for two different elements.
* If a method is declared in an interface in the hierarchy and implemented in the current type or in a super type, it counts for two (or n different elements).
* The method can be abstract.
*/
@DerivedProperty
Collection<CtExecutableReference<?>> getAllExecutables();
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/spoon/support/comparator/SignatureComparator.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@
*/
package spoon.support.comparator;

import spoon.reflect.declaration.CtElement;
import spoon.support.visitor.SignaturePrinter;

import java.io.Serializable;
import java.util.Comparator;

import spoon.reflect.declaration.CtExecutable;
import spoon.support.visitor.SignaturePrinter;

/**
* Compares executable based on a signature
* Compares executables (method, executable-references) based on a signature.
*/
public class SignatureComparator implements Comparator<CtExecutable<?>>, Serializable {
public class SignatureComparator implements Comparator<CtElement>, Serializable {

private static final long serialVersionUID = 1L;

@Override
public int compare(CtExecutable<?> o1, CtExecutable<?> o2) {
public int compare(CtElement o1, CtElement o2) {
SignaturePrinter signaturePrinter1 = new SignaturePrinter();
SignaturePrinter signaturePrinter2 = new SignaturePrinter();
signaturePrinter1.scan(o1);
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/spoon/support/reflect/declaration/CtClassImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,17 @@ public Class<?> loadClass(String s) throws ClassNotFoundException {
}
}
}

/** adding the constructors and static executables */
@Override
public Collection<CtExecutableReference<?>> getAllExecutables() {
Set<CtExecutableReference<?>> l = (Set<CtExecutableReference<?>>) super.getAllExecutables();
for (CtConstructor c : getConstructors()) {
l.add(c.getReference());
}
for (CtExecutable<?> anon : getAnonymousExecutables()) {
l.add(anon.getReference());
}
return l;
}
}
18 changes: 8 additions & 10 deletions src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@
import spoon.reflect.visitor.EarlyTerminatingScanner;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.ReferenceTypeFilter;
import spoon.support.compiler.SnippetCompilationHelper;
import spoon.support.SpoonClassNotFoundException;
import spoon.support.comparator.SignatureComparator;
import spoon.support.compiler.SnippetCompilationHelper;
import spoon.support.util.QualifiedNameBasedSortedSet;
import spoon.support.util.SignatureBasedSortedSet;

Expand All @@ -55,9 +56,9 @@
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import static spoon.reflect.ModelElementContainerDefaultCapacities.TYPE_TYPE_PARAMETERS_CONTAINER_DEFAULT_CAPACITY;

Expand Down Expand Up @@ -881,12 +882,9 @@ public Collection<CtExecutableReference<?>> getDeclaredExecutables() {

@Override
public Collection<CtExecutableReference<?>> getAllExecutables() {
Set<CtExecutableReference<?>> l = new HashSet<>(getDeclaredExecutables());
if (this instanceof CtClass) {
CtTypeReference<?> st = ((CtClass<?>) this).getSuperclass();
if (st != null) {
l.addAll(st.getAllExecutables());
}
Set<CtExecutableReference<?>> l = new TreeSet(new SignatureComparator());
for (CtMethod<?> m : getAllMethods()) {
l.add((CtExecutableReference<?>) m.getReference());
}
return l;
}
Expand Down Expand Up @@ -917,8 +915,8 @@ public Set<CtMethod<?>> getAllMethods() {
} catch (SpoonClassNotFoundException ignored) {
// should not be thrown in 'noClasspath' environment (#775)
}
} else {
// this is object
} else if (this instanceof CtClass) {
// only CtCLasses extend object
addAllBasedOnSignature(getFactory().Type().get(Object.class).getMethods(), l);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import spoon.support.util.RtHelper;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
Expand Down Expand Up @@ -486,22 +485,9 @@ public Collection<CtFieldReference<?>> getAllFields() {
@Override
public Collection<CtExecutableReference<?>> getAllExecutables() {
Collection<CtExecutableReference<?>> l = new ArrayList<>();
CtType<T> t = getDeclaration();
if (t == null) {
Class<?> c = getActualClass();
for (Method m : c.getDeclaredMethods()) {
l.add(getFactory().Method().createReference(m));
}
for (Constructor<?> cons : c.getDeclaredConstructors()) {
CtExecutableReference<?> consRef = getFactory().Constructor().createReference(cons);
l.add(consRef);
}
Class<?> sc = c.getSuperclass();
if (sc != null) {
l.addAll(getFactory().Type().createReference(sc).getAllExecutables());
}
} else {
return t.getAllExecutables();
CtType<T> t = getTypeDeclaration();
if (t != null) {
l.addAll(t.getAllExecutables());
}
return l;
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/spoon/support/visitor/SignaturePrinter.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
import spoon.reflect.reference.CtIntersectionTypeReference;
import spoon.reflect.reference.CtTypeParameterReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.CtInheritanceScanner;
import spoon.reflect.visitor.CtScanner;

/**
* Responsible for computing signatures for elements where a signature exists
* (CtType, CtMethod and CtPackage). Otherwise returns the empty string.
*
*/
public class SignaturePrinter extends CtInheritanceScanner {
public class SignaturePrinter extends CtScanner {

private final StringBuffer signature = new StringBuffer();

Expand Down
8 changes: 4 additions & 4 deletions src/test/java/spoon/test/interfaces/InterfaceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void testExtendsDefaultMethodInSubInterface() throws Exception {
final CtInterface<?> ctInterface = (CtInterface<?>) factory.Type().get(ExtendsDefaultMethodInterface.class);

assertEquals("Sub interface must have only one method in its interface", 1, ctInterface.getMethods().size());
assertEquals("Sub interface must have 6+12(from java.lang.Object) methods in its interface and its super interfaces", 18, ctInterface.getAllMethods().size());
assertEquals("Sub interface must have 6 methods in its interface and its super interfaces", 6, ctInterface.getAllMethods().size());

final CtMethod<?> getZonedDateTimeMethod = ctInterface.getMethodsByName("getZonedDateTime").get(0);
assertTrue("Method in the sub interface must be a default method", getZonedDateTimeMethod.isDefaultMethod());
Expand All @@ -70,7 +70,7 @@ public void testRedefinesDefaultMethodInSubInterface() throws Exception {
final CtInterface<?> ctInterface = (CtInterface<?>) factory.Type().get(RedefinesDefaultMethodInterface.class);

assertEquals("Sub interface must have only one method in its interface", 1, ctInterface.getMethods().size());
assertEquals("Sub interface must have 6+12(from java.lang.Object) methods in its interface and its super interfaces", 18, ctInterface.getAllMethods().size());
assertEquals("Sub interface must have 6 methods in its interface and its super interfaces", 6, ctInterface.getAllMethods().size());

final CtMethod<?> getZonedDateTimeMethod = ctInterface.getMethodsByName("getZonedDateTime").get(0);
assertFalse("Method in the sub interface mustn't be a default method", getZonedDateTimeMethod.isDefaultMethod());
Expand All @@ -82,7 +82,7 @@ public void testExtendsStaticMethodInSubInterface() throws Exception {
final CtInterface<?> ctInterface = (CtInterface<?>) factory.Type().get(ExtendsStaticMethodInterface.class);

assertEquals("Sub interface must have only one method in its interface", 1, ctInterface.getMethods().size());
assertEquals("Sub interface must have 6+12(from java.lang.Object) methods in its interface and its super interfaces", 18, ctInterface.getAllMethods().size());
assertEquals("Sub interface must have 6 methods in its interface and its super interfaces", 6, ctInterface.getAllMethods().size());

final CtMethod<?> getZoneIdMethod = ctInterface.getMethodsByName("getZoneId").get(0);
assertTrue("Method in the sub interface must be a static method", getZoneIdMethod.getModifiers().contains(ModifierKind.STATIC));
Expand All @@ -94,7 +94,7 @@ public void testRedefinesStaticMethodInSubInterface() throws Exception {
final CtInterface<?> ctInterface = (CtInterface<?>) factory.Type().get(RedefinesStaticMethodInterface.class);

assertEquals("Sub interface must have only one method in its interface", 1, ctInterface.getMethods().size());
assertEquals("Sub interface must have 6+12(from java.lang.Object) methods in its interface and its super interfaces", 18, ctInterface.getAllMethods().size());
assertEquals("Sub interface must have 6+12(from java.lang.Object) methods in its interface and its super interfaces", 6, ctInterface.getAllMethods().size());

final CtMethod<?> getZoneIdMethod = ctInterface.getMethodsByName("getZoneId").get(0);
assertFalse("Method in the sub interface mustn't be a static method", getZoneIdMethod.getModifiers().contains(ModifierKind.STATIC));
Expand Down
10 changes: 6 additions & 4 deletions src/test/java/spoon/test/model/TypeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,18 @@ public class TypeTest {

@Test
public void testGetAllExecutables() throws Exception {
CtType<?> type = build("spoon.test.model", "Foo");
CtClass<?> type = build("spoon.test.model", "Foo");
assertEquals(1, type.getDeclaredFields().size());
assertEquals(3, type.getMethods().size());
assertEquals(4, type.getDeclaredExecutables().size());
assertEquals(2, type.getAllFields().size());
assertEquals(1, type.getConstructors().size());
assertEquals(16, type.getAllMethods().size());
assertEquals(12, type.getFactory().Type().get(Object.class).getAllMethods().size());

// we have 4 methods + one explicit constructor + 3 implicit
// constructors for Bar, Baz and Baz.Inner
// we have 3 methods in Foo + 2 in Baz - 1 common in Foo.bar (m) + 12 in Object + 1 explicit constructor in Foo
Collection<CtExecutableReference<?>> allExecutables = type.getAllExecutables();
assertEquals(8, allExecutables.size());
assertEquals(17, allExecutables.size());
}

@Test
Expand Down
10 changes: 4 additions & 6 deletions src/test/java/spoon/test/reference/ExecutableReferenceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,16 @@ public void testSpecifyGetAllExecutablesMethod() throws Exception {

final CtInterface<spoon.test.reference.testclasses.Foo> foo = launcher.getFactory().Interface().get(spoon.test.reference.testclasses.Foo.class);
final List<CtExecutableReference<?>> fooExecutables = foo.getAllExecutables().stream().collect(Collectors.toList());
assertEquals(2, fooExecutables.size());
assertEquals(foo.getMethod("m").getReference(), fooExecutables.get(0));
assertEquals(launcher.getFactory().Interface().get(SuperFoo.class).getMethod("m").getReference(), fooExecutables.get(1));
assertEquals(1, fooExecutables.size());
assertEquals(foo.getSuperInterfaces().stream().findFirst().get().getTypeDeclaration().getMethod("m").getReference(), launcher.getFactory().Interface().get(SuperFoo.class).getMethod("m").getReference());

final CtClass<Bar> bar = launcher.getFactory().Class().get(Bar.class);
final List<CtExecutableReference<?>> barExecutables = bar.getAllExecutables().stream().collect(Collectors.toList());
assertEquals(1, barExecutables.size());
assertEquals(bar.getConstructors().stream().collect(Collectors.toList()).get(0).getReference(), barExecutables.get(0));
assertEquals(12 /* object */ + 1 /* constructor */, barExecutables.size());

final CtInterface<Kuu> kuu = launcher.getFactory().Interface().get(Kuu.class);
final List<CtExecutableReference<?>> kuuExecutables = kuu.getAllExecutables().stream().collect(Collectors.toList());
assertEquals(1, kuuExecutables.size());
assertEquals(1 /* default method in interface */, kuuExecutables.size());
assertEquals(kuu.getMethod("m").getReference(), kuuExecutables.get(0));
}

Expand Down