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 */ 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 ( "<foo>Hello World!</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 ( "<foo>Hello World!</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