diff --git a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/handler/DelegateHandler.java b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/handler/DelegateHandler.java index 4451fe209e4f..5167d339f2dd 100644 --- a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/handler/DelegateHandler.java +++ b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/handler/DelegateHandler.java @@ -167,7 +167,7 @@ public final class DelegateHandler { final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(psiType); final PsiClass psiClass = resolveResult.getElement(); if (null != psiClass) { - final PsiSubstitutor psiClassSubstitutor = resolveResult.getSubstitutor(); + final PsiSubstitutor psiClassSubstitutor = addAllInterfaceSuperSubstitutors(psiClass, resolveResult.getSubstitutor()); for (Pair pair : psiClass.getAllMethodsAndTheirSubstitutors()) { final PsiMethod psiMethod = pair.getFirst(); @@ -181,6 +181,14 @@ public final class DelegateHandler { } } + private static PsiSubstitutor addAllInterfaceSuperSubstitutors(PsiClass psiClass, PsiSubstitutor psiSubstitutor) { + for (PsiClass interfaceClass : psiClass.getInterfaces()) { + PsiSubstitutor classSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(interfaceClass, psiClass, psiSubstitutor); + psiSubstitutor = addAllInterfaceSuperSubstitutors(interfaceClass, psiSubstitutor.putAll(classSubstitutor)); + } + return psiSubstitutor; + } + private static void collectAllOwnMethods(@NotNull PsiExtensibleClass psiStartClass, Collection> results) { PsiExtensibleClass psiClass = psiStartClass; do { diff --git a/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/processor/DelegateTest.java b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/processor/DelegateTest.java index 1e84ae34d165..c9cc52ac2347 100644 --- a/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/processor/DelegateTest.java +++ b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/processor/DelegateTest.java @@ -56,4 +56,7 @@ public class DelegateTest extends AbstractLombokParsingTestCase { public void testDelegate$DelegateGenericInterfaceIssue88() { doTest(true); } + public void testDelegate$DelegateWithInterfaces() { + doTest(true); + } } diff --git a/plugins/lombok/testData/after/delegate/DelegateWithInterfaces.java b/plugins/lombok/testData/after/delegate/DelegateWithInterfaces.java new file mode 100644 index 000000000000..230d1d63ed5d --- /dev/null +++ b/plugins/lombok/testData/after/delegate/DelegateWithInterfaces.java @@ -0,0 +1,143 @@ +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class ItemsList implements List { + private final List items; + private final String additionalData; + + ItemsList(List items, String additionalData) { + this.items = items; + this.additionalData = additionalData; + } + + public int size() { + return this.items.size(); + } + + public boolean isEmpty() { + return this.items.isEmpty(); + } + + public boolean contains(Object o) { + return this.items.contains(o); + } + + public Iterator iterator() { + return this.items.iterator(); + } + + public Object[] toArray() { + return this.items.toArray(); + } + + public T[] toArray(T[] ts) { + return this.items.toArray(ts); + } + + public boolean add(T e) { + return this.items.add(e); + } + + public boolean remove(Object o) { + return this.items.remove(o); + } + + public boolean containsAll(Collection collection) { + return this.items.containsAll(collection); + } + + public boolean addAll(Collection collection) { + return this.items.addAll(collection); + } + + public boolean addAll(int i, Collection collection) { + return this.items.addAll(i, collection); + } + + public boolean removeAll(Collection collection) { + return this.items.removeAll(collection); + } + + public boolean retainAll(Collection collection) { + return this.items.retainAll(collection); + } + + public void replaceAll(UnaryOperator unaryOperator) { + this.items.replaceAll(unaryOperator); + } + + public void sort(Comparator comparator) { + this.items.sort(comparator); + } + + public void clear() { + this.items.clear(); + } + + public T get(int i) { + return this.items.get(i); + } + + public T set(int i, T e) { + return this.items.set(i, e); + } + + public void add(int i, T e) { + this.items.add(i, e); + } + + public T remove(int i) { + return this.items.remove(i); + } + + public int indexOf(Object o) { + return this.items.indexOf(o); + } + + public int lastIndexOf(Object o) { + return this.items.lastIndexOf(o); + } + + public ListIterator listIterator() { + return this.items.listIterator(); + } + + public ListIterator listIterator(int i) { + return this.items.listIterator(i); + } + + public List subList(int i, int i1) { + return this.items.subList(i, i1); + } + + public Spliterator spliterator() { + return this.items.spliterator(); + } + + public boolean removeIf(Predicate predicate) { + return this.items.removeIf(predicate); + } + + public Stream stream() { + return this.items.stream(); + } + + public Stream parallelStream() { + return this.items.parallelStream(); + } + + public void forEach(Consumer consumer) { + this.items.forEach(consumer); + } +} + +public class DelegateWithInterfaces { + public List test() { + var list = new ItemsList(Arrays.asList("S1", "S2"), "data"); + return list.stream().map(String::toLowerCase).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/before/delegate/DelegateWithInterfaces.java b/plugins/lombok/testData/before/delegate/DelegateWithInterfaces.java new file mode 100644 index 000000000000..6140a1cb573d --- /dev/null +++ b/plugins/lombok/testData/before/delegate/DelegateWithInterfaces.java @@ -0,0 +1,25 @@ +import lombok.experimental.Delegate; + +import lombok.experimental.Delegate; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +class ItemsList implements List { + @Delegate + private final List items; + private final String additionalData; + + ItemsList(List items, String additionalData) { + this.items = items; + this.additionalData = additionalData; + } +} + +public class DelegateWithInterfaces { + public List test() { + var list = new ItemsList(Arrays.asList("S1", "S2"), "data"); + return list.stream().map(String::toLowerCase).collect(Collectors.toList()); + } +} \ No newline at end of file