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