From d0b1dd8f20cc248ed309caf90f9caf24a64da69e Mon Sep 17 00:00:00 2001 From: Simon Urli Date: Wed, 7 Jun 2017 14:25:04 +0200 Subject: [PATCH 1/2] Show issue #1371 --- .../compiler/jdt/ReferenceBuilder.java | 1 + .../spoon/test/generics/GenericsTest.java | 28 +++++++++++ .../testclasses/rxjava/BehaviorSubject.java | 25 ++++++++++ .../testclasses/rxjava/Observable.java | 13 +++++ .../testclasses/rxjava/Processor.java | 7 +++ .../testclasses/rxjava/Publisher.java | 8 +++ .../testclasses/rxjava/PublisherRedo.java | 50 +++++++++++++++++++ .../generics/testclasses/rxjava/Subject.java | 7 +++ .../testclasses/rxjava/Subscriber.java | 12 +++++ .../rxjava/ToNotificationSubscriber.java | 30 +++++++++++ .../test/generics/testclasses/rxjava/Try.java | 8 +++ 11 files changed, 189 insertions(+) create mode 100644 src/test/java/spoon/test/generics/testclasses/rxjava/BehaviorSubject.java create mode 100644 src/test/java/spoon/test/generics/testclasses/rxjava/Observable.java create mode 100644 src/test/java/spoon/test/generics/testclasses/rxjava/Processor.java create mode 100644 src/test/java/spoon/test/generics/testclasses/rxjava/Publisher.java create mode 100644 src/test/java/spoon/test/generics/testclasses/rxjava/PublisherRedo.java create mode 100644 src/test/java/spoon/test/generics/testclasses/rxjava/Subject.java create mode 100644 src/test/java/spoon/test/generics/testclasses/rxjava/Subscriber.java create mode 100644 src/test/java/spoon/test/generics/testclasses/rxjava/ToNotificationSubscriber.java create mode 100644 src/test/java/spoon/test/generics/testclasses/rxjava/Try.java diff --git a/src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java b/src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java index b842daa08b1..d33a23563ac 100644 --- a/src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java +++ b/src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java @@ -838,6 +838,7 @@ CtTypeReference getTypeReference(TypeBinding binding) { } bindingCache.remove(binding); this.exploringParameterizedBindings.remove(binding); + //this.exploringParameterizedBindings.clear(); return (CtTypeReference) ref; } diff --git a/src/test/java/spoon/test/generics/GenericsTest.java b/src/test/java/spoon/test/generics/GenericsTest.java index 71c976d2d5d..9bf3b979fe9 100644 --- a/src/test/java/spoon/test/generics/GenericsTest.java +++ b/src/test/java/spoon/test/generics/GenericsTest.java @@ -1006,6 +1006,34 @@ public void testWildCardonShadowClass() throws Exception { factory = launcher.getFactory(); CtInterface fakeTplItf2 = factory.Interface().get(FakeTpl.class); checkFakeTpl(fakeTplItf2); + } + + @Test + public void testDiamondComplexGenericsRxJava() { + Launcher launcher = new Launcher(); + launcher.addInputResource("./src/test/java/spoon/test/generics/testclasses/rxjava/"); + launcher.setSourceOutputDirectory("./target/spooned-rxjava"); + launcher.run(); + + Factory factory = launcher.getFactory(); + + List invocations = factory.getModel().getElements(new TypeFilter<>(CtConstructorCall.class)); + + boolean invocationDetected = false; + for (CtConstructorCall call : invocations) { + if (call.getType().getSimpleName().equals("ToNotificationSubscriber")) { + assertEquals(1, call.getType().getActualTypeArguments().size()); + + CtTypeReference actualTA = call.getType().getActualTypeArguments().get(0); + assertTrue(actualTA instanceof CtWildcardReference); + assertEquals("?", actualTA.getSimpleName()); + assertTrue( ((CtWildcardReference)actualTA).getBoundingType() == null ); + invocationDetected = true; + } + } + + canBeBuilt("./target/spooned-rxjava",8); + assertTrue(invocationDetected); } } diff --git a/src/test/java/spoon/test/generics/testclasses/rxjava/BehaviorSubject.java b/src/test/java/spoon/test/generics/testclasses/rxjava/BehaviorSubject.java new file mode 100644 index 00000000000..0d9aef2b14d --- /dev/null +++ b/src/test/java/spoon/test/generics/testclasses/rxjava/BehaviorSubject.java @@ -0,0 +1,25 @@ +package spoon.test.generics.testclasses.rxjava; + +/** + * Created by urli on 07/06/2017. + */ +public final class BehaviorSubject extends Subject { + public static BehaviorSubject create() { + return new BehaviorSubject<>(); + } + + @Override + public void onNext(T var1) { + + } + + @Override + public void onError(Throwable var1) { + + } + + @Override + public void onComplete() { + + } +} diff --git a/src/test/java/spoon/test/generics/testclasses/rxjava/Observable.java b/src/test/java/spoon/test/generics/testclasses/rxjava/Observable.java new file mode 100644 index 00000000000..b3a67ff3e9e --- /dev/null +++ b/src/test/java/spoon/test/generics/testclasses/rxjava/Observable.java @@ -0,0 +1,13 @@ +package spoon.test.generics.testclasses.rxjava; + +import java.util.Objects; + +/** + * Created by urli on 07/06/2017. + */ +public class Observable implements Publisher { + + public final void subscribe(Subscriber s) { + Objects.requireNonNull(s); + } +} diff --git a/src/test/java/spoon/test/generics/testclasses/rxjava/Processor.java b/src/test/java/spoon/test/generics/testclasses/rxjava/Processor.java new file mode 100644 index 00000000000..9d2ba9365bf --- /dev/null +++ b/src/test/java/spoon/test/generics/testclasses/rxjava/Processor.java @@ -0,0 +1,7 @@ +package spoon.test.generics.testclasses.rxjava; + +/** + * Created by urli on 07/06/2017. + */ +public interface Processor extends Subscriber, Publisher { +} diff --git a/src/test/java/spoon/test/generics/testclasses/rxjava/Publisher.java b/src/test/java/spoon/test/generics/testclasses/rxjava/Publisher.java new file mode 100644 index 00000000000..d33887b6120 --- /dev/null +++ b/src/test/java/spoon/test/generics/testclasses/rxjava/Publisher.java @@ -0,0 +1,8 @@ +package spoon.test.generics.testclasses.rxjava; + +/** + * Created by urli on 07/06/2017. + */ +public interface Publisher { + void subscribe(Subscriber var1); +} diff --git a/src/test/java/spoon/test/generics/testclasses/rxjava/PublisherRedo.java b/src/test/java/spoon/test/generics/testclasses/rxjava/PublisherRedo.java new file mode 100644 index 00000000000..a8f51131cba --- /dev/null +++ b/src/test/java/spoon/test/generics/testclasses/rxjava/PublisherRedo.java @@ -0,0 +1,50 @@ +package spoon.test.generics.testclasses.rxjava; + +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +/** + * Created by urli on 07/06/2017. + */ +public final class PublisherRedo implements Publisher { + final Function>>, ? extends Publisher> manager; + + public PublisherRedo(Function>>, ? extends Publisher> manager) { + this.manager = manager; + } + + public void subscribe(Subscriber s) { + + BehaviorSubject>> subject = BehaviorSubject.create(); + RedoSubscriber parent = new RedoSubscriber<>(); + Publisher action = manager.apply(subject); + + action.subscribe(new ToNotificationSubscriber<>(parent::handle)); + } + + private void subscribe(ToNotificationSubscriber truc) { + + } + + static final class RedoSubscriber extends AtomicBoolean implements Subscriber { + void handle(Try> notification) { + + } + + @Override + public void onNext(T var1) { + + } + + @Override + public void onError(Throwable var1) { + + } + + @Override + public void onComplete() { + + } + } +} diff --git a/src/test/java/spoon/test/generics/testclasses/rxjava/Subject.java b/src/test/java/spoon/test/generics/testclasses/rxjava/Subject.java new file mode 100644 index 00000000000..bb58b64d260 --- /dev/null +++ b/src/test/java/spoon/test/generics/testclasses/rxjava/Subject.java @@ -0,0 +1,7 @@ +package spoon.test.generics.testclasses.rxjava; + +/** + * Created by urli on 07/06/2017. + */ +public abstract class Subject extends Observable implements Processor { +} diff --git a/src/test/java/spoon/test/generics/testclasses/rxjava/Subscriber.java b/src/test/java/spoon/test/generics/testclasses/rxjava/Subscriber.java new file mode 100644 index 00000000000..cc4e91ad981 --- /dev/null +++ b/src/test/java/spoon/test/generics/testclasses/rxjava/Subscriber.java @@ -0,0 +1,12 @@ +package spoon.test.generics.testclasses.rxjava; + +/** + * Created by urli on 07/06/2017. + */ +public interface Subscriber { + void onNext(T var1); + + void onError(Throwable var1); + + void onComplete(); +} diff --git a/src/test/java/spoon/test/generics/testclasses/rxjava/ToNotificationSubscriber.java b/src/test/java/spoon/test/generics/testclasses/rxjava/ToNotificationSubscriber.java new file mode 100644 index 00000000000..a76b6cc3428 --- /dev/null +++ b/src/test/java/spoon/test/generics/testclasses/rxjava/ToNotificationSubscriber.java @@ -0,0 +1,30 @@ +package spoon.test.generics.testclasses.rxjava; + +import java.util.Optional; +import java.util.function.Consumer; + +/** + * Created by urli on 07/06/2017. + */ +public final class ToNotificationSubscriber implements Subscriber { + final Consumer>> consumer; + + public ToNotificationSubscriber(Consumer>> consumer) { + this.consumer = consumer; + } + + @Override + public void onNext(T var1) { + + } + + @Override + public void onError(Throwable var1) { + + } + + @Override + public void onComplete() { + + } +} diff --git a/src/test/java/spoon/test/generics/testclasses/rxjava/Try.java b/src/test/java/spoon/test/generics/testclasses/rxjava/Try.java new file mode 100644 index 00000000000..68d10ad263c --- /dev/null +++ b/src/test/java/spoon/test/generics/testclasses/rxjava/Try.java @@ -0,0 +1,8 @@ +package spoon.test.generics.testclasses.rxjava; + + +/** + * Created by urli on 07/06/2017. + */ +public final class Try { +} From b9347ee456fb9e6e5d9d86f69a14dc732d8517b8 Mon Sep 17 00:00:00 2001 From: Simon Urli Date: Wed, 7 Jun 2017 14:49:58 +0200 Subject: [PATCH 2/2] Propose a fix by considering a map of already resolved type parameters instead of a set --- .../support/compiler/jdt/ReferenceBuilder.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java b/src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java index d33a23563ac..3e81dbc25db 100644 --- a/src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java +++ b/src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java @@ -86,10 +86,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -102,7 +100,7 @@ public class ReferenceBuilder { // Allow to detect circular references and to avoid endless recursivity // when resolving parameterizedTypes (e.g. Enum>) - private Set exploringParameterizedBindings = new HashSet<>(); + private Map exploringParameterizedBindings = new HashMap<>(); private Map> basestypes = new TreeMap<>(); private boolean bounds = false; @@ -654,11 +652,16 @@ CtTypeReference getTypeReference(TypeBinding binding) { if (bindingCache.containsKey(b)) { ref.addActualTypeArgument(getCtCircularTypeReference(b)); } else { - if (!this.exploringParameterizedBindings.contains(b)) { - this.exploringParameterizedBindings.add(b); - ref.addActualTypeArgument(getTypeReference(b)); + if (!this.exploringParameterizedBindings.containsKey(b)) { + this.exploringParameterizedBindings.put(b, null); + CtTypeReference typeRefB = getTypeReference(b); + this.exploringParameterizedBindings.put(b, typeRefB); + ref.addActualTypeArgument(typeRefB); } else { - this.exploringParameterizedBindings.remove(b); + CtTypeReference typeRefB = this.exploringParameterizedBindings.get(b); + if (typeRefB != null) { + ref.addActualTypeArgument(typeRefB.clone()); + } } } } @@ -838,7 +841,6 @@ CtTypeReference getTypeReference(TypeBinding binding) { } bindingCache.remove(binding); this.exploringParameterizedBindings.remove(binding); - //this.exploringParameterizedBindings.clear(); return (CtTypeReference) ref; }