xref: /aosp_15_r20/tools/metalava/metalava/src/test/java/com/android/tools/metalava/stub/StubsGenericTest.kt (revision 115816f9299ab6ddd6b9673b81f34e707f6bacab)
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tools.metalava.stub
18 
19 import com.android.tools.metalava.testing.java
20 import org.junit.Test
21 
22 @SuppressWarnings("ALL")
23 class StubsGenericTest : AbstractStubsTest() {
24     @Test
Generate stubs for genericsnull25     fun `Generate stubs for generics`() {
26         // Basic interface with generics; makes sure <T extends Object> is written as just <T>
27         // Also include some more complex generics expressions to make sure they're serialized
28         // correctly (in particular, using fully qualified names instead of what appears in
29         // the source code.)
30         check(
31             checkCompilation = true,
32             sourceFiles =
33                 arrayOf(
34                     java(
35                         """
36                     package test.pkg;
37                     @SuppressWarnings("ALL")
38                     public interface MyInterface2<T extends Number>
39                             extends MyBaseInterface {
40                         class TtsSpan<C extends MyInterface<?>> { }
41                         abstract class Range<T extends Comparable<? super T>> { }
42                     }
43                     """
44                     ),
45                     java(
46                         """
47                     package test.pkg;
48                     @SuppressWarnings("ALL")
49                     public interface MyInterface<T extends Object>
50                             extends MyBaseInterface {
51                     }
52                     """
53                     ),
54                     java(
55                         """
56                     package test.pkg;
57                     public interface MyBaseInterface {
58                     }
59                     """
60                     )
61                 ),
62             expectedIssues = "",
63             stubFiles =
64                 arrayOf(
65                     java(
66                         """
67                     package test.pkg;
68                     @SuppressWarnings({"unchecked", "deprecation", "all"})
69                     public interface MyInterface2<T extends java.lang.Number> extends test.pkg.MyBaseInterface {
70                     @SuppressWarnings({"unchecked", "deprecation", "all"})
71                     public abstract static class Range<T extends java.lang.Comparable<? super T>> {
72                     public Range() { throw new RuntimeException("Stub!"); }
73                     }
74                     @SuppressWarnings({"unchecked", "deprecation", "all"})
75                     public static class TtsSpan<C extends test.pkg.MyInterface<?>> {
76                     public TtsSpan() { throw new RuntimeException("Stub!"); }
77                     }
78                     }
79                     """
80                     ),
81                     java(
82                         """
83                     package test.pkg;
84                     @SuppressWarnings({"unchecked", "deprecation", "all"})
85                     public interface MyInterface<T> extends test.pkg.MyBaseInterface {
86                     }
87                     """
88                     ),
89                     java(
90                         """
91                     package test.pkg;
92                     @SuppressWarnings({"unchecked", "deprecation", "all"})
93                     public interface MyBaseInterface {
94                     }
95                     """
96                     )
97                 )
98         )
99     }
100 
101     @Test
Check correct throws list for genericsnull102     fun `Check correct throws list for generics`() {
103         checkStubs(
104             sourceFiles =
105                 arrayOf(
106                     java(
107                         """
108                     package test.pkg;
109 
110                     import java.util.function.Supplier;
111 
112                     @SuppressWarnings("RedundantThrows")
113                     public final class Test<T> {
114                         public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
115                             return null;
116                         }
117                     }
118                     """
119                     )
120                 ),
121             source =
122                 """
123                 package test.pkg;
124                 @SuppressWarnings({"unchecked", "deprecation", "all"})
125                 public final class Test<T> {
126                 public Test() { throw new RuntimeException("Stub!"); }
127                 public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X> exceptionSupplier) throws X { throw new RuntimeException("Stub!"); }
128                 }
129                 """
130         )
131     }
132 
133     @Test
Generate stubs for additional generics scenariosnull134     fun `Generate stubs for additional generics scenarios`() {
135         // Some additional declarations where PSI default type handling diffs from doclava1
136         checkStubs(
137             sourceFiles =
138                 arrayOf(
139                     java(
140                         """
141                     package test.pkg;
142 
143                     public abstract class Collections {
144                         public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T> collection) {
145                             return null;
146                         }
147                         public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T t);
148                         public final class Range<T extends java.lang.Comparable<? super T>> { }
149                     }
150                     """
151                     )
152                 ),
153             source =
154                 """
155                 package test.pkg;
156                 @SuppressWarnings({"unchecked", "deprecation", "all"})
157                 public abstract class Collections {
158                 public Collections() { throw new RuntimeException("Stub!"); }
159                 public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T t);
160                 public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T> collection) { throw new RuntimeException("Stub!"); }
161                 @SuppressWarnings({"unchecked", "deprecation", "all"})
162                 public final class Range<T extends java.lang.Comparable<? super T>> {
163                 public Range() { throw new RuntimeException("Stub!"); }
164                 }
165                 }
166                 """
167         )
168     }
169 
170     @Test
Generate stubs for even more generics scenariosnull171     fun `Generate stubs for even more generics scenarios`() {
172         // Some additional declarations where PSI default type handling diffs from doclava1
173         checkStubs(
174             sourceFiles =
175                 arrayOf(
176                     java(
177                         """
178                     package test.pkg;
179 
180                     import java.util.Set;
181 
182                     @SuppressWarnings("ALL")
183                     public class MoreAsserts {
184                         public static void assertEquals(String arg1, Set<? extends Object> arg2, Set<? extends Object> arg3) { }
185                         public static void assertEquals(Set<? extends Object> arg1, Set<? extends Object> arg2) { }
186                     }
187                     """
188                     )
189                 ),
190             source =
191                 """
192                 package test.pkg;
193                 @SuppressWarnings({"unchecked", "deprecation", "all"})
194                 public class MoreAsserts {
195                 public MoreAsserts() { throw new RuntimeException("Stub!"); }
196                 public static void assertEquals(java.lang.String arg1, java.util.Set<?> arg2, java.util.Set<?> arg3) { throw new RuntimeException("Stub!"); }
197                 public static void assertEquals(java.util.Set<?> arg1, java.util.Set<?> arg2) { throw new RuntimeException("Stub!"); }
198                 }
199                 """,
200             checkTextStubEquivalence = true
201         )
202     }
203 
204     @Test
Check generating classes with genericsnull205     fun `Check generating classes with generics`() {
206         checkStubs(
207             sourceFiles =
208                 arrayOf(
209                     java(
210                         """
211                     package test.pkg;
212 
213                     public class Generics {
214                         public <T> Generics(int surfaceSize, Class<T> klass) {
215                         }
216                     }
217                     """
218                     )
219                 ),
220             warnings = "",
221             source =
222                 """
223                     package test.pkg;
224                     @SuppressWarnings({"unchecked", "deprecation", "all"})
225                     public class Generics {
226                     public <T> Generics(int surfaceSize, java.lang.Class<T> klass) { throw new RuntimeException("Stub!"); }
227                     }
228                 """
229         )
230     }
231 
232     @Test
Generics Variable Rewritingnull233     fun `Generics Variable Rewriting`() {
234         // When we move methods from hidden superclasses into the subclass since they
235         // provide the implementation for a required method, it's possible that the
236         // method we copied in is referencing generics with a different variable than
237         // in the current class, so we need to handle this
238 
239         checkStubs(
240             sourceFiles =
241                 arrayOf(
242                     // TODO: Try using prefixes like "A", and "AA" to make sure my generics
243                     // variable renaming doesn't do something really unexpected
244                     java(
245                         """
246                     package test.pkg;
247 
248                     import java.util.List;
249                     import java.util.Map;
250 
251                     public class Generics {
252                         public class MyClass<X extends Number,Y> extends HiddenParent<X,Y> implements PublicParent<X,Y> {
253                         }
254 
255                         public class MyClass2<W> extends HiddenParent<Float,W> implements PublicParent<Float, W> {
256                         }
257 
258                         public class MyClass3 extends HiddenParent<Float,Double> implements PublicParent<Float,Double> {
259                         }
260 
261                         class HiddenParent<M, N> extends HiddenParent2<M, N>  {
262                         }
263 
264                         class HiddenParent2<T, TT>  {
265                             public Map<T,Map<TT, String>> createMap(List<T> list) {
266                                 return null;
267                             }
268                         }
269 
270                         public interface PublicParent<A extends Number,B> {
271                             Map<A,Map<B, String>> createMap(List<A> list);
272                         }
273                     }
274                     """
275                     )
276                 ),
277             warnings = "",
278             source =
279                 """
280                     package test.pkg;
281                     @SuppressWarnings({"unchecked", "deprecation", "all"})
282                     public class Generics {
283                     public Generics() { throw new RuntimeException("Stub!"); }
284                     @SuppressWarnings({"unchecked", "deprecation", "all"})
285                     public class MyClass<X extends java.lang.Number, Y> implements test.pkg.Generics.PublicParent<X,Y> {
286                     public MyClass() { throw new RuntimeException("Stub!"); }
287                     public java.util.Map<X,java.util.Map<Y,java.lang.String>> createMap(java.util.List<X> list) { throw new RuntimeException("Stub!"); }
288                     }
289                     @SuppressWarnings({"unchecked", "deprecation", "all"})
290                     public class MyClass2<W> implements test.pkg.Generics.PublicParent<java.lang.Float,W> {
291                     public MyClass2() { throw new RuntimeException("Stub!"); }
292                     public java.util.Map<java.lang.Float,java.util.Map<W,java.lang.String>> createMap(java.util.List<java.lang.Float> list) { throw new RuntimeException("Stub!"); }
293                     }
294                     @SuppressWarnings({"unchecked", "deprecation", "all"})
295                     public class MyClass3 implements test.pkg.Generics.PublicParent<java.lang.Float,java.lang.Double> {
296                     public MyClass3() { throw new RuntimeException("Stub!"); }
297                     public java.util.Map<java.lang.Float,java.util.Map<java.lang.Double,java.lang.String>> createMap(java.util.List<java.lang.Float> list) { throw new RuntimeException("Stub!"); }
298                     }
299                     @SuppressWarnings({"unchecked", "deprecation", "all"})
300                     public static interface PublicParent<A extends java.lang.Number, B> {
301                     public java.util.Map<A,java.util.Map<B,java.lang.String>> createMap(java.util.List<A> list);
302                     }
303                     }
304                     """
305         )
306     }
307 }
308