xref: /aosp_15_r20/tools/metalava/metalava/src/test/java/com/android/tools/metalava/stub/StubsConstructorTest.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.model.provider.Capability
20 import com.android.tools.metalava.model.testing.RequiresCapabilities
21 import com.android.tools.metalava.model.text.FileFormat
22 import com.android.tools.metalava.testing.java
23 import com.android.tools.metalava.testing.kotlin
24 import org.junit.Test
25 
26 @SuppressWarnings("ALL")
27 class StubsConstructorTest : AbstractStubsTest() {
28 
29     @Test
Generate stubs for class that should not get default constructor (has other constructors)null30     fun `Generate stubs for class that should not get default constructor (has other constructors)`() {
31         // Class without explicit constructors (shouldn't insert default constructor)
32         checkStubs(
33             sourceFiles =
34                 arrayOf(
35                     java(
36                         """
37                     package test.pkg;
38                     public class Foo {
39                         public Foo(int i) {
40 
41                         }
42                         public Foo(int i, int j) {
43                         }
44                     }
45                     """
46                     )
47                 ),
48             source =
49                 """
50                 package test.pkg;
51                 @SuppressWarnings({"unchecked", "deprecation", "all"})
52                 public class Foo {
53                 public Foo(int i) { throw new RuntimeException("Stub!"); }
54                 public Foo(int i, int j) { throw new RuntimeException("Stub!"); }
55                 }
56                 """
57         )
58     }
59 
60     @Test
Generate stubs for class that already has a private constructornull61     fun `Generate stubs for class that already has a private constructor`() {
62         // Class without private constructor; no default constructor should be inserted
63         checkStubs(
64             sourceFiles =
65                 arrayOf(
66                     java(
67                         """
68                     package test.pkg;
69                     public class Foo {
70                         private Foo() {
71                         }
72                     }
73                     """
74                     )
75                 ),
76             source =
77                 """
78                 package test.pkg;
79                 @SuppressWarnings({"unchecked", "deprecation", "all"})
80                 public class Foo {
81                 Foo() { throw new RuntimeException("Stub!"); }
82                 }
83                 """
84         )
85     }
86 
87     @Test
Arguments to super constructorsnull88     fun `Arguments to super constructors`() {
89         // When overriding constructors we have to supply arguments
90         checkStubs(
91             sourceFiles =
92                 arrayOf(
93                     java(
94                         """
95                     package test.pkg;
96 
97                     @SuppressWarnings("WeakerAccess")
98                     public class Constructors {
99                         public class Parent {
100                             public Parent(String arg1, int arg2, long arg3, boolean arg4, short arg5) {
101                             }
102                         }
103 
104                         public class Child extends Parent {
105                             public Child(String arg1, int arg2, long arg3, boolean arg4, short arg5) {
106                                 super(arg1, arg2, arg3, arg4, arg5);
107                             }
108 
109                             private Child(String arg1) {
110                                 super(arg1, 0, 0, false, 0);
111                             }
112                         }
113 
114                         public class Child2 extends Parent {
115                             Child2(String arg1) {
116                                 super(arg1, 0, 0, false, 0);
117                             }
118                         }
119 
120                         public class Child3 extends Child2 {
121                             private Child3(String arg1) {
122                                 super("something");
123                             }
124                         }
125 
126                         public class Child4 extends Parent {
127                             Child4(String arg1, HiddenClass arg2) {
128                                 super(arg1, 0, 0, true, 0);
129                             }
130                         }
131                         /** @hide */
132                         public class HiddenClass {
133                         }
134                     }
135                     """
136                     )
137                 ),
138             source =
139                 """
140                     package test.pkg;
141                     @SuppressWarnings({"unchecked", "deprecation", "all"})
142                     public class Constructors {
143                     public Constructors() { throw new RuntimeException("Stub!"); }
144                     @SuppressWarnings({"unchecked", "deprecation", "all"})
145                     public class Child extends test.pkg.Constructors.Parent {
146                     public Child(java.lang.String arg1, int arg2, long arg3, boolean arg4, short arg5) { super("", 0, 0, false, (short)0); throw new RuntimeException("Stub!"); }
147                     }
148                     @SuppressWarnings({"unchecked", "deprecation", "all"})
149                     public class Child2 extends test.pkg.Constructors.Parent {
150                     Child2() { super("", 0, 0, false, (short)0); throw new RuntimeException("Stub!"); }
151                     }
152                     @SuppressWarnings({"unchecked", "deprecation", "all"})
153                     public class Child3 extends test.pkg.Constructors.Child2 {
154                     Child3() { throw new RuntimeException("Stub!"); }
155                     }
156                     @SuppressWarnings({"unchecked", "deprecation", "all"})
157                     public class Child4 extends test.pkg.Constructors.Parent {
158                     Child4() { super("", 0, 0, false, (short)0); throw new RuntimeException("Stub!"); }
159                     }
160                     @SuppressWarnings({"unchecked", "deprecation", "all"})
161                     public class Parent {
162                     public Parent(java.lang.String arg1, int arg2, long arg3, boolean arg4, short arg5) { throw new RuntimeException("Stub!"); }
163                     }
164                     }
165                     """,
166             checkTextStubEquivalence = true
167         )
168     }
169 
170     @Test
Arguments to super constructors with showAnnotationsnull171     fun `Arguments to super constructors with showAnnotations`() {
172         // When overriding constructors we have to supply arguments
173         checkStubs(
174             showAnnotations = arrayOf("android.annotation.SystemApi"),
175             sourceFiles =
176                 arrayOf(
177                     java(
178                         """
179                     package test.pkg;
180 
181                     @SuppressWarnings("WeakerAccess")
182                     public class Constructors {
183                         public class Parent {
184                             public Parent(String s, int i, long l, boolean b, short sh) {
185                             }
186                         }
187 
188                         public class Child extends Parent {
189                             public Child(String s, int i, long l, boolean b, short sh) {
190                                 super(s, i, l, b, sh);
191                             }
192 
193                             private Child(String s) {
194                                 super(s, 0, 0, false, 0);
195                             }
196                         }
197 
198                         public class Child2 extends Parent {
199                             Child2(String s) {
200                                 super(s, 0, 0, false, 0);
201                             }
202                         }
203 
204                         public class Child3 extends Child2 {
205                             private Child3(String s) {
206                                 super("something");
207                             }
208                         }
209 
210                         public class Child4 extends Parent {
211                             Child4(String s, HiddenClass hidden) {
212                                 super(s, 0, 0, true, 0);
213                             }
214                         }
215                         /** @hide */
216                         public class HiddenClass {
217                         }
218                     }
219                     """
220                     )
221                 ),
222             source =
223                 """
224                     package test.pkg;
225                     @SuppressWarnings({"unchecked", "deprecation", "all"})
226                     public class Constructors {
227                     public Constructors() { throw new RuntimeException("Stub!"); }
228                     @SuppressWarnings({"unchecked", "deprecation", "all"})
229                     public class Child extends test.pkg.Constructors.Parent {
230                     public Child(java.lang.String s, int i, long l, boolean b, short sh) { super("", 0, 0, false, (short)0); throw new RuntimeException("Stub!"); }
231                     }
232                     @SuppressWarnings({"unchecked", "deprecation", "all"})
233                     public class Child2 extends test.pkg.Constructors.Parent {
234                     Child2() { super("", 0, 0, false, (short)0); throw new RuntimeException("Stub!"); }
235                     }
236                     @SuppressWarnings({"unchecked", "deprecation", "all"})
237                     public class Child3 extends test.pkg.Constructors.Child2 {
238                     Child3() { throw new RuntimeException("Stub!"); }
239                     }
240                     @SuppressWarnings({"unchecked", "deprecation", "all"})
241                     public class Child4 extends test.pkg.Constructors.Parent {
242                     Child4() { super("", 0, 0, false, (short)0); throw new RuntimeException("Stub!"); }
243                     }
244                     @SuppressWarnings({"unchecked", "deprecation", "all"})
245                     public class Parent {
246                     public Parent(java.lang.String s, int i, long l, boolean b, short sh) { throw new RuntimeException("Stub!"); }
247                     }
248                     }
249                     """
250         )
251     }
252 
253     // TODO: Add test to see what happens if I have Child4 in a different package which can't access
254     // the package private constructor of child3?
255 
256     @Test
Test inaccessible constructorsnull257     fun `Test inaccessible constructors`() {
258         // If the constructors of a class are not visible, and the class has subclasses,
259         // those subclass stubs will need to reference these inaccessible constructors.
260         // This generally only happens when the constructors are package private (and
261         // therefore hidden) but the subclass using it is also in the same package.
262 
263         check(
264             checkCompilation = true,
265             sourceFiles =
266                 arrayOf(
267                     java(
268                         """
269                     package test.pkg;
270                     public class MyClass1 {
271                         MyClass1(int myVar) { }
272                     }
273                     """
274                     ),
275                     java(
276                         """
277                     package test.pkg;
278                     import java.io.IOException;
279                     @SuppressWarnings("RedundantThrows")
280                     public class MySubClass1 extends MyClass1 {
281                         MySubClass1(int myVar) throws IOException { super(myVar); }
282                     }
283                     """
284                     ),
285                     java(
286                         """
287                     package test.pkg;
288                     public class MyClass2 {
289                         /** @hide */
290                         public MyClass2(int myVar) { }
291                     }
292                     """
293                     ),
294                     java(
295                         """
296                     package test.pkg;
297                     public class MySubClass2 extends MyClass2 {
298                         public MySubClass2() { super(5); }
299                     }
300                     """
301                     )
302                 ),
303             expectedIssues = "",
304             api =
305                 """
306                     package test.pkg {
307                       public class MyClass1 {
308                       }
309                       public class MyClass2 {
310                       }
311                       public class MySubClass1 extends test.pkg.MyClass1 {
312                       }
313                       public class MySubClass2 extends test.pkg.MyClass2 {
314                         ctor public MySubClass2();
315                       }
316                     }
317                     """,
318             stubFiles =
319                 arrayOf(
320                     java(
321                         """
322                     package test.pkg;
323                     @SuppressWarnings({"unchecked", "deprecation", "all"})
324                     public class MyClass1 {
325                     MyClass1() { throw new RuntimeException("Stub!"); }
326                     }
327                     """
328                     ),
329                     java(
330                         """
331                     package test.pkg;
332                     @SuppressWarnings({"unchecked", "deprecation", "all"})
333                     public class MySubClass1 extends test.pkg.MyClass1 {
334                     MySubClass1() { throw new RuntimeException("Stub!"); }
335                     }
336                     """
337                     ),
338                     java(
339                         """
340                     package test.pkg;
341                     @SuppressWarnings({"unchecked", "deprecation", "all"})
342                     public class MyClass2 {
343                     MyClass2() { throw new RuntimeException("Stub!"); }
344                     }
345                     """
346                     ),
347                     java(
348                         """
349                     package test.pkg;
350                     @SuppressWarnings({"unchecked", "deprecation", "all"})
351                     public class MySubClass2 extends test.pkg.MyClass2 {
352                     public MySubClass2() { throw new RuntimeException("Stub!"); }
353                     }
354                     """
355                     )
356                 ),
357         )
358     }
359 
360     // TODO: Add a protected constructor too to make sure my code to make non-public constructors
361     // package private
362     // don't accidentally demote protected constructors to package private!
363 
364     @Test
Picking Super Constructorsnull365     fun `Picking Super Constructors`() {
366         checkStubs(
367             format = FileFormat.V2,
368             sourceFiles =
369                 arrayOf(
370                     java(
371                         """
372                     package test.pkg;
373 
374                     @SuppressWarnings({"RedundantThrows", "JavaDoc", "WeakerAccess"})
375                     public class PickConstructors {
376                         public abstract static class FileInputStream extends InputStream {
377 
378                             public FileInputStream(String name) throws FileNotFoundException {
379                             }
380 
381                             public FileInputStream(File file) throws FileNotFoundException {
382                             }
383 
384                             public FileInputStream(FileDescriptor fdObj) {
385                                 this(fdObj, false /* isFdOwner */);
386                             }
387 
388                             /**
389                              * @hide
390                              */
391                             public FileInputStream(FileDescriptor fdObj, boolean isFdOwner) {
392                             }
393                         }
394 
395                         public abstract static class AutoCloseInputStream extends FileInputStream {
396                             public AutoCloseInputStream(ParcelFileDescriptor pfd) {
397                                 super(pfd.getFileDescriptor());
398                             }
399                         }
400 
401                         abstract static class HiddenParentStream extends FileInputStream {
402                             public HiddenParentStream(FileDescriptor pfd) {
403                                 super(pfd);
404                             }
405                         }
406 
407                         public abstract static class AutoCloseInputStream2 extends HiddenParentStream {
408                             public AutoCloseInputStream2(ParcelFileDescriptor pfd) {
409                                 super(pfd.getFileDescriptor());
410                             }
411                         }
412 
413                         public abstract class ParcelFileDescriptor implements Closeable {
414                             public abstract FileDescriptor getFileDescriptor();
415                         }
416 
417                         @SuppressWarnings("UnnecessaryInterfaceModifier")
418                         public static interface Closeable extends AutoCloseable {
419                         }
420 
421                         @SuppressWarnings("UnnecessaryInterfaceModifier")
422                         public static interface AutoCloseable {
423                         }
424 
425                         public static abstract class InputStream implements Closeable {
426                         }
427 
428                         public static class File {
429                         }
430 
431                         public static final class FileDescriptor {
432                         }
433 
434                         public static class FileNotFoundException extends IOException {
435                         }
436 
437                         public static class IOException extends Exception {
438                         }
439                     }
440                     """
441                     )
442                 ),
443             warnings = "",
444             api =
445                 """
446                     package test.pkg {
447                       public class PickConstructors {
448                         ctor public PickConstructors();
449                       }
450                       public abstract static class PickConstructors.AutoCloseInputStream extends test.pkg.PickConstructors.FileInputStream {
451                         ctor public PickConstructors.AutoCloseInputStream(test.pkg.PickConstructors.ParcelFileDescriptor);
452                       }
453                       public abstract static class PickConstructors.AutoCloseInputStream2 extends test.pkg.PickConstructors.FileInputStream {
454                         ctor public PickConstructors.AutoCloseInputStream2(test.pkg.PickConstructors.ParcelFileDescriptor);
455                       }
456                       public static interface PickConstructors.AutoCloseable {
457                       }
458                       public static interface PickConstructors.Closeable extends test.pkg.PickConstructors.AutoCloseable {
459                       }
460                       public static class PickConstructors.File {
461                         ctor public PickConstructors.File();
462                       }
463                       public static final class PickConstructors.FileDescriptor {
464                         ctor public PickConstructors.FileDescriptor();
465                       }
466                       public abstract static class PickConstructors.FileInputStream extends test.pkg.PickConstructors.InputStream {
467                         ctor public PickConstructors.FileInputStream(String) throws test.pkg.PickConstructors.FileNotFoundException;
468                         ctor public PickConstructors.FileInputStream(test.pkg.PickConstructors.File) throws test.pkg.PickConstructors.FileNotFoundException;
469                         ctor public PickConstructors.FileInputStream(test.pkg.PickConstructors.FileDescriptor);
470                       }
471                       public static class PickConstructors.FileNotFoundException extends test.pkg.PickConstructors.IOException {
472                         ctor public PickConstructors.FileNotFoundException();
473                       }
474                       public static class PickConstructors.IOException extends java.lang.Exception {
475                         ctor public PickConstructors.IOException();
476                       }
477                       public abstract static class PickConstructors.InputStream implements test.pkg.PickConstructors.Closeable {
478                         ctor public PickConstructors.InputStream();
479                       }
480                       public abstract class PickConstructors.ParcelFileDescriptor implements test.pkg.PickConstructors.Closeable {
481                         ctor public PickConstructors.ParcelFileDescriptor();
482                         method public abstract test.pkg.PickConstructors.FileDescriptor getFileDescriptor();
483                       }
484                     }
485                 """,
486             source =
487                 """
488                     package test.pkg;
489                     @SuppressWarnings({"unchecked", "deprecation", "all"})
490                     public class PickConstructors {
491                     public PickConstructors() { throw new RuntimeException("Stub!"); }
492                     @SuppressWarnings({"unchecked", "deprecation", "all"})
493                     public abstract static class AutoCloseInputStream extends test.pkg.PickConstructors.FileInputStream {
494                     public AutoCloseInputStream(test.pkg.PickConstructors.ParcelFileDescriptor pfd) { super((test.pkg.PickConstructors.FileDescriptor)null); throw new RuntimeException("Stub!"); }
495                     }
496                     @SuppressWarnings({"unchecked", "deprecation", "all"})
497                     public abstract static class AutoCloseInputStream2 extends test.pkg.PickConstructors.FileInputStream {
498                     public AutoCloseInputStream2(test.pkg.PickConstructors.ParcelFileDescriptor pfd) { super((test.pkg.PickConstructors.FileDescriptor)null); throw new RuntimeException("Stub!"); }
499                     }
500                     @SuppressWarnings({"unchecked", "deprecation", "all"})
501                     public static interface AutoCloseable {
502                     }
503                     @SuppressWarnings({"unchecked", "deprecation", "all"})
504                     public static interface Closeable extends test.pkg.PickConstructors.AutoCloseable {
505                     }
506                     @SuppressWarnings({"unchecked", "deprecation", "all"})
507                     public static class File {
508                     public File() { throw new RuntimeException("Stub!"); }
509                     }
510                     @SuppressWarnings({"unchecked", "deprecation", "all"})
511                     public static final class FileDescriptor {
512                     public FileDescriptor() { throw new RuntimeException("Stub!"); }
513                     }
514                     @SuppressWarnings({"unchecked", "deprecation", "all"})
515                     public abstract static class FileInputStream extends test.pkg.PickConstructors.InputStream {
516                     public FileInputStream(java.lang.String name) throws test.pkg.PickConstructors.FileNotFoundException { throw new RuntimeException("Stub!"); }
517                     public FileInputStream(test.pkg.PickConstructors.File file) throws test.pkg.PickConstructors.FileNotFoundException { throw new RuntimeException("Stub!"); }
518                     public FileInputStream(test.pkg.PickConstructors.FileDescriptor fdObj) { throw new RuntimeException("Stub!"); }
519                     }
520                     @SuppressWarnings({"unchecked", "deprecation", "all"})
521                     public static class FileNotFoundException extends test.pkg.PickConstructors.IOException {
522                     public FileNotFoundException() { throw new RuntimeException("Stub!"); }
523                     }
524                     @SuppressWarnings({"unchecked", "deprecation", "all"})
525                     public static class IOException extends java.lang.Exception {
526                     public IOException() { throw new RuntimeException("Stub!"); }
527                     }
528                     @SuppressWarnings({"unchecked", "deprecation", "all"})
529                     public abstract static class InputStream implements test.pkg.PickConstructors.Closeable {
530                     public InputStream() { throw new RuntimeException("Stub!"); }
531                     }
532                     @SuppressWarnings({"unchecked", "deprecation", "all"})
533                     public abstract class ParcelFileDescriptor implements test.pkg.PickConstructors.Closeable {
534                     public ParcelFileDescriptor() { throw new RuntimeException("Stub!"); }
535                     public abstract test.pkg.PickConstructors.FileDescriptor getFileDescriptor();
536                     }
537                     }
538                     """
539         )
540     }
541 
542     @Test
Picking Constructorsnull543     fun `Picking Constructors`() {
544         checkStubs(
545             sourceFiles =
546                 arrayOf(
547                     java(
548                         """
549                     package test.pkg;
550 
551                     @SuppressWarnings({"WeakerAccess", "unused"})
552                     public class Constructors2 {
553                         public class TestSuite implements Test {
554 
555                             public TestSuite() {
556                             }
557 
558                             public TestSuite(final Class<?> theClass) {
559                             }
560 
561                             public TestSuite(Class<? extends TestCase> theClass, String name) {
562                                 this(theClass);
563                             }
564 
565                             public TestSuite(String name) {
566                             }
567                             public TestSuite(Class<?>... classes) {
568                             }
569 
570                             public TestSuite(Class<? extends TestCase>[] classes, String name) {
571                                 this(classes);
572                             }
573                         }
574 
575                         public class TestCase {
576                         }
577 
578                         public interface Test {
579                         }
580 
581                         public class Parent {
582                             public Parent(int x) throws IOException {
583                             }
584                         }
585 
586                         class Intermediate extends Parent {
587                             Intermediate(int x) throws IOException { super(x); }
588                         }
589 
590                         public class Child extends Intermediate {
591                             public Child() throws IOException { super(5); }
592                             public Child(float x) throws IOException { this(); }
593                         }
594 
595                         // ----------------------------------------------------
596 
597                         public abstract class DrawableWrapper {
598                             public DrawableWrapper(Drawable dr) {
599                             }
600 
601                             DrawableWrapper(Clipstate state, Object resources) {
602                             }
603                         }
604 
605 
606                         public class ClipDrawable extends DrawableWrapper {
607                             ClipDrawable() {
608                                 this(null);
609                             }
610 
611                             public ClipDrawable(Drawable drawable, int gravity, int orientation) { this(null); }
612 
613                             private ClipDrawable(Clipstate clipstate) {
614                                 super(clipstate, null);
615                             }
616                         }
617 
618                         public class Drawable {
619                         }
620 
621                         class Clipstate {
622                         }
623                     }
624                     """
625                     )
626                 ),
627             warnings = "",
628             source =
629                 """
630                     package test.pkg;
631                     @SuppressWarnings({"unchecked", "deprecation", "all"})
632                     public class Constructors2 {
633                     public Constructors2() { throw new RuntimeException("Stub!"); }
634                     @SuppressWarnings({"unchecked", "deprecation", "all"})
635                     public class Child extends test.pkg.Constructors2.Parent {
636                     public Child() { super(0); throw new RuntimeException("Stub!"); }
637                     public Child(float x) { super(0); throw new RuntimeException("Stub!"); }
638                     }
639                     @SuppressWarnings({"unchecked", "deprecation", "all"})
640                     public class ClipDrawable extends test.pkg.Constructors2.DrawableWrapper {
641                     public ClipDrawable(test.pkg.Constructors2.Drawable drawable, int gravity, int orientation) { super((test.pkg.Constructors2.Drawable)null); throw new RuntimeException("Stub!"); }
642                     }
643                     @SuppressWarnings({"unchecked", "deprecation", "all"})
644                     public class Drawable {
645                     public Drawable() { throw new RuntimeException("Stub!"); }
646                     }
647                     @SuppressWarnings({"unchecked", "deprecation", "all"})
648                     public abstract class DrawableWrapper {
649                     public DrawableWrapper(test.pkg.Constructors2.Drawable dr) { throw new RuntimeException("Stub!"); }
650                     }
651                     @SuppressWarnings({"unchecked", "deprecation", "all"})
652                     public class Parent {
653                     public Parent(int x) { throw new RuntimeException("Stub!"); }
654                     }
655                     @SuppressWarnings({"unchecked", "deprecation", "all"})
656                     public static interface Test {
657                     }
658                     @SuppressWarnings({"unchecked", "deprecation", "all"})
659                     public class TestCase {
660                     public TestCase() { throw new RuntimeException("Stub!"); }
661                     }
662                     @SuppressWarnings({"unchecked", "deprecation", "all"})
663                     public class TestSuite implements test.pkg.Constructors2.Test {
664                     public TestSuite() { throw new RuntimeException("Stub!"); }
665                     public TestSuite(java.lang.Class<? extends test.pkg.Constructors2.TestCase> theClass, java.lang.String name) { throw new RuntimeException("Stub!"); }
666                     public TestSuite(java.lang.Class<? extends test.pkg.Constructors2.TestCase>[] classes, java.lang.String name) { throw new RuntimeException("Stub!"); }
667                     public TestSuite(java.lang.Class<?> theClass) { throw new RuntimeException("Stub!"); }
668                     public TestSuite(java.lang.Class<?>... classes) { throw new RuntimeException("Stub!"); }
669                     public TestSuite(java.lang.String name) { throw new RuntimeException("Stub!"); }
670                     }
671                     }
672                     """
673         )
674     }
675 
676     @Test
Another Constructor Testnull677     fun `Another Constructor Test`() {
678         // A specific scenario triggered in the API where the right super class detector was not
679         // chosen
680         checkStubs(
681             sourceFiles =
682                 arrayOf(
683                     java(
684                         """
685                     package test.pkg;
686 
687                     @SuppressWarnings({"RedundantThrows", "JavaDoc", "WeakerAccess"})
688                     public class PickConstructors2 {
689                         public interface EventListener {
690                         }
691 
692                         public interface PropertyChangeListener extends EventListener {
693                         }
694 
695                         public static abstract class EventListenerProxy<T extends EventListener>
696                                 implements EventListener {
697                             public EventListenerProxy(T listener) {
698                             }
699                         }
700 
701                         public static class PropertyChangeListenerProxy
702                                 extends EventListenerProxy<PropertyChangeListener>
703                                 implements PropertyChangeListener {
704                             public PropertyChangeListenerProxy(String propertyName, PropertyChangeListener listener) {
705                                 super(listener);
706                             }
707                         }
708                     }
709                     """
710                     )
711                 ),
712             warnings = "",
713             source =
714                 """
715                     package test.pkg;
716                     @SuppressWarnings({"unchecked", "deprecation", "all"})
717                     public class PickConstructors2 {
718                     public PickConstructors2() { throw new RuntimeException("Stub!"); }
719                     @SuppressWarnings({"unchecked", "deprecation", "all"})
720                     public static interface EventListener {
721                     }
722                     @SuppressWarnings({"unchecked", "deprecation", "all"})
723                     public abstract static class EventListenerProxy<T extends test.pkg.PickConstructors2.EventListener> implements test.pkg.PickConstructors2.EventListener {
724                     public EventListenerProxy(T listener) { throw new RuntimeException("Stub!"); }
725                     }
726                     @SuppressWarnings({"unchecked", "deprecation", "all"})
727                     public static interface PropertyChangeListener extends test.pkg.PickConstructors2.EventListener {
728                     }
729                     @SuppressWarnings({"unchecked", "deprecation", "all"})
730                     public static class PropertyChangeListenerProxy extends test.pkg.PickConstructors2.EventListenerProxy<test.pkg.PickConstructors2.PropertyChangeListener> implements test.pkg.PickConstructors2.PropertyChangeListener {
731                     public PropertyChangeListenerProxy(java.lang.String propertyName, test.pkg.PickConstructors2.PropertyChangeListener listener) { super((test.pkg.PickConstructors2.PropertyChangeListener)null); throw new RuntimeException("Stub!"); }
732                     }
733                     }
734                     """
735         )
736     }
737 
738     @Test
Use type argument in constructor castnull739     fun `Use type argument in constructor cast`() {
740         check(
741             format = FileFormat.V2,
742             sourceFiles =
743                 arrayOf(
744                     java(
745                         """
746                     package test.pkg;
747                     /** @deprecated */
748                     @Deprecated
749                     public class BasicPoolEntryRef extends WeakRef<BasicPoolEntry> {
750                         public BasicPoolEntryRef(BasicPoolEntry entry) {
751                             super(entry);
752                         }
753                     }
754                     """
755                     ),
756                     java(
757                         """
758                     package test.pkg;
759 
760                     public class WeakRef<T> {
761                         public WeakRef(T foo) {
762                         }
763                         // need to have more than one constructor to trigger casts in stubs
764                         public WeakRef(T foo, int size) {
765                         }
766                     }
767                     """
768                     ),
769                     java(
770                         """
771                     package test.pkg;
772 
773                     public class BasicPoolEntry {
774                     }
775                     """
776                     )
777                 ),
778             api =
779                 """
780                 package test.pkg {
781                   public class BasicPoolEntry {
782                     ctor public BasicPoolEntry();
783                   }
784                   @Deprecated public class BasicPoolEntryRef extends test.pkg.WeakRef<test.pkg.BasicPoolEntry> {
785                     ctor @Deprecated public BasicPoolEntryRef(test.pkg.BasicPoolEntry);
786                   }
787                   public class WeakRef<T> {
788                     ctor public WeakRef(T);
789                     ctor public WeakRef(T, int);
790                   }
791                 }
792                 """,
793             stubFiles =
794                 arrayOf(
795                     java(
796                         """
797                     package test.pkg;
798                     /** @deprecated */
799                     @SuppressWarnings({"unchecked", "deprecation", "all"})
800                     @Deprecated
801                     public class BasicPoolEntryRef extends test.pkg.WeakRef<test.pkg.BasicPoolEntry> {
802                     @Deprecated
803                     public BasicPoolEntryRef(test.pkg.BasicPoolEntry entry) { super((test.pkg.BasicPoolEntry)null); throw new RuntimeException("Stub!"); }
804                     }
805                     """
806                     )
807                 )
808         )
809     }
810 
811     @Test
Use unspecified type argument in constructor castnull812     fun `Use unspecified type argument in constructor cast`() {
813         check(
814             format = FileFormat.V2,
815             sourceFiles =
816                 arrayOf(
817                     java(
818                         """
819                     package test.pkg;
820                     public class Foo extends Bar {
821                         public Foo(Integer i) {
822                             super(i);
823                         }
824                     }
825                     """
826                     ),
827                     java(
828                         """
829                     package test.pkg;
830 
831                     public class Bar<T extends Number> {
832                         public Bar(T foo) {
833                         }
834                         // need to have more than one constructor to trigger casts in stubs
835                         public Bar(T foo, int size) {
836                         }
837                     }
838                     """
839                     ),
840                 ),
841             api =
842                 """
843                 package test.pkg {
844                   public class Bar<T extends java.lang.Number> {
845                     ctor public Bar(T);
846                     ctor public Bar(T, int);
847                   }
848                   public class Foo extends test.pkg.Bar {
849                     ctor public Foo(Integer);
850                   }
851                 }
852                 """,
853             stubFiles =
854                 arrayOf(
855                     java(
856                         """
857                         package test.pkg;
858                         @SuppressWarnings({"unchecked", "deprecation", "all"})
859                         public class Foo extends test.pkg.Bar {
860                         public Foo(java.lang.Integer i) { super((java.lang.Number)null); throw new RuntimeException("Stub!"); }
861                         }
862                         """
863                     )
864                 )
865         )
866     }
867 
868     @Test
Varargs constructor parameter requiring castnull869     fun `Varargs constructor parameter requiring cast`() {
870         check(
871             format = FileFormat.V2,
872             sourceFiles =
873                 arrayOf(
874                     java(
875                         """
876                     package test.pkg;
877 
878                     public class Child extends Parent {
879                         public Child(int... ints) {
880                             super(ints);
881                         }
882                         public Child(String... strings) {
883                             super(strings);
884                         }
885                     }
886                     """
887                     ),
888                     java(
889                         """
890                     package test.pkg;
891 
892                     public class Parent {
893                         public Parent(int... ints) {
894                         }
895                         public Parent(String... strings) {
896                         }
897                     }
898                     """
899                     ),
900                 ),
901             api =
902                 """
903                 package test.pkg {
904                   public class Child extends test.pkg.Parent {
905                     ctor public Child(int...);
906                     ctor public Child(java.lang.String...);
907                   }
908                   public class Parent {
909                     ctor public Parent(int...);
910                     ctor public Parent(java.lang.String...);
911                   }
912                 }
913                 """,
914             stubFiles =
915                 arrayOf(
916                     java(
917                         """
918                     package test.pkg;
919                     @SuppressWarnings({"unchecked", "deprecation", "all"})
920                     public class Child extends test.pkg.Parent {
921                     public Child(int... ints) { super((int[])null); throw new RuntimeException("Stub!"); }
922                     public Child(java.lang.String... strings) { super((int[])null); throw new RuntimeException("Stub!"); }
923                     }
924                     """
925                     )
926                 )
927         )
928     }
929 
930     @RequiresCapabilities(Capability.KOTLIN)
931     @Test
File facade constructornull932     fun `File facade constructor`() {
933         check(
934             format = FileFormat.V2,
935             sourceFiles =
936                 arrayOf(
937                     kotlin(
938                         "test/pkg/Constants.kt",
939                         """
940                             package test.pkg
941 
942                             const val CONSTANT = "CONSTANT"
943                         """
944                     ),
945                 ),
946             api =
947                 """
948                     // Signature format: 2.0
949                     package test.pkg {
950                       public final class ConstantsKt {
951                         property public static final String CONSTANT;
952                         field @NonNull public static final String CONSTANT = "CONSTANT";
953                       }
954                     }
955                 """,
956             stubPaths = arrayOf("test/pkg/ConstantsKt.java"),
957             stubFiles =
958                 arrayOf(
959                     java(
960                         """
961                             package test.pkg;
962                             @SuppressWarnings({"unchecked", "deprecation", "all"})
963                             public final class ConstantsKt {
964                             ConstantsKt() { throw new RuntimeException("Stub!"); }
965                             @android.annotation.NonNull public static final java.lang.String CONSTANT = "CONSTANT";
966                             }
967                         """
968                     )
969                 )
970         )
971     }
972 }
973