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