diff --git a/src/main/java/spoon/reflect/factory/ExecutableFactory.java b/src/main/java/spoon/reflect/factory/ExecutableFactory.java index 662c89f5940..0499eca0aae 100644 --- a/src/main/java/spoon/reflect/factory/ExecutableFactory.java +++ b/src/main/java/spoon/reflect/factory/ExecutableFactory.java @@ -118,7 +118,7 @@ private CtExecutableReference createReferenceInternal(CtExecutable e) return createReference(((CtMethod) e).getDeclaringType().getReference(), isStatic, ((CtMethod) e).getType().clone(), executableName, refs); } else if (e instanceof CtLambda) { CtMethod lambdaMethod = ((CtLambda) e).getOverriddenMethod(); - return createReference(e.getParent(CtType.class).getReference(), lambdaMethod == null ? null : lambdaMethod.getType(), executableName, refs); + return createReference(e.getParent(CtType.class).getReference(), lambdaMethod == null ? null : lambdaMethod.getType().clone(), executableName, refs); } else if (e instanceof CtAnonymousExecutable) { return createReference(((CtAnonymousExecutable) e).getDeclaringType().getReference(), e.getType().clone(), executableName); } diff --git a/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java b/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java index 01af41fe9a2..b93915f3a62 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java @@ -52,6 +52,7 @@ import spoon.support.compiler.SnippetCompilationHelper; import spoon.support.util.QualifiedNameBasedSortedSet; import spoon.support.util.SignatureBasedSortedSet; +import spoon.support.visitor.ClassTypingContext; import java.lang.annotation.Annotation; import java.util.ArrayList; @@ -895,14 +896,18 @@ public Collection> getAllExecutables() { @Override public Set> getAllMethods() { - final Set distinctSignatures = new HashSet<>(); - final Set> l = new SignatureBasedSortedSet<>(); + final Set> l = new HashSet<>(); + final ClassTypingContext ctc = new ClassTypingContext(this); map(new AllTypeMembersFunction(CtMethod.class)).forEach(new CtConsumer>() { @Override - public void accept(CtMethod method) { - if (distinctSignatures.add(method.getSignature())) { - l.add(method); + public void accept(CtMethod currentMethod) { + for (CtMethod alreadyVisitedMethod : l) { + if (ctc.isSameSignature(currentMethod, alreadyVisitedMethod)) { + return; + } } + + l.add(currentMethod); } }); return Collections.unmodifiableSet(l); diff --git a/src/main/java/spoon/support/visitor/ClassTypingContext.java b/src/main/java/spoon/support/visitor/ClassTypingContext.java index 4cec5502ef3..f1481517c30 100644 --- a/src/main/java/spoon/support/visitor/ClassTypingContext.java +++ b/src/main/java/spoon/support/visitor/ClassTypingContext.java @@ -423,6 +423,9 @@ private CtTypeReference getEnclosingType(CtTypeReference typeRef) { */ @Override protected CtTypeReference adaptTypeParameter(CtTypeParameter typeParam) { + if (typeParam == null) { + throw new SpoonException("You cannot adapt a null type parameter."); + } CtFormalTypeDeclarer declarer = typeParam.getTypeParameterDeclarer(); if ((declarer instanceof CtType) == false) { return null; @@ -643,6 +646,10 @@ private CtTypeReference adaptTypeForNewMethod(CtTypeReference typeRef) { if (typeRef instanceof CtTypeParameterReference) { CtTypeParameterReference typeParamRef = (CtTypeParameterReference) typeRef; CtTypeParameter typeParam = typeParamRef.getDeclaration(); + if (typeParam == null) { + throw new SpoonException("Declaration of the CtTypeParameter should not be null."); + } + if (typeParam.getTypeParameterDeclarer() instanceof CtExecutable) { //the parameter is declared in scope of Method or Constructor return typeRef.clone(); diff --git a/src/test/java/spoon/reflect/declaration/CtTypeInformationTest.java b/src/test/java/spoon/reflect/declaration/CtTypeInformationTest.java index 1627f87398a..9f22519c4f1 100644 --- a/src/test/java/spoon/reflect/declaration/CtTypeInformationTest.java +++ b/src/test/java/spoon/reflect/declaration/CtTypeInformationTest.java @@ -1,6 +1,8 @@ package spoon.reflect.declaration; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static spoon.testing.utils.ModelUtils.build; import java.lang.reflect.Field; @@ -135,13 +137,18 @@ public void testGetSuperclass() throws Exception { // + 48 of ArrayList (in library) // + 12 of java.lang.Object - Assert.assertEquals(1+12+48, extendObject.getAllMethods().size()); + // The final +1 is the result of the only usage of `ClassTypingContext#isSameSignature` in `getAllMethods` + // (see: https://github.com/INRIA/spoon/pull/1375) + // now it gets both `ArrayList#forEach` and `Iterable#forEach` + // this has been spotted as an issue in https://github.com/INRIA/spoon/issues/1407 + Assert.assertEquals(1+12+48+1, extendObject.getAllMethods().size()); final CtType subClass = this.factory.Type().get(Subclass.class); assertEquals(2, subClass.getMethods().size()); - // the abstract method from Comparable which is overridden is also present in the model - assertEquals(61+3, subClass.getAllMethods().size()); + // the abstract method from Comparable which is overridden should not be present in the model + // The +1 happens for the same reason as below + assertEquals(61+2+1, subClass.getAllMethods().size()); CtTypeReference superclass = subClass.getSuperclass(); Assert.assertEquals(ExtendsObject.class.getName(), superclass.getQualifiedName()); @@ -172,4 +179,22 @@ public void testGetSuperclass() throws Exception { type2.getMethodsByName("foo").get(0).getSignature()); } + + @Test + public void testGetAllMethodsWontReturnOverriddenMethod() { + final CtType subClass = this.factory.Type().get(Subclass.class); + Set> listCtMethods = subClass.getAllMethods(); + + boolean detectedCompareTo = false; + for (CtMethod ctMethod : listCtMethods) { + if (ctMethod.getSimpleName().equals("compareTo")) { + assertFalse(ctMethod.hasModifier(ModifierKind.ABSTRACT)); + assertFalse(ctMethod.getParameters().get(0).getType() instanceof CtTypeParameter); + assertEquals("Object", ctMethod.getParameters().get(0).getType().getSimpleName()); + detectedCompareTo = true; + } + } + + assertTrue(detectedCompareTo); + } } \ No newline at end of file