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