xref: /aosp_15_r20/tools/metalava/metalava/src/test/java/com/android/tools/metalava/JavadocTest.kt (revision 115816f9299ab6ddd6b9673b81f34e707f6bacab)
1 /*
2  * Copyright (C) 2018 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
18 
19 import com.android.tools.lint.checks.infrastructure.TestFile
20 import com.android.tools.metalava.lint.DefaultLintErrorMessage
21 import com.android.tools.metalava.model.psi.REPORT_UNRESOLVED_SYMBOLS
22 import com.android.tools.metalava.model.source.utils.packageHtmlToJavadoc
23 import com.android.tools.metalava.testing.java
24 import org.intellij.lang.annotations.Language
25 import org.junit.Assert.assertEquals
26 import org.junit.Test
27 
28 @Suppress("JavadocReference")
29 class JavadocTest : DriverTest() {
checkStubsnull30     private fun checkStubs(
31         @Language("JAVA") source: String,
32         warnings: String? = "",
33         expectedFail: String? = null,
34         apiLint: String? = null,
35         api: String? = null,
36         extraArguments: Array<String> = emptyArray(),
37         docStubs: Boolean = false,
38         showAnnotations: Array<String> = emptyArray(),
39         skipEmitPackages: List<String> = listOf("java.lang", "java.util", "java.io"),
40         sourceFiles: Array<TestFile>
41     ) {
42         check(
43             sourceFiles = sourceFiles,
44             showAnnotations = showAnnotations,
45             stubFiles = arrayOf(java(source)),
46             expectedFail = expectedFail,
47             expectedIssues = warnings,
48             checkCompilation = true,
49             apiLint = apiLint,
50             api = api,
51             extraArguments = extraArguments,
52             docStubs = docStubs,
53             skipEmitPackages = skipEmitPackages
54         )
55     }
56 
57     @Test
Test package to package infonull58     fun `Test package to package info`() {
59         @Language("HTML")
60         val html =
61             """
62             <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
63             <!-- not a body tag: <body> -->
64             <html>
65             <body bgcolor="white">
66             My package docs<br>
67             <!-- comment -->
68             Sample code: /** code here */
69             Another line.<br>
70             </BODY>
71             </html>
72             """
73 
74         @Suppress("DanglingJavadoc")
75         @Language("JAVA")
76         val java =
77             """
78             /**
79              * My package docs<br>
80              * <!-- comment -->
81              * Sample code: /** code here &#42;/
82              * Another line.<br>
83              */
84             """
85 
86         assertEquals(java.trimIndent() + "\n", packageHtmlToJavadoc(html.trimIndent()))
87     }
88 
89     @Test
Relative documentation links in stubsnull90     fun `Relative documentation links in stubs`() {
91         checkStubs(
92             docStubs = false,
93             sourceFiles =
94                 arrayOf(
95                     java(
96                         """
97                     package test.pkg1;
98                     import java.io.IOException;
99                     import test.pkg2.OtherClass;
100 
101                     /**
102                      *  Blah blah {@link OtherClass} blah blah.
103                      *  Referencing <b>field</b> {@link OtherClass#foo},
104                      *  and referencing method {@link OtherClass#bar(int,
105                      *   boolean)}.
106                      *  And relative method reference {@link #baz()}.
107                      *  And relative field reference {@link #importance}.
108                      *  Here's an already fully qualified reference: {@link test.pkg2.OtherClass}.
109                      *  And here's one in the same package: {@link LocalClass}.
110                      *
111                      *  @deprecated For some reason
112                      *  @see OtherClass
113                      *  @see OtherClass#bar(int, boolean)
114                      */
115                     @SuppressWarnings("all")
116                     public class SomeClass {
117                        /**
118                        * My method.
119                        * @param focus The focus to find. One of {@link OtherClass#FOCUS_INPUT} or
120                        *         {@link OtherClass#FOCUS_ACCESSIBILITY}.
121                        * @throws IOException when blah blah blah
122                        * @throws {@link RuntimeException} when blah blah blah
123                        */
124                        public void baz(int focus) throws IOException;
125                        public boolean importance;
126                     }
127                     """
128                     ),
129                     java(
130                         """
131                     package test.pkg2;
132 
133                     @SuppressWarnings("all")
134                     public class OtherClass {
135                         public static final int FOCUS_INPUT = 1;
136                         public static final int FOCUS_ACCESSIBILITY = 2;
137                         public int foo;
138                         public void bar(int baz, boolean bar);
139                     }
140                     """
141                     ),
142                     java(
143                         """
144                     package test.pkg1;
145 
146                     @SuppressWarnings("all")
147                     public class LocalClass {
148                     }
149                     """
150                     )
151                 ),
152             warnings = "",
153             source =
154                 """
155                     package test.pkg1;
156                     import java.io.IOException;
157                     import test.pkg2.OtherClass;
158                     /**
159                      *  Blah blah {@link test.pkg2.OtherClass OtherClass} blah blah.
160                      *  Referencing <b>field</b> {@link test.pkg2.OtherClass#foo OtherClass.foo},
161                      *  and referencing method {@link test.pkg2.OtherClass#bar(int,boolean) OtherClass.bar(int,
162                      *   boolean)}.
163                      *  And relative method reference {@link #baz()}.
164                      *  And relative field reference {@link #importance}.
165                      *  Here's an already fully qualified reference: {@link test.pkg2.OtherClass}.
166                      *  And here's one in the same package: {@link test.pkg1.LocalClass LocalClass}.
167                      *
168                      *  @deprecated For some reason
169                      *  @see test.pkg2.OtherClass
170                      *  @see test.pkg2.OtherClass#bar(int, boolean)
171                      */
172                     @SuppressWarnings({"unchecked", "deprecation", "all"})
173                     @Deprecated
174                     public class SomeClass {
175                     @Deprecated
176                     public SomeClass() { throw new RuntimeException("Stub!"); }
177                     /**
178                      * My method.
179                      * @param focus The focus to find. One of {@link test.pkg2.OtherClass#FOCUS_INPUT OtherClass.FOCUS_INPUT} or
180                      *         {@link test.pkg2.OtherClass#FOCUS_ACCESSIBILITY OtherClass.FOCUS_ACCESSIBILITY}.
181                      * @throws java.io.IOException when blah blah blah
182                      * @throws {@link java.lang.RuntimeException RuntimeException} when blah blah blah
183                      */
184                     @Deprecated
185                     public void baz(int focus) throws java.io.IOException { throw new RuntimeException("Stub!"); }
186                     @Deprecated public boolean importance;
187                     }
188                     """
189         )
190     }
191 
192     @Test
Check allowReadingComments = falsenull193     fun `Check allowReadingComments = false`() {
194         checkStubs(
195             extraArguments = arrayOf(ARG_SKIP_READING_COMMENTS),
196             docStubs = false,
197             // Enable API lint to make sure that some issues will be reported.
198             apiLint = "",
199             expectedFail = DefaultLintErrorMessage,
200             // These warnings prove that lint is enabled and will report MutableBareField and
201             // MissingNullability, issues that would be reported on test.hidden.Hidden if it was not
202             // hidden by the package-info.java.
203             warnings =
204                 """
205                     src/test/pkg1/SomeClass.java:29: error: Bare field importance must be marked final, or moved behind accessors if mutable [MutableBareField]
206                     src/test/pkg2/OtherClass.java:7: error: Missing nullability on field `foo` in class `class test.pkg2.OtherClass` [MissingNullability]
207                     src/test/pkg2/OtherClass.java:7: error: Bare field foo must be marked final, or moved behind accessors if mutable [MutableBareField]
208                 """,
209             sourceFiles =
210                 arrayOf(
211                     java(
212                         """
213                     package test.pkg1;
214                     import java.io.IOException;
215                     import test.pkg2.OtherClass;
216 
217                     /**
218                      *  Blah blah {@link OtherClass} blah blah.
219                      *  Referencing <b>field</b> {@link OtherClass#foo},
220                      *  and referencing method {@link OtherClass#bar(int,
221                      *   boolean)}.
222                      *  And relative method reference {@link #baz()}.
223                      *  And relative field reference {@link #importance}.
224                      *  Here's an already fully qualified reference: {@link test.pkg2.OtherClass}.
225                      *  And here's one in the same package: {@link LocalClass}.
226                      *
227                      *  @deprecated
228                      *  @see OtherClass
229                      *  @see OtherClass#bar(int, boolean)
230                      */
231                     @SuppressWarnings("all")
232                     public class SomeClass {
233                        /**
234                        * My method.
235                        * @param focus The focus to find. One of {@link OtherClass#FOCUS_INPUT} or
236                        *         {@link OtherClass#FOCUS_ACCESSIBILITY}.
237                        * @throws IOException when blah blah blah
238                        * @throws {@link RuntimeException} when blah blah blah
239                        */
240                        public void baz(int focus) throws IOException;
241                        public boolean importance;
242                     }
243                     """
244                     ),
245                     java(
246                         """
247                     package test.pkg2;
248 
249                     @SuppressWarnings("all")
250                     public class OtherClass {
251                         public static final int FOCUS_INPUT = 1;
252                         public static final int FOCUS_ACCESSIBILITY = 2;
253                         public String foo;
254                         public void bar(int baz, boolean bar);
255                     }
256                     """
257                     ),
258                     java(
259                         """
260                     package test.pkg1;
261 
262                     @SuppressWarnings("all")
263                     public class LocalClass {
264                     }
265                     """
266                     ),
267                     // Make sure that hiding a package by using `@hide` in the Javadoc of a
268                     // package-info.java file still works when allowReadingComments = false.
269                     java(
270                         """
271                             /** @hide */
272                             package test.hidden;
273                         """
274                     ),
275                     java(
276                         """
277                             package test.hidden;
278 
279                             public class Hidden {
280                                 public String bareMutableFieldMissingNullability;
281                             }
282                         """,
283                     )
284                 ),
285             source =
286                 """
287                     package test.pkg1;
288                     @SuppressWarnings({"unchecked", "deprecation", "all"})
289                     public class SomeClass {
290                     public SomeClass() { throw new RuntimeException("Stub!"); }
291                     public void baz(int focus) throws java.io.IOException { throw new RuntimeException("Stub!"); }
292                     public boolean importance;
293                     }
294                     """
295         )
296     }
297 
298     @Test
Rewrite relative documentation links in doc-stubsnull299     fun `Rewrite relative documentation links in doc-stubs`() {
300         checkStubs(
301             docStubs = true,
302             sourceFiles =
303                 arrayOf(
304                     java(
305                         """
306                     package test.pkg1;
307                     import java.io.IOException;
308                     import test.pkg2.OtherClass;
309 
310                     /**
311                      *  Blah blah {@link OtherClass} blah blah.
312                      *  Referencing <b>field</b> {@link OtherClass#foo},
313                      *  and referencing method {@link OtherClass#bar(int,
314                      *   boolean)}.
315                      *  And relative method reference {@link #baz()}.
316                      *  And relative field reference {@link #importance}.
317                      *  Here's an already fully qualified reference: {@link test.pkg2.OtherClass}.
318                      *  And here's one in the same package: {@link LocalClass}.
319                      *
320                      *  @deprecated For some reason
321                      *  @see OtherClass
322                      *  @see OtherClass#bar(int, boolean)
323                      */
324                     @SuppressWarnings("all")
325                     public class SomeClass {
326                        /**
327                        * My method.
328                        * @param focus The focus to find. One of {@link OtherClass#FOCUS_INPUT} or
329                        *         {@link OtherClass#FOCUS_ACCESSIBILITY}.
330                        * @throws java.io.IOException when blah blah blah
331                        * @throws {@link java.lang.RuntimeException} when blah blah blah
332                        */
333                        public void baz(int focus) throws IOException;
334                        public boolean importance;
335                     }
336                     """
337                     ),
338                     java(
339                         """
340                     package test.pkg2;
341 
342                     @SuppressWarnings("all")
343                     public class OtherClass {
344                         public static final int FOCUS_INPUT = 1;
345                         public static final int FOCUS_ACCESSIBILITY = 2;
346                         public int foo;
347                         public void bar(int baz, boolean bar);
348                     }
349                     """
350                     ),
351                     java(
352                         """
353                     package test.pkg1;
354 
355                     @SuppressWarnings("all")
356                     public class LocalClass {
357                     }
358                     """
359                     )
360                 ),
361             warnings = "",
362             source =
363                 """
364                 package test.pkg1;
365                 import java.io.IOException;
366                 import test.pkg2.OtherClass;
367                 /**
368                  *  Blah blah {@link test.pkg2.OtherClass OtherClass} blah blah.
369                  *  Referencing <b>field</b> {@link test.pkg2.OtherClass#foo OtherClass.foo},
370                  *  and referencing method {@link test.pkg2.OtherClass#bar(int,boolean) OtherClass.bar(int,
371                  *   boolean)}.
372                  *  And relative method reference {@link #baz()}.
373                  *  And relative field reference {@link #importance}.
374                  *  Here's an already fully qualified reference: {@link test.pkg2.OtherClass}.
375                  *  And here's one in the same package: {@link test.pkg1.LocalClass LocalClass}.
376                  *
377                  *  @deprecated For some reason
378                  *  @see test.pkg2.OtherClass
379                  *  @see test.pkg2.OtherClass#bar(int, boolean)
380                  */
381                 @SuppressWarnings({"unchecked", "deprecation", "all"})
382                 @Deprecated
383                 public class SomeClass {
384                 @Deprecated
385                 public SomeClass() { throw new RuntimeException("Stub!"); }
386                 /**
387                  * My method.
388                  * @param focus The focus to find. One of {@link test.pkg2.OtherClass#FOCUS_INPUT OtherClass.FOCUS_INPUT} or
389                  *         {@link test.pkg2.OtherClass#FOCUS_ACCESSIBILITY OtherClass.FOCUS_ACCESSIBILITY}.
390                  * @throws java.io.IOException when blah blah blah
391                  * @throws {@link java.lang.RuntimeException} when blah blah blah
392                  */
393                 @Deprecated
394                 public void baz(int focus) throws java.io.IOException { throw new RuntimeException("Stub!"); }
395                 @Deprecated public boolean importance;
396                 }
397                 """
398         )
399     }
400 
401     @Test
Rewrite relative documentation links in doc-stubs 2null402     fun `Rewrite relative documentation links in doc-stubs 2`() {
403         // Properly handle links to inherited methods
404         checkStubs(
405             docStubs = true,
406             sourceFiles =
407                 arrayOf(
408                     java(
409                         """
410                     package test.pkg1;
411                     import java.io.IOException;
412 
413                     @SuppressWarnings("all")
414                     public class R {
415                         public static class attr {
416                             /**
417                              * Resource identifier to assign to this piece of named meta-data.
418                              * The resource identifier can later be retrieved from the meta data
419                              * Bundle through {@link android.os.Bundle#getInt Bundle.getInt}.
420                              * <p>May be a reference to another resource, in the form
421                              * "<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>" or a theme
422                              * attribute in the form
423                              * "<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>".
424                              */
425                             public static final int resource=0x01010025;
426                         }
427                     }
428                     """
429                     ),
430                     java(
431                         """
432                     package android.os;
433 
434                     @SuppressWarnings("all")
435                     public class Bundle extends BaseBundle {
436                     }
437                     """
438                     ),
439                     java(
440                         """
441                     package android.os;
442 
443                     @SuppressWarnings("all")
444                     public class BaseBundle {
445                         public int getInt(String key) {
446                             return getInt(key, 0);
447                         }
448 
449                         public int getInt(String key, int defaultValue) {
450                             return defaultValue;
451                         }
452                     }
453                     """
454                     )
455                 ),
456             warnings = "",
457             source =
458                 """
459                 package test.pkg1;
460                 @SuppressWarnings({"unchecked", "deprecation", "all"})
461                 public class R {
462                 public R() { throw new RuntimeException("Stub!"); }
463                 @SuppressWarnings({"unchecked", "deprecation", "all"})
464                 public static class attr {
465                 public attr() { throw new RuntimeException("Stub!"); }
466                 /**
467                  * Resource identifier to assign to this piece of named meta-data.
468                  * The resource identifier can later be retrieved from the meta data
469                  * Bundle through {@link android.os.Bundle#getInt Bundle.getInt}.
470                  * <p>May be a reference to another resource, in the form
471                  * "<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>" or a theme
472                  * attribute in the form
473                  * "<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>".
474                  */
475                 public static final int resource = 16842789; // 0x1010025
476                 }
477                 }
478                 """
479         )
480     }
481 
482     @Test
Rewrite relative documentation links in doc-stubs 3null483     fun `Rewrite relative documentation links in doc-stubs 3`() {
484         checkStubs(
485             docStubs = true,
486             sourceFiles =
487                 arrayOf(
488                     java(
489                         """
490                     package android.accessibilityservice;
491 
492                     import android.view.accessibility.AccessibilityEvent;
493                     import android.view.accessibility.AccessibilityRecord;
494 
495                     /**
496                      * <p>
497                      * Window content may be retrieved with
498                      * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()}.
499                      * Mention AccessibilityRecords here.
500                      * </p>
501                      */
502                     @SuppressWarnings("all")
503                     public abstract class AccessibilityService {
504                     }
505                     """
506                     ),
507                     java(
508                         """
509                     package android.view.accessibility;
510 
511                     @SuppressWarnings("all")
512                     public final class AccessibilityEvent extends AccessibilityRecord {
513                     }
514                     """
515                     ),
516                     java(
517                         """
518                     package android.view.accessibility;
519 
520                     @SuppressWarnings("all")
521                     public class AccessibilityRecord {
522                         public AccessibilityNodeInfo getSource() {
523                             return null;
524                         }
525                     }
526                     """
527                     ),
528                     java(
529                         """
530                     package android.view.accessibility;
531                     public class AccessibilityNodeInfo {}
532                     """
533                     )
534                 ),
535             warnings = "",
536             source =
537                 """
538                 package android.accessibilityservice;
539                 import android.view.accessibility.AccessibilityEvent;
540                 /**
541                  * <p>
542                  * Window content may be retrieved with
543                  * {@link android.view.accessibility.AccessibilityEvent#getSource() AccessibilityEvent.getSource()}.
544                  * Mention AccessibilityRecords here.
545                  * </p>
546                  */
547                 @SuppressWarnings({"unchecked", "deprecation", "all"})
548                 public abstract class AccessibilityService {
549                 public AccessibilityService() { throw new RuntimeException("Stub!"); }
550                 }
551                 """
552         )
553     }
554 
555     @Test
Rewrite relative documentation links in doc-stubs but preserve custom link textnull556     fun `Rewrite relative documentation links in doc-stubs but preserve custom link text`() {
557         checkStubs(
558             docStubs = true,
559             sourceFiles =
560                 arrayOf(
561                     java(
562                         """
563                     package android.accessibilityservice;
564 
565                     import android.view.accessibility.AccessibilityEvent;
566                     import android.view.accessibility.AccessibilityRecord;
567 
568                     /**
569                      * <p>
570                      * Window content may be retrieved with
571                      * {@link AccessibilityEvent#getSource() this_method}.
572                      * Mention AccessibilityRecords here.
573                      * </p>
574                      */
575                     @SuppressWarnings("all")
576                     public abstract class AccessibilityService {
577                     }
578                     """
579                     ),
580                     java(
581                         """
582                     package android.view.accessibility;
583 
584                     @SuppressWarnings("all")
585                     public final class AccessibilityEvent extends AccessibilityRecord {
586                     }
587                     """
588                     ),
589                     java(
590                         """
591                     package android.view.accessibility;
592 
593                     @SuppressWarnings("all")
594                     public class AccessibilityRecord {
595                         public AccessibilityNodeInfo getSource() {
596                             return null;
597                         }
598                     }
599                     """
600                     ),
601                     java(
602                         """
603                     package android.view.accessibility;
604                     public class AccessibilityNodeInfo {}
605                     """
606                     )
607                 ),
608             warnings = "",
609             source =
610                 """
611                 package android.accessibilityservice;
612                 import android.view.accessibility.AccessibilityEvent;
613                 /**
614                  * <p>
615                  * Window content may be retrieved with
616                  * {@link android.view.accessibility.AccessibilityEvent#getSource() this_method}.
617                  * Mention AccessibilityRecords here.
618                  * </p>
619                  */
620                 @SuppressWarnings({"unchecked", "deprecation", "all"})
621                 public abstract class AccessibilityService {
622                 public AccessibilityService() { throw new RuntimeException("Stub!"); }
623                 }
624                 """
625         )
626     }
627 
628     @Test
Rewrite relative documentation links in doc-stubs 4null629     fun `Rewrite relative documentation links in doc-stubs 4`() {
630         checkStubs(
631             docStubs = true,
632             sourceFiles =
633                 arrayOf(
634                     java(
635                         """
636                     package android.content;
637 
638                     import android.os.OperationCanceledException;
639 
640                     @SuppressWarnings("all")
641                     public abstract class AsyncTaskLoader<D> {
642                         /**
643                          * Called if the task was canceled before it was completed.  Gives the class a chance
644                          * to clean up post-cancellation and to properly dispose of the result.
645                          *
646                          * @param data The value that was returned by {@link #loadInBackground}, or null
647                          * if the task threw {@link OperationCanceledException}.
648                          */
649                         public void onCanceled(D data) {
650                         }
651 
652                         /**
653                          * Called on a worker thread to perform the actual load and to return
654                          * the result of the load operation.
655                          *
656                          * Implementations should not deliver the result directly, but should return them
657                          * from this method, which will eventually end up calling {@link #deliverResult} on
658                          * the UI thread.  If implementations need to process the results on the UI thread
659                          * they may override {@link #deliverResult} and do so there.
660                          *
661                          * When the load is canceled, this method may either return normally or throw
662                          * {@link OperationCanceledException}.  In either case, the Loader will
663                          * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
664                          * result object, if any.
665                          *
666                          * @return The result of the load operation.
667                          *
668                          * @throws OperationCanceledException if the load is canceled during execution.
669                          *
670                          * @see #onCanceled
671                          */
672                         public abstract Object loadInBackground();
673 
674                         /**
675                          * Sends the result of the load to the registered listener. Should only be called by subclasses.
676                          *
677                          * Must be called from the process's main thread.
678                          *
679                          * @param data the result of the load
680                          */
681                         public void deliverResult(Object data) {
682                         }
683                     }
684                     """
685                     ),
686                     java(
687                         """
688                     package android.os;
689 
690 
691                     /**
692                      * An exception type that is thrown when an operation in progress is canceled.
693                      */
694                     @SuppressWarnings("all")
695                     public class OperationCanceledException extends RuntimeException {
696                         public OperationCanceledException() {
697                             this(null);
698                         }
699 
700                         public OperationCanceledException(String message) {
701                             super(message != null ? message : "The operation has been canceled.");
702                         }
703                     }
704                     """
705                     )
706                 ),
707             warnings = "",
708             source =
709                 """
710                 package android.content;
711                 import android.os.OperationCanceledException;
712                 @SuppressWarnings({"unchecked", "deprecation", "all"})
713                 public abstract class AsyncTaskLoader<D> {
714                 public AsyncTaskLoader() { throw new RuntimeException("Stub!"); }
715                 /**
716                  * Sends the result of the load to the registered listener. Should only be called by subclasses.
717                  *
718                  * Must be called from the process's main thread.
719                  *
720                  * @param data the result of the load
721                  */
722                 public void deliverResult(java.lang.Object data) { throw new RuntimeException("Stub!"); }
723                 /**
724                  * Called on a worker thread to perform the actual load and to return
725                  * the result of the load operation.
726                  *
727                  * Implementations should not deliver the result directly, but should return them
728                  * from this method, which will eventually end up calling {@link #deliverResult} on
729                  * the UI thread.  If implementations need to process the results on the UI thread
730                  * they may override {@link #deliverResult} and do so there.
731                  *
732                  * When the load is canceled, this method may either return normally or throw
733                  * {@link android.os.OperationCanceledException OperationCanceledException}.  In either case, the Loader will
734                  * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
735                  * result object, if any.
736                  *
737                  * @return The result of the load operation.
738                  *
739                  * @throws android.os.OperationCanceledException if the load is canceled during execution.
740                  *
741                  * @see #onCanceled
742                  */
743                 public abstract java.lang.Object loadInBackground();
744                 /**
745                  * Called if the task was canceled before it was completed.  Gives the class a chance
746                  * to clean up post-cancellation and to properly dispose of the result.
747                  *
748                  * @param data The value that was returned by {@link #loadInBackground}, or null
749                  * if the task threw {@link android.os.OperationCanceledException OperationCanceledException}.
750                  */
751                 public void onCanceled(D data) { throw new RuntimeException("Stub!"); }
752                 }
753                 """
754         )
755     }
756 
757     @Test
Rewrite relative documentation links in doc-stubs 5null758     fun `Rewrite relative documentation links in doc-stubs 5`() {
759         // Properly handle links to inherited methods
760         checkStubs(
761             docStubs = true,
762             sourceFiles =
763                 arrayOf(
764                     java(
765                         """
766                     package org.xmlpull.v1;
767 
768                     /**
769                      * Example docs.
770                      * <pre>
771                      * import org.xmlpull.v1.<a href="XmlPullParserException.html">XmlPullParserException</a>;
772                      *         xpp.<a href="#setInput">setInput</a>( new StringReader ( "&lt;foo>Hello World!&lt;/foo>" ) );
773                      * </pre>
774                      * see #setInput
775                      */
776                     @SuppressWarnings("all")
777                     public interface XmlPullParser {
778                         void setInput();
779                     }
780                     """
781                     )
782                 ),
783             warnings = "",
784             source =
785                 """
786                 package org.xmlpull.v1;
787                 /**
788                  * Example docs.
789                  * <pre>
790                  * import org.xmlpull.v1.<a href="XmlPullParserException.html">XmlPullParserException</a>;
791                  *         xpp.<a href="#setInput">setInput</a>( new StringReader ( "&lt;foo>Hello World!&lt;/foo>" ) );
792                  * </pre>
793                  * see #setInput
794                  */
795                 @SuppressWarnings({"unchecked", "deprecation", "all"})
796                 public interface XmlPullParser {
797                 public void setInput();
798                 }
799                 """
800         )
801     }
802 
803     @Test
Check references to inherited field constantsnull804     fun `Check references to inherited field constants`() {
805         checkStubs(
806             docStubs = true,
807             warnings = "",
808             sourceFiles =
809                 arrayOf(
810                     java(
811                         """
812                     package test.pkg1;
813                     import test.pkg2.MyChild;
814 
815                     /**
816                      * Reference to {@link MyChild#CONSTANT1},
817                      * {@link MyChild#CONSTANT2}, and
818                      * {@link MyChild#myMethod}.
819                      * <p>
820                      * Absolute reference:
821                      * {@link test.pkg2.MyChild#CONSTANT1 MyChild.CONSTANT1}
822                      * <p>
823                      * Inner class reference:
824                      * {@link Test.TestInner#CONSTANT3}, again
825                      * {@link TestInner#CONSTANT3}
826                      *
827                      * @see test.pkg2.MyChild#myMethod
828                      */
829                     @SuppressWarnings("all")
830                     public class Test {
831                         public static class TestInner {
832                             public static final String CONSTANT3 = "Hello";
833                         }
834                     }
835                     """
836                     ),
837                     java(
838                         """
839                     package test.pkg1;
840                     @SuppressWarnings("all")
841                     interface MyConstants {
842                         long CONSTANT1 = 12345;
843                     }
844                     """
845                     ),
846                     java(
847                         """
848                     package test.pkg1;
849                     import java.io.Closeable;
850                     @SuppressWarnings("all")
851                     class MyParent implements MyConstants, Closeable {
852                         public static final long CONSTANT2 = 67890;
853                         public void myMethod() {
854                         }
855                     }
856                     """
857                     ),
858                     java(
859                         """
860                     package test.pkg2;
861 
862                     import test.pkg1.MyParent;
863                     @SuppressWarnings("all")
864                     public class MyChild extends MyParent implements MyConstants {
865                         @Override
866                         public void close() {}
867                     }
868                     """
869                     )
870                 ),
871             source =
872                 """
873                 package test.pkg1;
874                 import test.pkg2.MyChild;
875                 /**
876                  * Reference to {@link test.pkg2.MyChild#CONSTANT1 MyChild.CONSTANT1},
877                  * {@link test.pkg2.MyChild#CONSTANT2 MyChild.CONSTANT2}, and
878                  * {@link test.pkg2.MyChild#myMethod MyChild.myMethod}.
879                  * <p>
880                  * Absolute reference:
881                  * {@link test.pkg2.MyChild#CONSTANT1 MyChild.CONSTANT1}
882                  * <p>
883                  * Inner class reference:
884                  * {@link test.pkg1.Test.TestInner#CONSTANT3 Test.TestInner.CONSTANT3}, again
885                  * {@link test.pkg1.Test.TestInner#CONSTANT3 TestInner.CONSTANT3}
886                  *
887                  * @see test.pkg2.MyChild#myMethod
888                  */
889                 @SuppressWarnings({"unchecked", "deprecation", "all"})
890                 public class Test {
891                 public Test() { throw new RuntimeException("Stub!"); }
892                 @SuppressWarnings({"unchecked", "deprecation", "all"})
893                 public static class TestInner {
894                 public TestInner() { throw new RuntimeException("Stub!"); }
895                 public static final java.lang.String CONSTANT3 = "Hello";
896                 }
897                 }
898                 """
899         )
900     }
901 
902     @Test
Rewrite parameter listnull903     fun `Rewrite parameter list`() {
904         checkStubs(
905             docStubs = true,
906             warnings = "",
907             sourceFiles =
908                 arrayOf(
909                     java(
910                         """
911                     package test.pkg1;
912                     import test.pkg2.OtherClass1;
913                     import test.pkg2.OtherClass2;
914 
915                     /**
916                      * Reference to {@link OtherClass1#myMethod(OtherClass2, int name, OtherClass2[])},
917                      */
918                     @SuppressWarnings("all")
919                     public class Test<E extends OtherClass2> {
920                         /**
921                          * Reference to {@link OtherClass1#myMethod(E, int, OtherClass2 [])},
922                          */
923                         public void test() { }
924                     }
925                     """
926                     ),
927                     java(
928                         """
929                     package test.pkg2;
930 
931                     @SuppressWarnings("all")
932                     class OtherClass1 {
933                         public void myMethod(OtherClass2 parameter1, int parameter2, OtherClass2[] parameter3) {
934                         }
935                     }
936                     """
937                     ),
938                     java(
939                         """
940                     package test.pkg2;
941 
942                     @SuppressWarnings("all")
943                     public class OtherClass2 {
944                     }
945                     """
946                     )
947                 ),
948             source =
949                 """
950                 package test.pkg1;
951                 import test.pkg2.OtherClass2;
952                 /**
953                  * Reference to {@link test.pkg2.OtherClass1#myMethod(test.pkg2.OtherClass2,int name,test.pkg2.OtherClass2[]) OtherClass1.myMethod(OtherClass2, int name, OtherClass2[])},
954                  */
955                 @SuppressWarnings({"unchecked", "deprecation", "all"})
956                 public class Test<E extends test.pkg2.OtherClass2> {
957                 public Test() { throw new RuntimeException("Stub!"); }
958                 /**
959                  * Reference to {@link test.pkg2.OtherClass1#myMethod(E,int,test.pkg2.OtherClass2[]) OtherClass1.myMethod(E, int, OtherClass2 [])},
960                  */
961                 public void test() { throw new RuntimeException("Stub!"); }
962                 }
963                 """
964         )
965     }
966 
967     @Test
Rewrite parameter list 2null968     fun `Rewrite parameter list 2`() {
969         checkStubs(
970             docStubs = true,
971             warnings = "",
972             sourceFiles =
973                 arrayOf(
974                     java(
975                         """
976                     package test.pkg1;
977                     import java.nio.ByteBuffer;
978 
979                     @SuppressWarnings("all")
980                     public abstract class Test {
981                         /**
982                          * Blah blah
983                          * <blockquote><pre>
984                          * {@link #wrap(ByteBuffer [], int, int, ByteBuffer)
985                          *     engine.wrap(new ByteBuffer [] { src }, 0, 1, dst);}
986                          * </pre></blockquote>
987                          */
988                         public void test() { }
989 
990                         public abstract void wrap(ByteBuffer [] srcs, int offset,
991                             int length, ByteBuffer dst);
992                     }
993                     """
994                     )
995                 ),
996             source =
997                 """
998                 package test.pkg1;
999                 import java.nio.ByteBuffer;
1000                 @SuppressWarnings({"unchecked", "deprecation", "all"})
1001                 public abstract class Test {
1002                 public Test() { throw new RuntimeException("Stub!"); }
1003                 /**
1004                  * Blah blah
1005                  * <blockquote><pre>
1006                  * {@link #wrap(java.nio.ByteBuffer[],int,int,java.nio.ByteBuffer)
1007                  *     engine.wrap(new ByteBuffer [] { src }, 0, 1, dst);}
1008                  * </pre></blockquote>
1009                  */
1010                 public void test() { throw new RuntimeException("Stub!"); }
1011                 public abstract void wrap(java.nio.ByteBuffer[] srcs, int offset, int length, java.nio.ByteBuffer dst);
1012                 }
1013                 """
1014         )
1015     }
1016 
1017     @Test
Warn about unresolvednull1018     fun `Warn about unresolved`() {
1019         @Suppress("ConstantConditionIf")
1020         checkStubs(
1021             docStubs = true,
1022             warnings =
1023                 if (REPORT_UNRESOLVED_SYMBOLS) {
1024                     """
1025                 src/test/pkg1/Test.java:6: lint: Unresolved documentation reference: SomethingMissing [UnresolvedLink]
1026                 src/test/pkg1/Test.java:6: lint: Unresolved documentation reference: OtherMissing [UnresolvedLink]
1027             """
1028                 } else {
1029                     ""
1030                 },
1031             sourceFiles =
1032                 arrayOf(
1033                     java(
1034                         """
1035                     package test.pkg1;
1036                     import java.nio.ByteBuffer;
1037 
1038                     @SuppressWarnings("all")
1039                     public class Test {
1040                         /**
1041                          * Reference to {@link SomethingMissing} and
1042                          * {@link String#randomMethod}.
1043                          *
1044                          * @see OtherMissing
1045                          */
1046                         public void test() { }
1047                     }
1048                     """
1049                     )
1050                 ),
1051             source =
1052                 """
1053                 package test.pkg1;
1054                 @SuppressWarnings({"unchecked", "deprecation", "all"})
1055                 public class Test {
1056                 public Test() { throw new RuntimeException("Stub!"); }
1057                 /**
1058                  * Reference to {@link SomethingMissing} and
1059                  * {@link java.lang.String#randomMethod String.randomMethod}.
1060                  *
1061                  * @see OtherMissing
1062                  */
1063                 public void test() { throw new RuntimeException("Stub!"); }
1064                 }
1065                 """
1066         )
1067     }
1068 
1069     @Test
Javadoc link to innerclass constructornull1070     fun `Javadoc link to innerclass constructor`() {
1071         check(
1072             sourceFiles =
1073                 arrayOf(
1074                     java(
1075                         """
1076                     package android.view;
1077                     import android.graphics.Insets;
1078 
1079                     public final class WindowInsets {
1080                         /**
1081                          * Returns a copy of this WindowInsets with selected system window insets replaced
1082                          * with new values.
1083                          *
1084                          * @param left New left inset in pixels
1085                          * @param top New top inset in pixels
1086                          * @param right New right inset in pixels
1087                          * @param bottom New bottom inset in pixels
1088                          * @return A modified copy of this WindowInsets
1089                          * @deprecated use {@link Builder#Builder(WindowInsets)} with
1090                          *             {@link Builder#setSystemWindowInsets(Insets)} instead.
1091                          */
1092                         @Deprecated
1093                         public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) {
1094 
1095                         }
1096 
1097                         public static class Builder {
1098                             public Builder() {
1099                             }
1100 
1101                             public Builder(WindowInsets insets) {
1102                             }
1103 
1104                             public Builder setSystemWindowInsets(Insets systemWindowInsets) {
1105                                 return this;
1106                             }
1107                         }
1108                     }
1109                     """
1110                     ),
1111                     java(
1112                         """
1113                     package android.graphics;
1114                     public class Insets {
1115                     }
1116                     """
1117                     )
1118                 ),
1119             docStubs = true,
1120             stubFiles =
1121                 arrayOf(
1122                     java(
1123                         """
1124                     package android.view;
1125                     import android.graphics.Insets;
1126                     @SuppressWarnings({"unchecked", "deprecation", "all"})
1127                     public final class WindowInsets {
1128                     public WindowInsets() { throw new RuntimeException("Stub!"); }
1129                     /**
1130                      * Returns a copy of this WindowInsets with selected system window insets replaced
1131                      * with new values.
1132                      *
1133                      * @param left New left inset in pixels
1134                      * @param top New top inset in pixels
1135                      * @param right New right inset in pixels
1136                      * @param bottom New bottom inset in pixels
1137                      * @return A modified copy of this WindowInsets
1138                      * @deprecated use {@link android.view.WindowInsets.Builder#Builder(android.view.WindowInsets) Builder.Builder(WindowInsets)} with
1139                      *             {@link android.view.WindowInsets.Builder#setSystemWindowInsets(android.graphics.Insets) Builder.setSystemWindowInsets(Insets)} instead.
1140                      */
1141                     @Deprecated
1142                     public android.view.WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) { throw new RuntimeException("Stub!"); }
1143                     @SuppressWarnings({"unchecked", "deprecation", "all"})
1144                     public static class Builder {
1145                     public Builder() { throw new RuntimeException("Stub!"); }
1146                     public Builder(android.view.WindowInsets insets) { throw new RuntimeException("Stub!"); }
1147                     public android.view.WindowInsets.Builder setSystemWindowInsets(android.graphics.Insets systemWindowInsets) { throw new RuntimeException("Stub!"); }
1148                     }
1149                     }
1150                     """
1151                     )
1152                 )
1153         )
1154     }
1155 
1156     @Test
Ensure references to classes in JavaDoc of hidden members do not affect importsnull1157     fun `Ensure references to classes in JavaDoc of hidden members do not affect imports`() {
1158         check(
1159             sourceFiles =
1160                 arrayOf(
1161                     java(
1162                         """
1163                     package test.pkg;
1164                     import test.pkg.bar.Bar;
1165                     import test.pkg.baz.Baz;
1166                     public class Foo {
1167                         /**
1168                          * This method is hidden so the reference to {@link Baz} in this comment
1169                          * should not cause test.pkg.baz.Baz import to be added even though Baz is
1170                          * part of the API.
1171                          * @hide
1172                          */
1173                         public void baz() {}
1174 
1175                         /**
1176                          * @see Bar
1177                          */
1178                         public void bar() {}
1179                     }
1180                     """
1181                     ),
1182                     java(
1183                         """
1184                     package test.pkg.bar;
1185                     import test.pkg.Foo;
1186                     import test.pkg.baz.Baz;
1187                     public class Bar {
1188                         /** @see Baz */
1189                         public void baz(Baz baz) {}
1190                         /** @see Foo */
1191                         public void foo(Foo foo) {}
1192                     }
1193                     """
1194                     ),
1195                     java(
1196                         """
1197                     package test.pkg.baz;
1198                     public class Baz {
1199                     }
1200                     """
1201                     )
1202                 ),
1203             stubFiles =
1204                 arrayOf(
1205                     java(
1206                         """
1207                     package test.pkg;
1208                     import test.pkg.bar.Bar;
1209                     @SuppressWarnings({"unchecked", "deprecation", "all"})
1210                     public class Foo {
1211                     public Foo() { throw new RuntimeException("Stub!"); }
1212                     /**
1213                      * @see test.pkg.bar.Bar
1214                      */
1215                     public void bar() { throw new RuntimeException("Stub!"); }
1216                     }
1217                     """
1218                     ),
1219                     java(
1220                         """
1221                     package test.pkg.bar;
1222                     import test.pkg.Foo;
1223                     import test.pkg.baz.Baz;
1224                     @SuppressWarnings({"unchecked", "deprecation", "all"})
1225                     public class Bar {
1226                     public Bar() { throw new RuntimeException("Stub!"); }
1227                     /** @see test.pkg.baz.Baz */
1228                     public void baz(test.pkg.baz.Baz baz) { throw new RuntimeException("Stub!"); }
1229                     /** @see test.pkg.Foo */
1230                     public void foo(test.pkg.Foo foo) { throw new RuntimeException("Stub!"); }
1231                     }
1232                     """
1233                     ),
1234                     java(
1235                         """
1236                     package test.pkg.baz;
1237                     @SuppressWarnings({"unchecked", "deprecation", "all"})
1238                     public class Baz {
1239                     public Baz() { throw new RuntimeException("Stub!"); }
1240                     }
1241                     """
1242                     )
1243                 )
1244         )
1245     }
1246 }
1247