Desugared lib: Fix getGenericTypes
Bug: 160909126
Change-Id: Id9a3a4425b1c4ad224d36198b66e93aff2d8b4ed
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 423acef..0a5014a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -230,8 +230,8 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems,
- DexMethod method, int instructionOffset) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems, DexMethod method, int instructionOffset) {
if (indexedItems.addClass(this)) {
type.collectIndexedItems(indexedItems, method, instructionOffset);
if (superType != null) {
@@ -260,8 +260,8 @@
}
}
- private static <T extends DexItem> void synchronizedCollectAll(IndexedItemCollection collection,
- T[] items) {
+ private static <T extends DexItem> void synchronizedCollectAll(
+ IndexedItemCollection collection, T[] items) {
synchronized (items) {
collectAll(collection, items);
}
@@ -447,6 +447,50 @@
methodCollection.addDirectMethod(directMethod);
}
+ public void addExtraInterfaces(List<DexType> extraInterfaces, DexItemFactory factory) {
+ if (extraInterfaces.isEmpty()) {
+ return;
+ }
+ addExtraInterfacesToInterfacesArray(extraInterfaces);
+ addExtraInterfacesToSignatureAnnotationIfPresent(extraInterfaces, factory);
+ }
+
+ private void addExtraInterfacesToInterfacesArray(List<DexType> extraInterfaces) {
+ DexType[] newInterfaces =
+ Arrays.copyOf(interfaces.values, interfaces.size() + extraInterfaces.size());
+ for (int i = interfaces.size(); i < newInterfaces.length; i++) {
+ newInterfaces[i] = extraInterfaces.get(i - interfaces.size());
+ }
+ interfaces = new DexTypeList(newInterfaces);
+ }
+
+ private void addExtraInterfacesToSignatureAnnotationIfPresent(
+ List<DexType> extraInterfaces, DexItemFactory factory) {
+ // We need to introduce in the dalvik.annotation.Signature annotation the extra interfaces.
+ // At this point we cheat and pretend the extraInterfaces simply don't use any generic types.
+ DexAnnotation[] annotations = annotations().annotations;
+ for (int i = 0; i < annotations.length; i++) {
+ DexAnnotation annotation = annotations[i];
+ if (DexAnnotation.isSignatureAnnotation(annotation, factory)) {
+ DexAnnotation[] rewrittenAnnotations = annotations.clone();
+ rewrittenAnnotations[i] = rewriteSignatureAnnotation(annotation, extraInterfaces, factory);
+ setAnnotations(new DexAnnotationSet(rewrittenAnnotations));
+ // There is at most one signature annotation, so we can return here.
+ return;
+ }
+ }
+ }
+
+ private DexAnnotation rewriteSignatureAnnotation(
+ DexAnnotation annotation, List<DexType> extraInterfaces, DexItemFactory factory) {
+ String signature = DexAnnotation.getSignature(annotation);
+ StringBuilder newSignatureBuilder = new StringBuilder(signature);
+ for (DexType extraInterface : extraInterfaces) {
+ newSignatureBuilder.append(extraInterface.descriptor.toString());
+ }
+ return DexAnnotation.createSignatureAnnotation(newSignatureBuilder.toString(), factory);
+ }
+
@Override
public DexProgramClass get() {
return this;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
index be1bbfd..5ce5bb8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ResolutionResult;
@@ -33,7 +32,6 @@
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
@@ -325,10 +323,8 @@
// We cannot use the ClassProcessor since this applies up to 26, while the ClassProcessor
// applies up to 24.
for (DexEncodedMethod method : methods) {
- DexType[] newInterfaces =
- Arrays.copyOf(clazz.interfaces.values, clazz.interfaces.size() + 1);
- newInterfaces[newInterfaces.length - 1] = dispatchInterfaceTypeFor(method);
- clazz.interfaces = new DexTypeList(newInterfaces);
+ clazz.addExtraInterfaces(
+ Collections.singletonList(dispatchInterfaceTypeFor(method)), appView.dexItemFactory());
if (clazz.lookupVirtualMethod(method.getReference()) == null) {
DexEncodedMethod newMethod = createForwardingMethod(method, clazz);
clazz.addVirtualMethod(newMethod);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 27a5224..f537a6f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -920,7 +920,7 @@
private void duplicateEmulatedInterfaces() {
// All classes implementing an emulated interface now implements the interface and the
// emulated one, as well as hidden overrides, for correct emulated dispatch.
- for (DexClass clazz : appView.appInfo().classes()) {
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
if (clazz.type == appView.dexItemFactory().objectType) {
continue;
}
@@ -940,17 +940,11 @@
}
}
// Remove duplicates.
- extraInterfaces = new ArrayList<>(new LinkedHashSet<>(extraInterfaces));
- }
- if (!extraInterfaces.isEmpty()) {
- DexType[] newInterfaces =
- Arrays.copyOf(
- clazz.interfaces.values, clazz.interfaces.size() + extraInterfaces.size());
- for (int i = clazz.interfaces.size(); i < newInterfaces.length; i++) {
- newInterfaces[i] = extraInterfaces.get(i - clazz.interfaces.size());
+ if (extraInterfaces.size() > 1) {
+ extraInterfaces = new ArrayList<>(new LinkedHashSet<>(extraInterfaces));
}
- clazz.interfaces = new DexTypeList(newInterfaces);
}
+ clazz.addExtraInterfaces(extraInterfaces, appView.dexItemFactory());
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibrarySubclassInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibrarySubclassInterfaceTest.java
new file mode 100644
index 0000000..12073e3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibrarySubclassInterfaceTest.java
@@ -0,0 +1,1014 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import dalvik.system.PathClassLoader;
+import java.sql.SQLDataException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class LibrarySubclassInterfaceTest extends DesugaredLibraryTestBase {
+
+ private final TestParameters parameters;
+ private final boolean shrinkDesugaredLibrary;
+
+ @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ }
+
+ public LibrarySubclassInterfaceTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+ this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testCustomCollectionD8() throws Exception {
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ String stdOut =
+ testForD8()
+ .addInnerClasses(LibrarySubclassInterfaceTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary,
+ parameters.getApiLevel(),
+ keepRuleConsumer.get(),
+ shrinkDesugaredLibrary)
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccess()
+ .getStdOut();
+ assertValidInterfaces(stdOut);
+ }
+
+ @Test
+ public void testCustomCollectionR8() throws Exception {
+ Assume.assumeFalse("TODO(b/162437880)", shrinkDesugaredLibrary);
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ String stdOut =
+ testForR8(Backend.DEX)
+ .addInnerClasses(LibrarySubclassInterfaceTest.class)
+ .addKeepMainRule(Executor.class)
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary,
+ parameters.getApiLevel(),
+ keepRuleConsumer.get(),
+ shrinkDesugaredLibrary)
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccess()
+ .getStdOut();
+ assertValidInterfaces(stdOut);
+ }
+
+ private void assertValidInterfaces(String stdOut) {
+ // The value of getGenericInterfaces has to be the value of getInterfaces with generic types.
+ // Here are two examples:
+ // - class A implements I {}
+ // getInterfaces -> [interface I]
+ // getGenericInterfaces -> [interface I]
+ // - class B<E> implements J<E> {}
+ // getInterfaces -> [interface J]
+ // getGenericInterfaces -> [J<E>]
+ // Both arrays have to be of the same size and each class has to be present in the same order.
+ String[] lines = stdOut.split("\n");
+ for (int i = 0; i < lines.length; i += 4) {
+ String className = lines[i];
+ String[] interfaces1 = lines[i + 1].split("(, com|, interface|, j)");
+ String[] interfaces2 = lines[i + 2].split("(, com|, interface|, j)");
+ assertEquals(
+ "Invalid number of interfaces in "
+ + className
+ + "\n "
+ + Arrays.toString(interfaces1)
+ + "\n "
+ + Arrays.toString(interfaces2),
+ interfaces1.length,
+ interfaces2.length);
+ // Ignore the empty list of interface case.
+ if (!interfaces1[0].equals("[]")) {
+ for (int j = 0; j < interfaces1.length; j++) {
+ String interfaceName = interfaces1[j].substring("interface ".length()).trim();
+ while (interfaceName.charAt(interfaceName.length() - 1) == ']') {
+ interfaceName = interfaceName.substring(0, interfaceName.length() - 2).trim();
+ }
+ assertTrue(
+ "Invalid interface in " + className + "\n " + interfaces1[j] + "\n " + interfaces2[j],
+ interfaces2[j].contains(interfaceName));
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
+ static class Executor {
+
+ // The output of the test is, in stdOut, composed of 4 lines entries:
+ // line 1: class name
+ // line 2: getInterfaces() for the class
+ // line 3: getGenericInterfaces() for the class
+ // line 4: empty.
+ public static void main(String[] args) {
+ mapTest();
+ collectionTest();
+ collectionMapTest();
+ sqlDateTest();
+ }
+
+ private static void mapTest() {
+ System.out.println(NullableConcurrentHashMapExtendDifferentLetters.class);
+ System.out.println(
+ Arrays.toString(NullableConcurrentHashMapExtendDifferentLetters.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(
+ NullableConcurrentHashMapExtendDifferentLetters.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(NullableConcurrentHashMapExtend.class);
+ System.out.println(Arrays.toString(NullableConcurrentHashMapExtend.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(NullableConcurrentHashMapExtend.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(NullableConcurrentHashMapExtendZ.class);
+ System.out.println(Arrays.toString(NullableConcurrentHashMapExtendZ.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(NullableConcurrentHashMapExtendZ.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(NullableConcurrentHashMapImplement.class);
+ System.out.println(Arrays.toString(NullableConcurrentHashMapImplement.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(NullableConcurrentHashMapImplement.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(NullableConcurrentHashMapImplementZ.class);
+ System.out.println(
+ Arrays.toString(NullableConcurrentHashMapImplementZ.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(NullableConcurrentHashMapImplementZ.class.getGenericInterfaces()));
+ System.out.println();
+ }
+
+ private static void collectionTest() {
+ System.out.println(NullableArrayListExtend.class);
+ System.out.println(Arrays.toString(NullableArrayListExtend.class.getInterfaces()));
+ System.out.println(Arrays.toString(NullableArrayListExtend.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(NullableArrayListExtendZ.class);
+ System.out.println(Arrays.toString(NullableArrayListExtendZ.class.getInterfaces()));
+ System.out.println(Arrays.toString(NullableArrayListExtendZ.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(NullableArrayListImplement.class);
+ System.out.println(Arrays.toString(NullableArrayListImplement.class.getInterfaces()));
+ System.out.println(Arrays.toString(NullableArrayListImplement.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(NullableArrayListImplementZ.class);
+ System.out.println(Arrays.toString(NullableArrayListImplementZ.class.getInterfaces()));
+ System.out.println(Arrays.toString(NullableArrayListImplementZ.class.getGenericInterfaces()));
+ System.out.println();
+ }
+
+ private static void collectionMapTest() {
+ System.out.println(CollectionMapImplements2.class);
+ System.out.println(Arrays.toString(CollectionMapImplements2.class.getInterfaces()));
+ System.out.println(Arrays.toString(CollectionMapImplements2.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(CollectionMapExtendImplement.class);
+ System.out.println(Arrays.toString(CollectionMapExtendImplement.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(CollectionMapExtendImplement.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(CollectionMapImplements2Integer1.class);
+ System.out.println(Arrays.toString(CollectionMapImplements2Integer1.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(CollectionMapImplements2Integer1.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(CollectionMapExtendImplementInteger1.class);
+ System.out.println(
+ Arrays.toString(CollectionMapExtendImplementInteger1.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(CollectionMapExtendImplementInteger1.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(CollectionMapImplements2Integer2.class);
+ System.out.println(Arrays.toString(CollectionMapImplements2Integer2.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(CollectionMapImplements2Integer2.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(CollectionMapExtendImplementInteger2.class);
+ System.out.println(
+ Arrays.toString(CollectionMapExtendImplementInteger2.class.getInterfaces()));
+ System.out.println(
+ Arrays.toString(CollectionMapExtendImplementInteger2.class.getGenericInterfaces()));
+ System.out.println();
+ }
+
+ private static void sqlDateTest() {
+ System.out.println(MySQLDataException.class);
+ System.out.println(Arrays.toString(MySQLDataException.class.getInterfaces()));
+ System.out.println(Arrays.toString(MySQLDataException.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(MyDate.class);
+ System.out.println(Arrays.toString(MyDate.class.getInterfaces()));
+ System.out.println(Arrays.toString(MyDate.class.getGenericInterfaces()));
+ System.out.println();
+
+ System.out.println(MyDateZ.class);
+ System.out.println(Arrays.toString(MyDateZ.class.getInterfaces()));
+ System.out.println(Arrays.toString(MyDateZ.class.getGenericInterfaces()));
+ System.out.println();
+ }
+ }
+
+ interface MyInterface<Z> {
+ void print(Z z);
+ }
+
+ static class NullableConcurrentHashMapExtendDifferentLetters<R, T>
+ extends ConcurrentHashMap<R, T> {
+ NullableConcurrentHashMapExtendDifferentLetters() {
+ super();
+ }
+ }
+
+ static class NullableConcurrentHashMapExtend<K, V> extends ConcurrentHashMap<K, V> {
+ NullableConcurrentHashMapExtend() {
+ super();
+ }
+ }
+
+ static class NullableConcurrentHashMapImplement<K, V> implements ConcurrentMap<K, V> {
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean containsKey(Object o) {
+ return false;
+ }
+
+ @Override
+ public boolean containsValue(Object o) {
+ return false;
+ }
+
+ @Override
+ public V get(Object o) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public V put(K k, V v) {
+ return null;
+ }
+
+ @Override
+ public V remove(Object o) {
+ return null;
+ }
+
+ @Override
+ public void putAll(@NotNull Map<? extends K, ? extends V> map) {}
+
+ @Override
+ public void clear() {}
+
+ @NotNull
+ @Override
+ public Set<K> keySet() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Collection<V> values() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ return null;
+ }
+
+ @Override
+ public V putIfAbsent(@NotNull K k, V v) {
+ return null;
+ }
+
+ @Override
+ public boolean remove(@NotNull Object o, Object o1) {
+ return false;
+ }
+
+ @Override
+ public boolean replace(@NotNull K k, @NotNull V v, @NotNull V v1) {
+ return false;
+ }
+
+ @Override
+ public V replace(@NotNull K k, @NotNull V v) {
+ return null;
+ }
+ }
+
+ static class NullableConcurrentHashMapExtendZ<K, V> extends ConcurrentHashMap<K, V>
+ implements MyInterface<K> {
+ NullableConcurrentHashMapExtendZ() {
+ super();
+ }
+
+ @Override
+ public void print(K k) {}
+ }
+
+ static class NullableConcurrentHashMapImplementZ<K, V>
+ implements ConcurrentMap<K, V>, MyInterface<K> {
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean containsKey(Object o) {
+ return false;
+ }
+
+ @Override
+ public boolean containsValue(Object o) {
+ return false;
+ }
+
+ @Override
+ public V get(Object o) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public V put(K k, V v) {
+ return null;
+ }
+
+ @Override
+ public V remove(Object o) {
+ return null;
+ }
+
+ @Override
+ public void putAll(@NotNull Map<? extends K, ? extends V> map) {}
+
+ @Override
+ public void clear() {}
+
+ @NotNull
+ @Override
+ public Set<K> keySet() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Collection<V> values() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ return null;
+ }
+
+ @Override
+ public V putIfAbsent(@NotNull K k, V v) {
+ return null;
+ }
+
+ @Override
+ public boolean remove(@NotNull Object o, Object o1) {
+ return false;
+ }
+
+ @Override
+ public boolean replace(@NotNull K k, @NotNull V v, @NotNull V v1) {
+ return false;
+ }
+
+ @Override
+ public V replace(@NotNull K k, @NotNull V v) {
+ return null;
+ }
+
+ @Override
+ public void print(K k) {}
+ }
+
+ static class NullableArrayListExtend<E> extends ArrayList<E> {
+ NullableArrayListExtend() {
+ super();
+ }
+ }
+
+ static class NullableArrayListImplement<E> implements List<E> {
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return false;
+ }
+
+ @NotNull
+ @Override
+ public Iterator<E> iterator() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Object[] toArray() {
+ return new Object[0];
+ }
+
+ @NotNull
+ @Override
+ public <T> T[] toArray(@NotNull T[] ts) {
+ return null;
+ }
+
+ @Override
+ public boolean add(E e) {
+ return false;
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return false;
+ }
+
+ @Override
+ public boolean containsAll(@NotNull Collection<?> collection) {
+ return false;
+ }
+
+ @Override
+ public boolean addAll(@NotNull Collection<? extends E> collection) {
+ return false;
+ }
+
+ @Override
+ public boolean addAll(int i, @NotNull Collection<? extends E> collection) {
+ return false;
+ }
+
+ @Override
+ public boolean removeAll(@NotNull Collection<?> collection) {
+ return false;
+ }
+
+ @Override
+ public boolean retainAll(@NotNull Collection<?> collection) {
+ return false;
+ }
+
+ @Override
+ public void clear() {}
+
+ @Override
+ public E get(int i) {
+ return null;
+ }
+
+ @Override
+ public E set(int i, E e) {
+ return null;
+ }
+
+ @Override
+ public void add(int i, E e) {}
+
+ @Override
+ public E remove(int i) {
+ return null;
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ return 0;
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ return 0;
+ }
+
+ @NotNull
+ @Override
+ public ListIterator<E> listIterator() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public ListIterator<E> listIterator(int i) {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public List<E> subList(int i, int i1) {
+ return null;
+ }
+ }
+
+ static class NullableArrayListExtendZ<E> extends ArrayList<E> implements MyInterface<E> {
+ NullableArrayListExtendZ() {
+ super();
+ }
+
+ @Override
+ public void print(E e) {}
+ }
+
+ static class NullableArrayListImplementZ<E> implements List<E>, MyInterface<E> {
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return false;
+ }
+
+ @NotNull
+ @Override
+ public Iterator<E> iterator() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Object[] toArray() {
+ return new Object[0];
+ }
+
+ @NotNull
+ @Override
+ public <T> T[] toArray(@NotNull T[] ts) {
+ return null;
+ }
+
+ @Override
+ public boolean add(E e) {
+ return false;
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return false;
+ }
+
+ @Override
+ public boolean containsAll(@NotNull Collection<?> collection) {
+ return false;
+ }
+
+ @Override
+ public boolean addAll(@NotNull Collection<? extends E> collection) {
+ return false;
+ }
+
+ @Override
+ public boolean addAll(int i, @NotNull Collection<? extends E> collection) {
+ return false;
+ }
+
+ @Override
+ public boolean removeAll(@NotNull Collection<?> collection) {
+ return false;
+ }
+
+ @Override
+ public boolean retainAll(@NotNull Collection<?> collection) {
+ return false;
+ }
+
+ @Override
+ public void clear() {}
+
+ @Override
+ public E get(int i) {
+ return null;
+ }
+
+ @Override
+ public E set(int i, E e) {
+ return null;
+ }
+
+ @Override
+ public void add(int i, E e) {}
+
+ @Override
+ public E remove(int i) {
+ return null;
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ return 0;
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ return 0;
+ }
+
+ @NotNull
+ @Override
+ public ListIterator<E> listIterator() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public ListIterator<E> listIterator(int i) {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public List<E> subList(int i, int i1) {
+ return null;
+ }
+
+ @Override
+ public void print(E e) {}
+ }
+
+ static class CollectionMapImplements2<R, C> implements Iterable<R>, Map<R, C> {
+ @NotNull
+ @Override
+ public Iterator<R> iterator() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean containsKey(Object o) {
+ return false;
+ }
+
+ @Override
+ public boolean containsValue(Object o) {
+ return false;
+ }
+
+ @Override
+ public C get(Object o) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public C put(R r, C c) {
+ return null;
+ }
+
+ @Override
+ public C remove(Object o) {
+ return null;
+ }
+
+ @Override
+ public void putAll(@NotNull Map<? extends R, ? extends C> map) {}
+
+ @Override
+ public void clear() {}
+
+ @NotNull
+ @Override
+ public Set<R> keySet() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Collection<C> values() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Set<Entry<R, C>> entrySet() {
+ return null;
+ }
+ }
+
+ static class CollectionMapExtendImplement<R, C> extends HashMap<R, C> implements Iterable<R> {
+ @NotNull
+ @Override
+ public Iterator<R> iterator() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean containsKey(Object o) {
+ return false;
+ }
+
+ @Override
+ public boolean containsValue(Object o) {
+ return false;
+ }
+
+ @Override
+ public C get(Object o) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public C put(R r, C c) {
+ return null;
+ }
+
+ @Override
+ public C remove(Object o) {
+ return null;
+ }
+
+ @Override
+ public void putAll(@NotNull Map<? extends R, ? extends C> map) {}
+
+ @Override
+ public void clear() {}
+
+ @NotNull
+ @Override
+ public Set<R> keySet() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Collection<C> values() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Set<Entry<R, C>> entrySet() {
+ return null;
+ }
+ }
+
+ static class CollectionMapImplements2Integer1<C>
+ implements Iterable<PathClassLoader>, Map<PathClassLoader, C> {
+ @NotNull
+ @Override
+ public Iterator<PathClassLoader> iterator() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean containsKey(Object o) {
+ return false;
+ }
+
+ @Override
+ public boolean containsValue(Object o) {
+ return false;
+ }
+
+ @Override
+ public C get(Object o) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public C put(PathClassLoader unsafe, C c) {
+ return null;
+ }
+
+ @Override
+ public C remove(Object o) {
+ return null;
+ }
+
+ @Override
+ public void putAll(@NotNull Map<? extends PathClassLoader, ? extends C> map) {}
+
+ @Override
+ public void clear() {}
+
+ @NotNull
+ @Override
+ public Set<PathClassLoader> keySet() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Collection<C> values() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Set<Entry<PathClassLoader, C>> entrySet() {
+ return null;
+ }
+ }
+
+ static class CollectionMapExtendImplementInteger1<C> extends HashMap<PathClassLoader, C>
+ implements Iterable<PathClassLoader> {
+ @NotNull
+ @Override
+ public Iterator<PathClassLoader> iterator() {
+ return null;
+ }
+ }
+
+ static class CollectionMapImplements2Integer2<R> implements Iterable<R>, Map<R, PathClassLoader> {
+ @NotNull
+ @Override
+ public Iterator<R> iterator() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean containsKey(Object o) {
+ return false;
+ }
+
+ @Override
+ public boolean containsValue(Object o) {
+ return false;
+ }
+
+ @Override
+ public PathClassLoader get(Object o) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public PathClassLoader put(R r, PathClassLoader unsafe) {
+ return null;
+ }
+
+ @Override
+ public PathClassLoader remove(Object o) {
+ return null;
+ }
+
+ @Override
+ public void putAll(@NotNull Map<? extends R, ? extends PathClassLoader> map) {}
+
+ @Override
+ public void clear() {}
+
+ @NotNull
+ @Override
+ public Set<R> keySet() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Collection<PathClassLoader> values() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Set<Entry<R, PathClassLoader>> entrySet() {
+ return null;
+ }
+ }
+
+ static class CollectionMapExtendImplementInteger2<R> extends HashMap<R, PathClassLoader>
+ implements Iterable<R> {
+ @NotNull
+ @Override
+ public Iterator<R> iterator() {
+ return null;
+ }
+ }
+
+ // SQLDataException implements Iterable<Throwable>.
+ static class MySQLDataException extends SQLDataException {}
+
+ // java.util.Date for the extra dispatch case.
+ static class MyDate extends Date {}
+
+ static class MyDateZ<Z> extends Date implements MyInterface<Z> {
+ @Override
+ public void print(Z z) {}
+ }
+}