From 7494a395d9346da6261a0bc5ed8bbe5392303c6c Mon Sep 17 00:00:00 2001 From: Filip Krakowski Date: Fri, 1 Jun 2018 21:15:04 +0200 Subject: [PATCH 1/3] Add failing test demonstrating Comparator bug --- src/test/java/spoon/test/lambda/LambdaTest.java | 12 ++++++++++++ src/test/java/spoon/test/lambda/testclasses/Foo.java | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/src/test/java/spoon/test/lambda/LambdaTest.java b/src/test/java/spoon/test/lambda/LambdaTest.java index c8e90c8377e..b98979cb0e9 100644 --- a/src/test/java/spoon/test/lambda/LambdaTest.java +++ b/src/test/java/spoon/test/lambda/LambdaTest.java @@ -35,6 +35,7 @@ import spoon.testing.utils.ModelUtils; import java.io.File; +import java.util.Comparator; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; @@ -403,6 +404,17 @@ public void testLambdaFilter() throws Exception { assertHasStrings(methodNames, "m2", "m4", "m7", "m8"); } + @Test + public void testLambdaComparator() throws Exception { + CtInterface comparatorInterface = factory.Interface().get(Comparator.class); + List> comparators = foo.filterChildren(new LambdaFilter(comparatorInterface)).list(); + assertEquals(1, comparators.size()); + CtLambda comparator = comparators.get(0); + assertEquals(2, comparator.getParameters().size()); + CtMethod method = comparator.getOverriddenMethod(); + assertTrue(comparatorInterface.getMethods().contains(method)); + } + private void assertHasStrings(List methodNames, String... strs) { for (String str : strs) { assertTrue("List should contain "+str+" but it is missing.", methodNames.remove(str)); diff --git a/src/test/java/spoon/test/lambda/testclasses/Foo.java b/src/test/java/spoon/test/lambda/testclasses/Foo.java index 10d7e3578ab..148c4e05aa4 100644 --- a/src/test/java/spoon/test/lambda/testclasses/Foo.java +++ b/src/test/java/spoon/test/lambda/testclasses/Foo.java @@ -1,6 +1,7 @@ package spoon.test.lambda.testclasses; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; @@ -55,6 +56,10 @@ public void m9() { }; } + public void m10() { + sortPersonsWithComparator(persons, (p1, p2) -> p1.age - p2.age); + } + public static void printPersonsWithPredicate(List roster, Predicate tester) { for (Person p : roster) { if (tester.test(p)) { @@ -85,6 +90,10 @@ public static void printPersonsWithCheckPersons(List roster, CheckPerson } } + public static void sortPersonsWithComparator(List roster, Comparator comparator) { + roster.sort(comparator); + } + public class Person { public final int age; From 083bd5cd83293b1194a20d708724be883d1314ab Mon Sep 17 00:00:00 2001 From: Filip Krakowski Date: Fri, 1 Jun 2018 21:51:55 +0200 Subject: [PATCH 2/3] Fix counting java.lang.Object methods as abstract methods in interfaces --- .../spoon/reflect/factory/MethodFactory.java | 7 +++++-- .../support/reflect/code/CtLambdaImpl.java | 5 ++++- src/test/java/spoon/test/lambda/LambdaTest.java | 17 +++++++++-------- .../java/spoon/test/lambda/testclasses/Foo.java | 9 +-------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/spoon/reflect/factory/MethodFactory.java b/src/main/java/spoon/reflect/factory/MethodFactory.java index d7695519223..400fa7f4b1d 100644 --- a/src/main/java/spoon/reflect/factory/MethodFactory.java +++ b/src/main/java/spoon/reflect/factory/MethodFactory.java @@ -27,17 +27,20 @@ import spoon.template.Substitution; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.ArrayList; +import java.util.Arrays; /** * The {@link CtMethod} sub-factory. */ public class MethodFactory extends ExecutableFactory { + public final Set> OBJECT_METHODS = Collections.unmodifiableSet(factory.Class().get(Object.class).getMethods()); + /** * Creates a new method sub-factory. * diff --git a/src/main/java/spoon/support/reflect/code/CtLambdaImpl.java b/src/main/java/spoon/support/reflect/code/CtLambdaImpl.java index bbf0336aa35..9515ea8cdac 100644 --- a/src/main/java/spoon/support/reflect/code/CtLambdaImpl.java +++ b/src/main/java/spoon/support/reflect/code/CtLambdaImpl.java @@ -23,11 +23,11 @@ import spoon.reflect.code.CtExpression; import spoon.reflect.code.CtLambda; import spoon.reflect.code.CtStatement; -import spoon.reflect.declaration.CtExecutable; import spoon.reflect.declaration.CtMethod; import spoon.reflect.declaration.CtNamedElement; import spoon.reflect.declaration.CtParameter; import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtExecutable; import spoon.reflect.declaration.ModifierKind; import spoon.reflect.path.CtRole; import spoon.reflect.reference.CtExecutableReference; @@ -124,6 +124,9 @@ public CtMethod getOverriddenMethod() { lambdaExecutableMethod = lambdaTypeMethods.iterator().next(); } else { for (CtMethod method : lambdaTypeMethods) { + if (getFactory().Method().OBJECT_METHODS.stream().anyMatch(method::isOverriding)) { + continue; + } if (method.isDefaultMethod() || method.hasModifier(ModifierKind.PRIVATE) || method.hasModifier(ModifierKind.STATIC)) { continue; } diff --git a/src/test/java/spoon/test/lambda/LambdaTest.java b/src/test/java/spoon/test/lambda/LambdaTest.java index b98979cb0e9..5a2d1127fb9 100644 --- a/src/test/java/spoon/test/lambda/LambdaTest.java +++ b/src/test/java/spoon/test/lambda/LambdaTest.java @@ -405,14 +405,15 @@ public void testLambdaFilter() throws Exception { } @Test - public void testLambdaComparator() throws Exception { - CtInterface comparatorInterface = factory.Interface().get(Comparator.class); - List> comparators = foo.filterChildren(new LambdaFilter(comparatorInterface)).list(); - assertEquals(1, comparators.size()); - CtLambda comparator = comparators.get(0); - assertEquals(2, comparator.getParameters().size()); - CtMethod method = comparator.getOverriddenMethod(); - assertTrue(comparatorInterface.getMethods().contains(method)); + public void testInterfaceWithObjectMethods() throws Exception { + CtInterface checkPersons = factory.Interface().get(Foo.CheckPersons.class); + List> lambdas = foo.filterChildren(new LambdaFilter(checkPersons)).list(); + assertEquals(2, lambdas.size()); + CtLambda lambda = lambdas.get(0); + assertEquals(2, lambda.getParameters().size()); + CtMethod method = lambda.getOverriddenMethod(); + assertTrue(checkPersons.getMethods().contains(method)); + assertEquals("test", method.getSimpleName()); } private void assertHasStrings(List methodNames, String... strs) { diff --git a/src/test/java/spoon/test/lambda/testclasses/Foo.java b/src/test/java/spoon/test/lambda/testclasses/Foo.java index 148c4e05aa4..30efdfb0d40 100644 --- a/src/test/java/spoon/test/lambda/testclasses/Foo.java +++ b/src/test/java/spoon/test/lambda/testclasses/Foo.java @@ -56,10 +56,6 @@ public void m9() { }; } - public void m10() { - sortPersonsWithComparator(persons, (p1, p2) -> p1.age - p2.age); - } - public static void printPersonsWithPredicate(List roster, Predicate tester) { for (Person p : roster) { if (tester.test(p)) { @@ -90,10 +86,6 @@ public static void printPersonsWithCheckPersons(List roster, CheckPerson } } - public static void sortPersonsWithComparator(List roster, Comparator comparator) { - roster.sort(comparator); - } - public class Person { public final int age; @@ -119,5 +111,6 @@ public interface Check { public interface CheckPersons { boolean test(Person p1, Person p2); + boolean equals(Object other); } } \ No newline at end of file From e1472e5902d4e5d5e2bbaf62c1d4282bae57168a Mon Sep 17 00:00:00 2001 From: Filip Krakowski Date: Tue, 5 Jun 2018 14:04:10 +0200 Subject: [PATCH 3/3] Add contract comment to test method --- src/test/java/spoon/test/lambda/LambdaTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/spoon/test/lambda/LambdaTest.java b/src/test/java/spoon/test/lambda/LambdaTest.java index 5a2d1127fb9..5099746fe3d 100644 --- a/src/test/java/spoon/test/lambda/LambdaTest.java +++ b/src/test/java/spoon/test/lambda/LambdaTest.java @@ -10,7 +10,6 @@ import spoon.reflect.code.CtLambda; import spoon.reflect.code.CtTypeAccess; import spoon.reflect.declaration.CtClass; -import spoon.reflect.declaration.CtField; import spoon.reflect.declaration.CtInterface; import spoon.reflect.declaration.CtMethod; import spoon.reflect.declaration.CtParameter; @@ -35,7 +34,6 @@ import spoon.testing.utils.ModelUtils; import java.io.File; -import java.util.Comparator; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; @@ -406,6 +404,7 @@ public void testLambdaFilter() throws Exception { @Test public void testInterfaceWithObjectMethods() throws Exception { + // contract Lambda expression works on interfaces with methods inherited from java.lang.Object CtInterface checkPersons = factory.Interface().get(Foo.CheckPersons.class); List> lambdas = foo.filterChildren(new LambdaFilter(checkPersons)).list(); assertEquals(2, lambdas.size());