1 /* 2 * Copyright (C) 2017 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 @file:Suppress("ALL") 18 19 package com.android.tools.metalava 20 21 import org.junit.Test 22 23 class ApiFileTest : DriverTest() { 24 /* 25 Conditions to test: 26 - test all the error scenarios found in the notStrippable case! 27 - split up test into many individual test cases 28 - try referencing a class from an annotation! 29 - test having a throws list where some exceptions are hidden but extend 30 public exceptions: do we map over to the referenced ones? 31 32 - test type reference from all the possible places -- in type signatures - interfaces, 33 extends, throws, type bounds, etc. 34 - method which overrides @hide method: should appear in subclass (test chain 35 of two nested too) 36 - BluetoothGattCharacteristic.java#describeContents: Was marked @hide, 37 but is unhidden because it extends a public interface method 38 - package javadoc (also make sure merging both!, e.g. try having @hide in each) 39 - StopWatchMap -- inner class with @hide marks allh top levels! 40 - Test field inlining: should I include fields from an interface, if that 41 inteface was implemented by the parent class (and therefore appears there too?) 42 What if the superclass is abstract? 43 - Exposing package private classes. Test that I only do this for package private 44 classes, NOT Those marked @hide (is that, having @hide on a used type, illegal?) 45 - Test error handling (invalid @hide combinations)) 46 - Consider what happens if we promote a package private class (because it's 47 extended by a public class), and then we restore its public members; the 48 override logic there isn't quite right. We've duplicated the significant-override 49 code to not skip private members, but that could change semantics. This isn't 50 ideal; instead we should now mark this class as public, and re-run the analysis 51 again (with the new hidden state for this class). 52 - compilation unit sorting - top level classes out of order 53 - Massive classes such as android.R.java? Maybe do synthetic test. 54 - HttpResponseCache implemented a public OkHttp interface, but the sole implementation 55 method was marked @hide, so the method doesn't show up. Is that some other rule -- 56 that we skip interfaces if their implementation methods are marked @hide? 57 - Test recursive package filtering. 58 */ 59 60 @Test Basic class signature extractionnull61 fun `Basic class signature extraction`() { 62 // Basic class; also checks that default constructor is made explicit 63 check( 64 sourceFiles = *arrayOf( 65 java( 66 """ 67 package test.pkg; 68 public class Foo { 69 } 70 """ 71 ) 72 ), 73 api = """ 74 package test.pkg { 75 public class Foo { 76 ctor public Foo(); 77 } 78 } 79 """ 80 ) 81 } 82 83 @Test Parameter Names in Javanull84 fun `Parameter Names in Java`() { 85 // Java code which explicitly specifies parameter names 86 check( 87 sourceFiles = *arrayOf( 88 java( 89 """ 90 package test.pkg; 91 import androidx.annotation.ParameterName; 92 93 public class Foo { 94 public void foo(int javaParameter1, @ParameterName("publicParameterName") int javaParameter2) { 95 } 96 } 97 """ 98 ), 99 supportParameterName 100 ), 101 api = """ 102 package test.pkg { 103 public class Foo { 104 ctor public Foo(); 105 method public void foo(int, int publicParameterName); 106 } 107 } 108 """, 109 extraArguments = arrayOf("--hide-package", "androidx.annotation"), 110 checkDoclava1 = false /* doesn't support parameter names */ 111 ) 112 } 113 114 @Test Default Values Names in Javanull115 fun `Default Values Names in Java`() { 116 // Java code which explicitly specifies parameter names 117 check( 118 compatibilityMode = false, 119 sourceFiles = *arrayOf( 120 java( 121 """ 122 package test.pkg; 123 import androidx.annotation.DefaultValue; 124 125 public class Foo { 126 public void foo( 127 @DefaultValue("null") String prefix, 128 @DefaultValue("\"Hello World\"") String greeting, 129 @DefaultValue("42") int meaning) { 130 } 131 } 132 """ 133 ), 134 supportDefaultValue 135 ), 136 api = """ 137 package test.pkg { 138 public class Foo { 139 ctor public Foo(); 140 method public void foo(String! = "null", String! = "\"Hello World\"", int = "42"); 141 } 142 } 143 """, 144 extraArguments = arrayOf("--hide-package", "androidx.annotation"), 145 checkDoclava1 = false /* doesn't support default Values */ 146 ) 147 } 148 149 @Test Default Values and Names in Kotlinnull150 fun `Default Values and Names in Kotlin`() { 151 // Kotlin code which explicitly specifies parameter names 152 check( 153 compatibilityMode = false, 154 sourceFiles = *arrayOf( 155 kotlin( 156 """ 157 package test.pkg 158 159 class Foo { 160 fun error(int: Int = 42, int2: Int? = null, byte: Int = 42) { } 161 } 162 """ 163 ) 164 ), 165 api = """ 166 package test.pkg { 167 public final class Foo { 168 ctor public Foo(); 169 method public void error(int p = "42", Integer? int2 = "null", int p1 = "42"); 170 } 171 } 172 """, 173 extraArguments = arrayOf("--hide-package", "androidx.annotation"), 174 checkDoclava1 = false /* doesn't support default Values */ 175 ) 176 } 177 178 @Test Basic Kotlin classnull179 fun `Basic Kotlin class`() { 180 check( 181 sourceFiles = *arrayOf( 182 kotlin( 183 """ 184 package test.pkg 185 class Kotlin(val property1: String = "Default Value", arg2: Int) : Parent() { 186 override fun method() = "Hello World" 187 fun otherMethod(ok: Boolean, times: Int) { 188 } 189 190 var property2: String? = null 191 192 private var someField = 42 193 @JvmField 194 var someField2 = 42 195 196 internal var myHiddenVar = false 197 internal fun myHiddenMethod(): Unit { } 198 internal data class myHiddenClass(): Unit { } 199 200 companion object { 201 const val MY_CONST = 42 202 } 203 } 204 205 open class Parent { 206 open fun method(): String? = null 207 open fun method2(value: Boolean, value: Boolean?): String? = null 208 open fun method3(value: Int?, value2: Int): Int = null 209 } 210 """ 211 ) 212 ), 213 api = """ 214 package test.pkg { 215 public final class Kotlin extends test.pkg.Parent { 216 ctor public Kotlin(java.lang.String property1, int arg2); 217 method public java.lang.String getProperty1(); 218 method public java.lang.String getProperty2(); 219 method public void otherMethod(boolean ok, int times); 220 method public void setProperty2(java.lang.String p); 221 field public static final test.pkg.Kotlin.Companion Companion; 222 field public static final int MY_CONST = 42; // 0x2a 223 field public int someField2; 224 } 225 public static final class Kotlin.Companion { 226 } 227 public class Parent { 228 ctor public Parent(); 229 method public java.lang.String method(); 230 method public java.lang.String method2(boolean value, java.lang.Boolean value); 231 method public int method3(java.lang.Integer value, int value2); 232 } 233 } 234 """, 235 privateApi = """ 236 package test.pkg { 237 public final class Kotlin extends test.pkg.Parent { 238 method internal boolean getMyHiddenVar${"$"}lintWithKotlin(); 239 method internal void myHiddenMethod${"$"}lintWithKotlin(); 240 method internal void setMyHiddenVar${"$"}lintWithKotlin(boolean p); 241 field internal boolean myHiddenVar; 242 field private final java.lang.String property1; 243 field private java.lang.String property2; 244 field private int someField; 245 } 246 public static final class Kotlin.Companion { 247 ctor private Kotlin.Companion(); 248 } 249 internal static final class Kotlin.myHiddenClass extends kotlin.Unit { 250 ctor public Kotlin.myHiddenClass(); 251 method internal test.pkg.Kotlin.myHiddenClass copy(); 252 } 253 } 254 """, 255 checkDoclava1 = false /* doesn't support Kotlin... */ 256 ) 257 } 258 259 @Test Kotlin Reified Methodsnull260 fun `Kotlin Reified Methods`() { 261 check( 262 sourceFiles = *arrayOf( 263 java( 264 """ 265 package test.pkg; 266 267 public class Context { 268 @SuppressWarnings("unchecked") 269 public final <T> T getSystemService(Class<T> serviceClass) { 270 return null; 271 } 272 } 273 """ 274 ), 275 kotlin( 276 """ 277 package test.pkg 278 279 inline fun <reified T> Context.systemService1() = getSystemService(T::class.java) 280 inline fun Context.systemService2() = getSystemService(String::class.java) 281 """ 282 ) 283 ), 284 api = """ 285 package test.pkg { 286 public class Context { 287 ctor public Context(); 288 method public final <T> T getSystemService(java.lang.Class<T>); 289 } 290 public final class _java_Kt { 291 ctor public _java_Kt(); 292 method public static java.lang.String systemService2(test.pkg.Context); 293 } 294 } 295 """, 296 checkDoclava1 = false /* doesn't support Kotlin... */ 297 ) 298 } 299 300 @Test Propagate Platform types in Kotlinnull301 fun `Propagate Platform types in Kotlin`() { 302 check( 303 compatibilityMode = false, 304 outputKotlinStyleNulls = true, 305 sourceFiles = *arrayOf( 306 kotlin( 307 """ 308 // Nullable Pair in Kotlin 309 package androidx.util 310 311 class NullableKotlinPair<out F, out S>(val first: F?, val second: S?) 312 """ 313 ), 314 kotlin( 315 """ 316 // Non-nullable Pair in Kotlin 317 package androidx.util 318 class NonNullableKotlinPair<out F: Any, out S: Any>(val first: F, val second: S) 319 """ 320 ), 321 java( 322 """ 323 // Platform nullability Pair in Java 324 package androidx.util; 325 326 @SuppressWarnings("WeakerAccess") 327 public class PlatformJavaPair<F, S> { 328 public final F first; 329 public final S second; 330 331 public PlatformJavaPair(F first, S second) { 332 this.first = first; 333 this.second = second; 334 } 335 } 336 """ 337 ), 338 java( 339 """ 340 // Platform nullability Pair in Java 341 package androidx.util; 342 import androidx.annotation.NonNull; 343 import androidx.annotation.Nullable; 344 345 @SuppressWarnings("WeakerAccess") 346 public class NullableJavaPair<F, S> { 347 public final @Nullable F first; 348 public final @Nullable S second; 349 350 public NullableJavaPair(@Nullable F first, @Nullable S second) { 351 this.first = first; 352 this.second = second; 353 } 354 } 355 """ 356 ), 357 java( 358 """ 359 // Platform nullability Pair in Java 360 package androidx.util; 361 362 import androidx.annotation.NonNull; 363 364 @SuppressWarnings("WeakerAccess") 365 public class NonNullableJavaPair<F, S> { 366 public final @NonNull F first; 367 public final @NonNull S second; 368 369 public NonNullableJavaPair(@NonNull F first, @NonNull S second) { 370 this.first = first; 371 this.second = second; 372 } 373 } 374 """ 375 ), 376 kotlin( 377 """ 378 package androidx.util 379 380 @Suppress("HasPlatformType") // Intentionally propagating platform type with unknown nullability. 381 inline operator fun <F, S> PlatformJavaPair<F, S>.component1() = first 382 """ 383 ), 384 supportNonNullSource, 385 supportNullableSource 386 ), 387 api = """ 388 package androidx.util { 389 public class NonNullableJavaPair<F, S> { 390 ctor public NonNullableJavaPair(F, S); 391 field public final F first; 392 field public final S second; 393 } 394 public final class NonNullableKotlinPair<F, S> { 395 ctor public NonNullableKotlinPair(F first, S second); 396 method public F getFirst(); 397 method public S getSecond(); 398 } 399 public class NullableJavaPair<F, S> { 400 ctor public NullableJavaPair(F?, S?); 401 field public final F? first; 402 field public final S? second; 403 } 404 public final class NullableKotlinPair<F, S> { 405 ctor public NullableKotlinPair(F? first, S? second); 406 method public F? getFirst(); 407 method public S? getSecond(); 408 } 409 public class PlatformJavaPair<F, S> { 410 ctor public PlatformJavaPair(F!, S!); 411 field public final F! first; 412 field public final S! second; 413 } 414 public final class TestKt { 415 ctor public TestKt(); 416 method public static operator <F, S> F! component1(androidx.util.PlatformJavaPair<F,S>); 417 } 418 } 419 """, 420 extraArguments = arrayOf("--hide-package", "androidx.annotation"), 421 checkDoclava1 = false /* doesn't support Kotlin... */ 422 ) 423 } 424 425 @Test JvmOverloadsnull426 fun `JvmOverloads`() { 427 // Regression test for https://github.com/android/android-ktx/issues/366 428 check( 429 compatibilityMode = false, 430 sourceFiles = *arrayOf( 431 kotlin( 432 """ 433 package androidx.content 434 435 import android.annotation.SuppressLint 436 import android.content.SharedPreferences 437 438 @SuppressLint("ApplySharedPref") 439 @JvmOverloads 440 inline fun SharedPreferences.edit( 441 commit: Boolean = false, 442 action: SharedPreferences.Editor.() -> Unit 443 ) { 444 val editor = edit() 445 action(editor) 446 if (commit) { 447 editor.commit() 448 } else { 449 editor.apply() 450 } 451 } 452 453 @JvmOverloads 454 fun String.blahblahblah(firstArg: String = "hello", secondArg: Int = "42", thirdArg: String = "world") { 455 } 456 """ 457 ) 458 ), 459 api = """ 460 package androidx.content { 461 public final class TestKt { 462 ctor public TestKt(); 463 method public static void blahblahblah(String, String firstArg = "\"hello\"", int secondArg = "\"42\"", String thirdArg = "\"world\""); 464 method public static void blahblahblah(String, String firstArg = "\"hello\"", int secondArg = "\"42\""); 465 method public static void blahblahblah(String, String firstArg = "\"hello\""); 466 method public static void blahblahblah(String); 467 method public static void edit(android.content.SharedPreferences, boolean commit = "false", kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action); 468 method public static void edit(android.content.SharedPreferences, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action); 469 } 470 } 471 """, 472 extraArguments = arrayOf("--hide-package", "androidx.annotation"), 473 checkDoclava1 = false /* doesn't support default Values */ 474 ) 475 } 476 477 @Test Extract class with genericsnull478 fun `Extract class with generics`() { 479 // Basic interface with generics; makes sure <T extends Object> is written as just <T> 480 // Also include some more complex generics expressions to make sure they're serialized 481 // correctly (in particular, using fully qualified names instead of what appears in 482 // the source code.) 483 check( 484 checkDoclava1 = true, 485 sourceFiles = *arrayOf( 486 java( 487 """ 488 package test.pkg; 489 @SuppressWarnings("ALL") 490 public interface MyInterface<T extends Object> 491 extends MyBaseInterface { 492 } 493 """ 494 ), java( 495 """ 496 package a.b.c; 497 @SuppressWarnings("ALL") 498 public interface MyStream<T, S extends MyStream<T, S>> extends test.pkg.AutoCloseable { 499 } 500 """ 501 ), java( 502 """ 503 package test.pkg; 504 @SuppressWarnings("ALL") 505 public interface MyInterface2<T extends Number> 506 extends MyBaseInterface { 507 class TtsSpan<C extends MyInterface<?>> { } 508 abstract class Range<T extends Comparable<? super T>> { 509 protected String myString; 510 } 511 } 512 """ 513 ), 514 java( 515 """ 516 package test.pkg; 517 public interface MyBaseInterface { 518 void fun(int a, String b); 519 } 520 """ 521 ), 522 java( 523 """ 524 package test.pkg; 525 public interface MyOtherInterface extends MyBaseInterface, AutoCloseable { 526 void fun(int a, String b); 527 } 528 """ 529 ), 530 java( 531 """ 532 package test.pkg; 533 public interface AutoCloseable { 534 } 535 """ 536 ) 537 ), 538 api = """ 539 package a.b.c { 540 public abstract interface MyStream<T, S extends a.b.c.MyStream<T, S>> implements test.pkg.AutoCloseable { 541 } 542 } 543 package test.pkg { 544 public abstract interface AutoCloseable { 545 } 546 public abstract interface MyBaseInterface { 547 method public abstract void fun(int, java.lang.String); 548 } 549 public abstract interface MyInterface<T> implements test.pkg.MyBaseInterface { 550 } 551 public abstract interface MyInterface2<T extends java.lang.Number> implements test.pkg.MyBaseInterface { 552 } 553 public static abstract class MyInterface2.Range<T extends java.lang.Comparable<? super T>> { 554 ctor public MyInterface2.Range(); 555 field protected java.lang.String myString; 556 } 557 public static class MyInterface2.TtsSpan<C extends test.pkg.MyInterface<?>> { 558 ctor public MyInterface2.TtsSpan(); 559 } 560 public abstract interface MyOtherInterface implements test.pkg.AutoCloseable test.pkg.MyBaseInterface { 561 } 562 } 563 """, 564 extraArguments = arrayOf("--hide", "KotlinKeyword") 565 ) 566 } 567 568 @Test Basic class without default constructor, has constructors with argsnull569 fun `Basic class without default constructor, has constructors with args`() { 570 // Class without private constructors (shouldn't insert default constructor) 571 check( 572 sourceFiles = *arrayOf( 573 java( 574 """ 575 package test.pkg; 576 public class Foo { 577 public Foo(int i) { 578 579 } 580 public Foo(int i, int j) { 581 } 582 } 583 """ 584 ) 585 ), 586 api = """ 587 package test.pkg { 588 public class Foo { 589 ctor public Foo(int); 590 ctor public Foo(int, int); 591 } 592 } 593 """ 594 ) 595 } 596 597 @Test Basic class without default constructor, has private constructornull598 fun `Basic class without default constructor, has private constructor`() { 599 // Class without private constructors; no default constructor should be inserted 600 check( 601 sourceFiles = *arrayOf( 602 java( 603 """ 604 package test.pkg; 605 @SuppressWarnings("ALL") 606 public class Foo { 607 private Foo() { 608 } 609 } 610 """ 611 ) 612 ), 613 api = """ 614 package test.pkg { 615 public class Foo { 616 } 617 } 618 """ 619 ) 620 } 621 622 @Test Interface class extractionnull623 fun `Interface class extraction`() { 624 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 625 // in the interface are taken to be public etc) 626 check( 627 sourceFiles = *arrayOf( 628 java( 629 """ 630 package test.pkg; 631 @SuppressWarnings("ALL") 632 public interface Foo { 633 void foo(); 634 } 635 """ 636 ) 637 ), 638 api = """ 639 package test.pkg { 640 public abstract interface Foo { 641 method public abstract void foo(); 642 } 643 } 644 """ 645 ) 646 } 647 648 @Test Enum class extractionnull649 fun `Enum class extraction`() { 650 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 651 // in the interface are taken to be public etc) 652 check( 653 sourceFiles = *arrayOf( 654 java( 655 """ 656 package test.pkg; 657 @SuppressWarnings("ALL") 658 public enum Foo { 659 A, B; 660 } 661 """ 662 ) 663 ), 664 api = """ 665 package test.pkg { 666 public final class Foo extends java.lang.Enum { 667 method public static test.pkg.Foo valueOf(java.lang.String); 668 method public static final test.pkg.Foo[] values(); 669 enum_constant public static final test.pkg.Foo A; 670 enum_constant public static final test.pkg.Foo B; 671 } 672 } 673 """ 674 ) 675 } 676 677 @Test Enum class, non-compat modenull678 fun `Enum class, non-compat mode`() { 679 @Suppress("ConstantConditionIf") 680 if (SKIP_NON_COMPAT) { 681 println("Skipping test for non-compatibility mode which isn't fully done yet") 682 return 683 } 684 685 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 686 // in the interface are taken to be public etc) 687 check( 688 sourceFiles = *arrayOf( 689 java( 690 """ 691 package test.pkg; 692 @SuppressWarnings("ALL") 693 public enum Foo { 694 A, B; 695 } 696 """ 697 ) 698 ), 699 compatibilityMode = false, 700 api = """ 701 package test.pkg { 702 public enum Foo { 703 enum_constant public static final test.pkg.Foo! A; 704 enum_constant public static final test.pkg.Foo! B; 705 } 706 } 707 """ 708 ) 709 } 710 711 @Test Annotation class extractionnull712 fun `Annotation class extraction`() { 713 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 714 // in the interface are taken to be public etc) 715 check( 716 // For unknown reasons, doclava1 behaves differently here than when invoked on the 717 // whole platform 718 checkDoclava1 = false, 719 sourceFiles = *arrayOf( 720 java( 721 """ 722 package test.pkg; 723 @SuppressWarnings("ALL") 724 public @interface Foo { 725 String value(); 726 } 727 """ 728 ), 729 java( 730 """ 731 package android.annotation; 732 import static java.lang.annotation.ElementType.*; 733 import java.lang.annotation.*; 734 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) 735 @Retention(RetentionPolicy.CLASS) 736 @SuppressWarnings("ALL") 737 public @interface SuppressLint { 738 String[] value(); 739 } 740 """ 741 ) 742 ), 743 api = """ 744 package android.annotation { 745 public abstract class SuppressLint implements java.lang.annotation.Annotation { 746 } 747 } 748 package test.pkg { 749 public abstract class Foo implements java.lang.annotation.Annotation { 750 } 751 } 752 """ 753 ) 754 } 755 756 @Test Do not include inherited public methods from private parents in compat modenull757 fun `Do not include inherited public methods from private parents in compat mode`() { 758 // Real life example: StringBuilder.setLength, in compat mode 759 check( 760 compatibilityMode = true, 761 sourceFiles = *arrayOf( 762 java( 763 """ 764 package test.pkg; 765 public class MyStringBuilder extends AbstractMyStringBuilder { 766 } 767 """ 768 ), 769 java( 770 """ 771 package test.pkg; 772 class AbstractMyStringBuilder { 773 public void setLength(int length) { 774 } 775 } 776 """ 777 ) 778 ), 779 api = """ 780 package test.pkg { 781 public class MyStringBuilder { 782 ctor public MyStringBuilder(); 783 } 784 } 785 """ 786 ) 787 } 788 789 @Test Include inherited public methods from private parentsnull790 fun `Include inherited public methods from private parents`() { 791 // In non-compat mode, include public methods from hidden parents too. 792 // Real life example: StringBuilder.setLength 793 // This is just like the above test, but with compat mode disabled. 794 check( 795 compatibilityMode = false, 796 sourceFiles = *arrayOf( 797 java( 798 """ 799 package test.pkg; 800 public class MyStringBuilder extends AbstractMyStringBuilder { 801 } 802 """ 803 ), 804 java( 805 """ 806 package test.pkg; 807 class AbstractMyStringBuilder { 808 public void setLength(int length) { 809 } 810 } 811 """ 812 ) 813 ), 814 api = """ 815 package test.pkg { 816 public class MyStringBuilder { 817 ctor public MyStringBuilder(); 818 method public void setLength(int); 819 } 820 } 821 """ 822 ) 823 } 824 825 @Test Annotation class extraction, non-compat modenull826 fun `Annotation class extraction, non-compat mode`() { 827 @Suppress("ConstantConditionIf") 828 if (SKIP_NON_COMPAT) { 829 println("Skipping test for non-compatibility mode which isn't fully done yet") 830 return 831 } 832 833 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 834 // in the interface are taken to be public etc) 835 check( 836 sourceFiles = *arrayOf( 837 java( 838 """ 839 package test.pkg; 840 public @interface Foo { 841 String value(); 842 } 843 """ 844 ), 845 java( 846 """ 847 package android.annotation; 848 import static java.lang.annotation.ElementType.*; 849 import java.lang.annotation.*; 850 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) 851 @Retention(RetentionPolicy.CLASS) 852 @SuppressWarnings("ALL") 853 public @interface SuppressLint { 854 String[] value(); 855 } 856 """ 857 ) 858 ), 859 compatibilityMode = false, 860 api = """ 861 package android.annotation { 862 public @interface SuppressLint { 863 method public abstract String[]! value(); 864 } 865 } 866 package test.pkg { 867 public @interface Foo { 868 method public abstract String! value(); 869 } 870 } 871 """ 872 ) 873 } 874 875 @Test Superclass signature extractionnull876 fun `Superclass signature extraction`() { 877 // Make sure superclass statement is correct; inherited method from parent that has same 878 // signature isn't included in the child 879 check( 880 sourceFiles = *arrayOf( 881 java( 882 """ 883 package test.pkg; 884 @SuppressWarnings("ALL") 885 public class Foo extends Super { 886 @Override public void base() { } 887 public void child() { } 888 } 889 """ 890 ), 891 java( 892 """ 893 package test.pkg; 894 @SuppressWarnings("ALL") 895 public class Super { 896 public void base() { } 897 } 898 """ 899 ) 900 ), 901 api = """ 902 package test.pkg { 903 public class Foo extends test.pkg.Super { 904 ctor public Foo(); 905 method public void child(); 906 } 907 public class Super { 908 ctor public Super(); 909 method public void base(); 910 } 911 } 912 """ 913 ) 914 } 915 916 @Test Extract fields with types and initial valuesnull917 fun `Extract fields with types and initial values`() { 918 check( 919 sourceFiles = *arrayOf( 920 java( 921 """ 922 package test.pkg; 923 @SuppressWarnings("ALL") 924 public class Foo { 925 private int hidden = 1; 926 int hidden2 = 2; 927 /** @hide */ 928 int hidden3 = 3; 929 930 protected int field00; // No value 931 public static final boolean field01 = true; 932 public static final int field02 = 42; 933 public static final long field03 = 42L; 934 public static final short field04 = 5; 935 public static final byte field05 = 5; 936 public static final char field06 = 'c'; 937 public static final float field07 = 98.5f; 938 public static final double field08 = 98.5; 939 public static final String field09 = "String with \"escapes\" and \u00a9..."; 940 public static final double field10 = Double.NaN; 941 public static final double field11 = Double.POSITIVE_INFINITY; 942 943 public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; 944 public static final char HEX_INPUT = 61184; 945 } 946 """ 947 ) 948 ), 949 api = """ 950 package test.pkg { 951 public class Foo { 952 ctor public Foo(); 953 field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; 954 field public static final char HEX_INPUT = 61184; // 0xef00 '\uef00' 955 field protected int field00; 956 field public static final boolean field01 = true; 957 field public static final int field02 = 42; // 0x2a 958 field public static final long field03 = 42L; // 0x2aL 959 field public static final short field04 = 5; // 0x5 960 field public static final byte field05 = 5; // 0x5 961 field public static final char field06 = 99; // 0x0063 'c' 962 field public static final float field07 = 98.5f; 963 field public static final double field08 = 98.5; 964 field public static final java.lang.String field09 = "String with \"escapes\" and \u00a9..."; 965 field public static final double field10 = (0.0/0.0); 966 field public static final double field11 = (1.0/0.0); 967 } 968 } 969 """ 970 ) 971 } 972 973 @Test Check all modifiersnull974 fun `Check all modifiers`() { 975 // Include as many modifiers as possible to see which ones are included 976 // in the signature files, and the expected sorting order. 977 // Note that the signature files treat "deprecated" as a fake modifier. 978 // Note also how the "protected" modifier on the interface method gets 979 // promoted to public. 980 check( 981 checkDoclava1 = true, 982 sourceFiles = *arrayOf( 983 java( 984 """ 985 package test.pkg; 986 987 @SuppressWarnings("ALL") 988 public abstract class Foo { 989 @Deprecated private static final long field1 = 5; 990 @Deprecated private static volatile long field2 = 5; 991 @Deprecated public static strictfp final synchronized void method1() { } 992 @Deprecated public static final synchronized native void method2(); 993 @Deprecated protected static final class Inner1 { } 994 @Deprecated protected static abstract class Inner2 { } 995 @Deprecated protected interface Inner3 { 996 default void method3() { } 997 static void method4(final int arg) { } 998 } 999 } 1000 """ 1001 ) 1002 ), 1003 1004 warnings = """ 1005 src/test/pkg/Foo.java:7: warning: Method test.pkg.Foo.method1(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch:113] 1006 src/test/pkg/Foo.java:8: warning: Method test.pkg.Foo.method2(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch:113] 1007 src/test/pkg/Foo.java:9: warning: Class test.pkg.Foo.Inner1: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch:113] 1008 src/test/pkg/Foo.java:10: warning: Class test.pkg.Foo.Inner2: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch:113] 1009 src/test/pkg/Foo.java:11: warning: Class test.pkg.Foo.Inner3: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch:113] 1010 """, 1011 1012 api = """ 1013 package test.pkg { 1014 public abstract class Foo { 1015 ctor public Foo(); 1016 method public static final deprecated synchronized void method1(); 1017 method public static final deprecated synchronized void method2(); 1018 } 1019 protected static final deprecated class Foo.Inner1 { 1020 ctor protected Foo.Inner1(); 1021 } 1022 protected static abstract deprecated class Foo.Inner2 { 1023 ctor protected Foo.Inner2(); 1024 } 1025 protected static abstract deprecated interface Foo.Inner3 { 1026 method public default void method3(); 1027 method public static void method4(int); 1028 } 1029 } 1030 """ 1031 ) 1032 } 1033 1034 @Test Check all modifiers, non-compat modenull1035 fun `Check all modifiers, non-compat mode`() { 1036 @Suppress("ConstantConditionIf") 1037 if (SKIP_NON_COMPAT) { 1038 @Suppress("ConstantConditionIf") 1039 println("Skipping test for non-compatibility mode which isn't fully done yet") 1040 return 1041 } 1042 1043 // Like testModifiers but turns off compat mode, such that we have 1044 // a modifier order more in line with standard code conventions 1045 check( 1046 compatibilityMode = false, 1047 sourceFiles = *arrayOf( 1048 java( 1049 """ 1050 package test.pkg; 1051 1052 @SuppressWarnings("ALL") 1053 public abstract class Foo { 1054 @Deprecated private static final long field1 = 5; 1055 @Deprecated private static volatile long field2 = 5; 1056 /** @deprecated */ @Deprecated public static strictfp final synchronized void method1() { } 1057 /** @deprecated */ @Deprecated public static final synchronized native void method2(); 1058 /** @deprecated */ @Deprecated protected static final class Inner1 { } 1059 /** @deprecated */ @Deprecated protected static abstract class Inner2 { } 1060 /** @deprecated */ @Deprecated protected interface Inner3 { 1061 protected default void method3() { } 1062 static void method4(final int arg) { } 1063 } 1064 } 1065 """ 1066 ) 1067 ), 1068 api = """ 1069 package test.pkg { 1070 public abstract class Foo { 1071 ctor public Foo(); 1072 method deprecated public static final synchronized strictfp void method1(); 1073 method deprecated public static final synchronized native void method2(); 1074 } 1075 deprecated protected static final class Foo.Inner1 { 1076 ctor protected Foo.Inner1(); 1077 } 1078 deprecated protected abstract static class Foo.Inner2 { 1079 ctor protected Foo.Inner2(); 1080 } 1081 deprecated protected static interface Foo.Inner3 { 1082 method public default void method3(); 1083 method public static void method4(int); 1084 } 1085 } 1086 """ 1087 ) 1088 } 1089 1090 @Test Package with only hidden classes should be removed from signature filesnull1091 fun `Package with only hidden classes should be removed from signature files`() { 1092 // Checks that if we have packages that are hidden, or contain only hidden or doconly 1093 // classes, the entire package is omitted from the signature file. Note how the test.pkg1.sub 1094 // package is not marked @hide, but doclava now treats subpackages of a hidden package 1095 // as also hidden. 1096 check( 1097 sourceFiles = *arrayOf( 1098 java( 1099 """ 1100 ${"/** @hide hidden package */" /* avoid dangling javadoc warning */} 1101 package test.pkg1; 1102 """ 1103 ), 1104 java( 1105 """ 1106 package test.pkg1; 1107 @SuppressWarnings("ALL") 1108 public class Foo { 1109 // Hidden by package hide 1110 } 1111 """ 1112 ), 1113 java( 1114 """ 1115 package test.pkg2; 1116 /** @hide hidden class in this package */ 1117 @SuppressWarnings("ALL") 1118 public class Bar { 1119 } 1120 """ 1121 ), 1122 java( 1123 """ 1124 package test.pkg2; 1125 /** @doconly hidden class in this package */ 1126 @SuppressWarnings("ALL") 1127 public class Baz { 1128 } 1129 """ 1130 ), 1131 java( 1132 """ 1133 package test.pkg1.sub; 1134 // Hidden by @hide in package above 1135 @SuppressWarnings("ALL") 1136 public class Test { 1137 } 1138 """ 1139 ), 1140 java( 1141 """ 1142 package test.pkg3; 1143 // The only really visible class 1144 @SuppressWarnings("ALL") 1145 public class Boo { 1146 } 1147 """ 1148 ) 1149 ), 1150 api = """ 1151 package test.pkg3 { 1152 public class Boo { 1153 ctor public Boo(); 1154 } 1155 } 1156 """ 1157 ) 1158 } 1159 1160 @Test Enums can be abstractnull1161 fun `Enums can be abstract`() { 1162 // As per https://bugs.openjdk.java.net/browse/JDK-6287639 1163 // abstract methods in enums should not be listed as abstract, 1164 // but doclava1 does, so replicate this. 1165 // Also checks that we handle both enum fields and regular fields 1166 // and that they are listed separately. 1167 1168 check( 1169 sourceFiles = *arrayOf( 1170 java( 1171 """ 1172 package test.pkg; 1173 1174 @SuppressWarnings("ALL") 1175 public enum FooBar { 1176 ABC { 1177 @Override 1178 protected void foo() { } 1179 }, DEF { 1180 @Override 1181 protected void foo() { } 1182 }; 1183 1184 protected abstract void foo(); 1185 public static int field1 = 1; 1186 public int field2 = 2; 1187 } 1188 """ 1189 ) 1190 ), 1191 api = """ 1192 package test.pkg { 1193 public class FooBar extends java.lang.Enum { 1194 method protected abstract void foo(); 1195 method public static test.pkg.FooBar valueOf(java.lang.String); 1196 method public static final test.pkg.FooBar[] values(); 1197 enum_constant public static final test.pkg.FooBar ABC; 1198 enum_constant public static final test.pkg.FooBar DEF; 1199 field public static int field1; 1200 field public int field2; 1201 } 1202 } 1203 """ 1204 ) 1205 } 1206 1207 @Test Check erasure in throws-listnull1208 fun `Check erasure in throws-list`() { 1209 // Makes sure that when we have a generic signature in the throws list we take 1210 // the erasure instead (in compat mode); "Throwable" instead of "X" in the below 1211 // test. Real world example: Optional.orElseThrow. 1212 check( 1213 compatibilityMode = true, 1214 sourceFiles = *arrayOf( 1215 java( 1216 """ 1217 package test.pkg; 1218 1219 import java.util.function.Supplier; 1220 1221 @SuppressWarnings("ALL") 1222 public final class Test<T> { 1223 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 1224 return null; 1225 } 1226 } 1227 """ 1228 ) 1229 ), 1230 api = """ 1231 package test.pkg { 1232 public final class Test<T> { 1233 ctor public Test(); 1234 method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable; 1235 } 1236 } 1237 """ 1238 ) 1239 } 1240 1241 @Test Check various generics signature subtletiesnull1242 fun `Check various generics signature subtleties`() { 1243 // Some additional declarations where PSI default type handling diffs from doclava1 1244 check( 1245 sourceFiles = *arrayOf( 1246 java( 1247 """ 1248 package test.pkg; 1249 1250 @SuppressWarnings("ALL") 1251 public abstract class Collections { 1252 public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T> collection) { 1253 return null; 1254 } 1255 public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T t); 1256 public final class Range<T extends java.lang.Comparable<? super T>> { } 1257 } 1258 """ 1259 ), java( 1260 """ 1261 package test.pkg; 1262 1263 import java.util.Set; 1264 1265 @SuppressWarnings("ALL") 1266 public class MoreAsserts { 1267 public static void assertEquals(String arg0, Set<? extends Object> arg1, Set<? extends Object> arg2) { } 1268 public static void assertEquals(Set<? extends Object> arg1, Set<? extends Object> arg2) { } 1269 } 1270 1271 """ 1272 ) 1273 ), 1274 1275 // This is the output from doclava1; I'm not quite matching this yet (sorting order differs, 1276 // and my heuristic to remove "extends java.lang.Object" is somehow preserved here. I'm 1277 // not clear on when they do it and when they don't. 1278 /* 1279 api = """ 1280 package test.pkg { 1281 public abstract class Collections { 1282 ctor public Collections(); 1283 method public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T); 1284 method public static <T & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1285 } 1286 public final class Collections.Range<T extends java.lang.Comparable<? super T>> { 1287 ctor public Collections.Range(); 1288 } 1289 public class MoreAsserts { 1290 ctor public MoreAsserts(); 1291 method public static void assertEquals(java.util.Set<? extends java.lang.Object>, java.util.Set<? extends java.lang.Object>); 1292 method public static void assertEquals(java.lang.String, java.util.Set<? extends java.lang.Object>, java.util.Set<? extends java.lang.Object>); 1293 } 1294 } 1295 """, 1296 */ 1297 api = """ 1298 package test.pkg { 1299 public abstract class Collections { 1300 ctor public Collections(); 1301 method public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T); 1302 method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1303 } 1304 public final class Collections.Range<T extends java.lang.Comparable<? super T>> { 1305 ctor public Collections.Range(); 1306 } 1307 public class MoreAsserts { 1308 ctor public MoreAsserts(); 1309 method public static void assertEquals(java.lang.String, java.util.Set<?>, java.util.Set<?>); 1310 method public static void assertEquals(java.util.Set<?>, java.util.Set<?>); 1311 } 1312 } 1313 """, 1314 1315 // Can't check doclava1 on this: its output doesn't match javac, e.g. for the above declaration 1316 // of max, javap shows this signature: 1317 // public static <T extends java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1318 // which matches metalava's output: 1319 // method public static <T & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1320 // and not doclava1: 1321 // method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1322 1323 checkDoclava1 = false 1324 ) 1325 } 1326 1327 @Test Check instance methods in enumsnull1328 fun `Check instance methods in enums`() { 1329 // Make sure that when we have instance methods in an enum they're handled 1330 // correctly (there's some special casing around enums to insert extra methods 1331 // that was broken, as exposed by ChronoUnit#toString) 1332 check( 1333 sourceFiles = *arrayOf( 1334 java( 1335 """ 1336 package test.pkg; 1337 1338 @SuppressWarnings("ALL") 1339 public interface TempUnit { 1340 @Override 1341 String toString(); 1342 } 1343 """ 1344 ), 1345 java( 1346 """ 1347 package test.pkg; 1348 1349 @SuppressWarnings("ALL") 1350 public enum ChronUnit implements TempUnit { 1351 C, B, A; 1352 1353 public String valueOf(int x) { 1354 return Integer.toString(x + 5); 1355 } 1356 1357 public String values(String separator) { 1358 return null; 1359 } 1360 1361 @Override 1362 public String toString() { 1363 return name(); 1364 } 1365 } 1366 """ 1367 ) 1368 ), 1369 importedPackages = emptyList(), 1370 api = """ 1371 package test.pkg { 1372 public final class ChronUnit extends java.lang.Enum implements test.pkg.TempUnit { 1373 method public static test.pkg.ChronUnit valueOf(java.lang.String); 1374 method public java.lang.String valueOf(int); 1375 method public static final test.pkg.ChronUnit[] values(); 1376 method public final java.lang.String values(java.lang.String); 1377 enum_constant public static final test.pkg.ChronUnit A; 1378 enum_constant public static final test.pkg.ChronUnit B; 1379 enum_constant public static final test.pkg.ChronUnit C; 1380 } 1381 public abstract interface TempUnit { 1382 method public abstract java.lang.String toString(); 1383 } 1384 } 1385 """ 1386 ) 1387 } 1388 1389 @Test Mixing enums and fieldsnull1390 fun `Mixing enums and fields`() { 1391 // Checks sorting order of enum constant values 1392 val source = """ 1393 package java.nio.file.attribute { 1394 public final class AclEntryPermission extends java.lang.Enum { 1395 method public static java.nio.file.attribute.AclEntryPermission valueOf(java.lang.String); 1396 method public static final java.nio.file.attribute.AclEntryPermission[] values(); 1397 enum_constant public static final java.nio.file.attribute.AclEntryPermission APPEND_DATA; 1398 enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE; 1399 enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE_CHILD; 1400 enum_constant public static final java.nio.file.attribute.AclEntryPermission EXECUTE; 1401 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ACL; 1402 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ATTRIBUTES; 1403 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_DATA; 1404 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_NAMED_ATTRS; 1405 enum_constant public static final java.nio.file.attribute.AclEntryPermission SYNCHRONIZE; 1406 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ACL; 1407 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ATTRIBUTES; 1408 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_DATA; 1409 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_NAMED_ATTRS; 1410 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_OWNER; 1411 field public static final java.nio.file.attribute.AclEntryPermission ADD_FILE; 1412 field public static final java.nio.file.attribute.AclEntryPermission ADD_SUBDIRECTORY; 1413 field public static final java.nio.file.attribute.AclEntryPermission LIST_DIRECTORY; 1414 } 1415 } 1416 """ 1417 check( 1418 signatureSource = source, 1419 api = source 1420 ) 1421 } 1422 1423 @Test Superclass filtering, should skip intermediate hidden classesnull1424 fun `Superclass filtering, should skip intermediate hidden classes`() { 1425 check( 1426 sourceFiles = *arrayOf( 1427 java( 1428 """ 1429 package test.pkg; 1430 @SuppressWarnings("ALL") 1431 public class MyClass extends HiddenParent { 1432 public void method4() { } 1433 } 1434 """ 1435 ), 1436 java( 1437 """ 1438 package test.pkg; 1439 /** @hide */ 1440 @SuppressWarnings("ALL") 1441 public class HiddenParent extends HiddenParent2 { 1442 public static final String CONSTANT = "MyConstant"; 1443 protected int mContext; 1444 public void method3() { } 1445 } 1446 """ 1447 ), 1448 java( 1449 """ 1450 package test.pkg; 1451 /** @hide */ 1452 @SuppressWarnings("ALL") 1453 public class HiddenParent2 extends PublicParent { 1454 public void method2() { } 1455 } 1456 """ 1457 ), 1458 java( 1459 """ 1460 package test.pkg; 1461 @SuppressWarnings("ALL") 1462 public class PublicParent { 1463 public void method1() { } 1464 } 1465 """ 1466 ) 1467 ), 1468 // Notice how the intermediate methods (method2, method3) have been removed 1469 includeStrippedSuperclassWarnings = true, 1470 warnings = "src/test/pkg/MyClass.java:2: warning: Public class test.pkg.MyClass stripped of unavailable superclass test.pkg.HiddenParent [HiddenSuperclass:111]", 1471 api = """ 1472 package test.pkg { 1473 public class MyClass extends test.pkg.PublicParent { 1474 ctor public MyClass(); 1475 method public void method4(); 1476 } 1477 public class PublicParent { 1478 ctor public PublicParent(); 1479 method public void method1(); 1480 } 1481 } 1482 """ 1483 ) 1484 } 1485 1486 @Test Inheriting from package private classes, package private class should be includednull1487 fun `Inheriting from package private classes, package private class should be included`() { 1488 check( 1489 checkDoclava1 = false, // doclava1 does not include method2, which it should 1490 compatibilityMode = false, 1491 sourceFiles = 1492 *arrayOf( 1493 java( 1494 """ 1495 package test.pkg; 1496 @SuppressWarnings("ALL") 1497 public class MyClass extends HiddenParent { 1498 public void method1() { } 1499 } 1500 """ 1501 ), 1502 java( 1503 """ 1504 package test.pkg; 1505 @SuppressWarnings("ALL") 1506 class HiddenParent { 1507 public static final String CONSTANT = "MyConstant"; 1508 protected int mContext; 1509 public void method2() { } 1510 } 1511 """ 1512 ) 1513 ), 1514 warnings = "", 1515 api = """ 1516 package test.pkg { 1517 public class MyClass { 1518 ctor public MyClass(); 1519 method public void method1(); 1520 method public void method2(); 1521 } 1522 } 1523 """ 1524 ) 1525 } 1526 1527 @Test Using compatibility flag manuallynull1528 fun `Using compatibility flag manually`() { 1529 // Like previous test, but using compatibility mode and explicitly turning on 1530 // the hidden super class compatibility flag. This test is mostly intended 1531 // to test the flag handling for individual compatibility flags. 1532 check( 1533 checkDoclava1 = false, // doclava1 does not include method2, which it should 1534 compatibilityMode = true, 1535 extraArguments = arrayOf("--skip-inherited-methods=false"), 1536 sourceFiles = 1537 *arrayOf( 1538 java( 1539 """ 1540 package test.pkg; 1541 @SuppressWarnings("ALL") 1542 public class MyClass extends HiddenParent { 1543 public void method1() { } 1544 } 1545 """ 1546 ), 1547 java( 1548 """ 1549 package test.pkg; 1550 @SuppressWarnings("ALL") 1551 class HiddenParent { 1552 public static final String CONSTANT = "MyConstant"; 1553 protected int mContext; 1554 public void method2() { } 1555 } 1556 """ 1557 ) 1558 ), 1559 warnings = "", 1560 api = """ 1561 package test.pkg { 1562 public class MyClass { 1563 ctor public MyClass(); 1564 method public void method1(); 1565 method public void method2(); 1566 } 1567 } 1568 """ 1569 ) 1570 } 1571 1572 @Test When implementing rather than extending package private class, inline members insteadnull1573 fun `When implementing rather than extending package private class, inline members instead`() { 1574 // If you implement a package private interface, we just remove it and inline the members into 1575 // the subclass 1576 check( 1577 compatibilityMode = true, 1578 sourceFiles = *arrayOf( 1579 java( 1580 """ 1581 package test.pkg; 1582 public class MyClass implements HiddenInterface { 1583 @Override public void method() { } 1584 @Override public void other() { } 1585 } 1586 """ 1587 ), 1588 java( 1589 """ 1590 package test.pkg; 1591 public interface OtherInterface { 1592 void other(); 1593 } 1594 """ 1595 ), 1596 java( 1597 """ 1598 package test.pkg; 1599 interface HiddenInterface extends OtherInterface { 1600 void method() { } 1601 String CONSTANT = "MyConstant"; 1602 } 1603 """ 1604 ) 1605 ), 1606 api = """ 1607 package test.pkg { 1608 public class MyClass implements test.pkg.OtherInterface { 1609 ctor public MyClass(); 1610 method public void method(); 1611 method public void other(); 1612 field public static final java.lang.String CONSTANT = "MyConstant"; 1613 } 1614 public abstract interface OtherInterface { 1615 method public abstract void other(); 1616 } 1617 } 1618 """ 1619 ) 1620 } 1621 1622 @Test Implementing package private class, non-compat modenull1623 fun `Implementing package private class, non-compat mode`() { 1624 @Suppress("ConstantConditionIf") 1625 if (SKIP_NON_COMPAT) { 1626 println("Skipping test for non-compatibility mode which isn't fully done yet") 1627 return 1628 } 1629 1630 // Like the previous test, but in non compat mode we correctly 1631 // include all the non-hidden public interfaces into the signature 1632 1633 // BUG: Note that we need to implement the parent 1634 check( 1635 compatibilityMode = false, 1636 sourceFiles = *arrayOf( 1637 java( 1638 """ 1639 package test.pkg; 1640 public class MyClass implements HiddenInterface { 1641 @Override public void method() { } 1642 @Override public void other() { } 1643 } 1644 """ 1645 ), 1646 java( 1647 """ 1648 package test.pkg; 1649 public interface OtherInterface { 1650 void other(); 1651 } 1652 """ 1653 ), 1654 java( 1655 """ 1656 package test.pkg; 1657 interface HiddenInterface extends OtherInterface { 1658 void method() { } 1659 String CONSTANT = "MyConstant"; 1660 } 1661 """ 1662 ) 1663 ), 1664 api = """ 1665 package test.pkg { 1666 public class MyClass implements test.pkg.OtherInterface { 1667 ctor public MyClass(); 1668 method public void method(); 1669 method public void other(); 1670 field public static final String! CONSTANT = "MyConstant"; 1671 } 1672 public interface OtherInterface { 1673 method public void other(); 1674 } 1675 } 1676 """ 1677 ) 1678 } 1679 1680 @Test Default modifiers should be omittednull1681 fun `Default modifiers should be omitted`() { 1682 // If signatures vary only by the "default" modifier in the interface, don't show it on the implementing 1683 // class 1684 check( 1685 sourceFiles = 1686 *arrayOf( 1687 java( 1688 """ 1689 package test.pkg; 1690 1691 public class MyClass implements SuperInterface { 1692 @Override public void method() { } 1693 @Override public void method2() { } 1694 } 1695 """ 1696 ), 1697 java( 1698 """ 1699 package test.pkg; 1700 1701 public interface SuperInterface { 1702 void method(); 1703 default void method2() { 1704 } 1705 } 1706 """ 1707 ) 1708 ), 1709 api = """ 1710 package test.pkg { 1711 public class MyClass implements test.pkg.SuperInterface { 1712 ctor public MyClass(); 1713 method public void method(); 1714 } 1715 public abstract interface SuperInterface { 1716 method public abstract void method(); 1717 method public default void method2(); 1718 } 1719 } 1720 """ 1721 ) 1722 } 1723 1724 @Test Override via different throws list should be includednull1725 fun `Override via different throws list should be included`() { 1726 // If a method overrides another but changes the throws list, the overriding 1727 // method must be listed in the subclass. This is observed for example in 1728 // AbstractCursor#finalize, which omits the throws clause from Object's finalize. 1729 check( 1730 sourceFiles = 1731 *arrayOf( 1732 java( 1733 """ 1734 package test.pkg; 1735 1736 public abstract class AbstractCursor extends Parent { 1737 @Override protected void finalize2() { } // note: not throws Throwable! 1738 } 1739 """ 1740 ), 1741 java( 1742 """ 1743 package test.pkg; 1744 1745 @SuppressWarnings("RedundantThrows") 1746 public class Parent { 1747 protected void finalize2() throws Throwable { 1748 } 1749 } 1750 """ 1751 ) 1752 ), 1753 api = """ 1754 package test.pkg { 1755 public abstract class AbstractCursor extends test.pkg.Parent { 1756 ctor public AbstractCursor(); 1757 method protected void finalize2(); 1758 } 1759 public class Parent { 1760 ctor public Parent(); 1761 method protected void finalize2() throws java.lang.Throwable; 1762 } 1763 } 1764 """ 1765 ) 1766 } 1767 1768 @Test Implementing interface methodnull1769 fun `Implementing interface method`() { 1770 // If you have a public method that implements an interface method, 1771 // they'll vary in the "abstract" modifier, but it shouldn't be listed on the 1772 // class. This is an issue for example for the ZonedDateTime#getLong method 1773 // implementing the TemporalAccessor#getLong method 1774 check( 1775 sourceFiles = *arrayOf( 1776 // java( 1777 // """ 1778 // package test.pkg; 1779 // public interface SomeInterface { 1780 // long getLong(); 1781 // } 1782 // """ 1783 // ), 1784 java( 1785 """ 1786 package test.pkg; 1787 public interface SomeInterface2 { 1788 @Override default long getLong() { 1789 return 42; 1790 } 1791 } 1792 """ 1793 ), 1794 java( 1795 """ 1796 package test.pkg; 1797 public class Foo implements /*SomeInterface,*/ SomeInterface2 { 1798 @Override 1799 public long getLong() { return 0L; } 1800 } 1801 """ 1802 ) 1803 ), 1804 // api = """ 1805 // package test.pkg { 1806 // public class Foo implements test.pkg.SomeInterface test.pkg.SomeInterface2 { 1807 // ctor public Foo(); 1808 // } 1809 // public abstract interface SomeInterface { 1810 // method public abstract long getLong(); 1811 // } 1812 // public abstract interface SomeInterface2 { 1813 // method public default long getLong(); 1814 // } 1815 // } 1816 // """ 1817 api = """ 1818 package test.pkg { 1819 public class Foo implements test.pkg.SomeInterface2 { 1820 ctor public Foo(); 1821 } 1822 public abstract interface SomeInterface2 { 1823 method public default long getLong(); 1824 } 1825 } 1826 """ 1827 ) 1828 } 1829 1830 @Test Check basic @remove scenariosnull1831 fun `Check basic @remove scenarios`() { 1832 // Test basic @remove handling for methods and fields 1833 check( 1834 checkDoclava1 = true, 1835 sourceFiles = *arrayOf( 1836 java( 1837 """ 1838 package test.pkg; 1839 @SuppressWarnings("JavaDoc") 1840 public class Bar { 1841 /** @removed */ 1842 public Bar() { } 1843 public int field; 1844 public void test() { } 1845 /** @removed */ 1846 public int removedField; 1847 /** @removed */ 1848 public void removedMethod() { } 1849 /** @removed and @hide - should not be listed */ 1850 public int hiddenField; 1851 1852 /** @removed */ 1853 public class Inner { } 1854 1855 public class Inner2 { 1856 public class Inner3 { 1857 /** @removed */ 1858 public class Inner4 { } 1859 } 1860 } 1861 1862 public class Inner5 { 1863 public class Inner6 { 1864 public class Inner7 { 1865 /** @removed */ 1866 public int removed; 1867 } 1868 } 1869 } 1870 } 1871 """ 1872 ) 1873 ), 1874 removedApi = """ 1875 package test.pkg { 1876 public class Bar { 1877 ctor public Bar(); 1878 method public void removedMethod(); 1879 field public int removedField; 1880 } 1881 public class Bar.Inner { 1882 ctor public Bar.Inner(); 1883 } 1884 public class Bar.Inner2.Inner3.Inner4 { 1885 ctor public Bar.Inner2.Inner3.Inner4(); 1886 } 1887 public class Bar.Inner5.Inner6.Inner7 { 1888 field public int removed; 1889 } 1890 } 1891 """, 1892 removedDexApi = "" + 1893 "Ltest/pkg/Bar;-><init>()V\n" + 1894 "Ltest/pkg/Bar;->removedMethod()V\n" + 1895 "Ltest/pkg/Bar;->removedField:I\n" + 1896 "Ltest/pkg/Bar\$Inner;\n" + 1897 "Ltest/pkg/Bar\$Inner;-><init>()V\n" + 1898 "Ltest/pkg/Bar\$Inner2\$Inner3\$Inner4;\n" + 1899 "Ltest/pkg/Bar\$Inner2\$Inner3\$Inner4;-><init>()V\n" + 1900 "Ltest/pkg/Bar\$Inner5\$Inner6\$Inner7;->removed:I" 1901 ) 1902 } 1903 1904 @Test Check @remove classnull1905 fun `Check @remove class`() { 1906 // Test removing classes 1907 check( 1908 checkDoclava1 = true, 1909 sourceFiles = *arrayOf( 1910 java( 1911 """ 1912 package test.pkg; 1913 /** @removed */ 1914 @SuppressWarnings("JavaDoc") 1915 public class Foo { 1916 public void foo() { } 1917 public class Inner { 1918 } 1919 } 1920 """ 1921 ), 1922 java( 1923 """ 1924 package test.pkg; 1925 @SuppressWarnings("JavaDoc") 1926 public class Bar implements Parcelable { 1927 public int field; 1928 public void method(); 1929 1930 /** @removed */ 1931 public int removedField; 1932 /** @removed */ 1933 public void removedMethod() { } 1934 1935 public class Inner1 { 1936 } 1937 /** @removed */ 1938 public class Inner2 { 1939 } 1940 } 1941 """ 1942 ), 1943 java( 1944 """ 1945 package test.pkg; 1946 @SuppressWarnings("ALL") 1947 public interface Parcelable { 1948 void method(); 1949 } 1950 """ 1951 ) 1952 ), 1953 /* 1954 I expected this: but doclava1 doesn't do that (and we now match its behavior) 1955 package test.pkg { 1956 public class Bar { 1957 method public void removedMethod(); 1958 field public int removedField; 1959 } 1960 public class Bar.Inner2 { 1961 } 1962 public class Foo { 1963 method public void foo(); 1964 } 1965 } 1966 */ 1967 removedApi = """ 1968 package test.pkg { 1969 public class Bar implements test.pkg.Parcelable { 1970 method public void removedMethod(); 1971 field public int removedField; 1972 } 1973 public class Bar.Inner2 { 1974 ctor public Bar.Inner2(); 1975 } 1976 public class Foo { 1977 ctor public Foo(); 1978 method public void foo(); 1979 } 1980 public class Foo.Inner { 1981 ctor public Foo.Inner(); 1982 } 1983 } 1984 """ 1985 ) 1986 } 1987 1988 @Test Test include overridden @Deprecated even if annotated with @hidenull1989 fun `Test include overridden @Deprecated even if annotated with @hide`() { 1990 check( 1991 checkDoclava1 = true, 1992 sourceFiles = *arrayOf( 1993 java( 1994 """ 1995 package test.pkg; 1996 @SuppressWarnings("JavaDoc") 1997 public class Child extends Parent { 1998 /** 1999 * @deprecated 2000 * @hide 2001 */ 2002 @Deprecated @Override 2003 public String toString() { 2004 return "Child"; 2005 } 2006 } 2007 """ 2008 ), 2009 java( 2010 """ 2011 package test.pkg; 2012 public class Parent { 2013 public String toString() { 2014 return "Parent"; 2015 } 2016 } 2017 """ 2018 ) 2019 ), 2020 api = """ 2021 package test.pkg { 2022 public class Child extends test.pkg.Parent { 2023 ctor public Child(); 2024 method public deprecated java.lang.String toString(); 2025 } 2026 public class Parent { 2027 ctor public Parent(); 2028 } 2029 } 2030 """, 2031 dexApi = """ 2032 Ltest/pkg/Child; 2033 Ltest/pkg/Child;-><init>()V 2034 Ltest/pkg/Child;->toString()Ljava/lang/String; 2035 Ltest/pkg/Parent; 2036 Ltest/pkg/Parent;-><init>()V 2037 Ltest/pkg/Parent;->toString()Ljava/lang/String; 2038 """ 2039 ) 2040 } 2041 2042 @Test Test invalid class namenull2043 fun `Test invalid class name`() { 2044 // Regression test for b/73018978 2045 check( 2046 checkDoclava1 = false, 2047 sourceFiles = *arrayOf( 2048 kotlin( 2049 "src/test/pkg/Foo.kt", 2050 """ 2051 @file:JvmName("-Foo") 2052 2053 package test.pkg 2054 2055 @Suppress("unused") 2056 inline fun String.printHelloWorld() { println("Hello World") } 2057 """ 2058 ) 2059 ), 2060 api = """ 2061 package test.pkg { 2062 public final class -Foo { 2063 method public static void printHelloWorld(java.lang.String); 2064 } 2065 } 2066 """ 2067 ) 2068 } 2069 2070 @Test Indirect Field Includes from Interfacesnull2071 fun `Indirect Field Includes from Interfaces`() { 2072 // Real-world example: include ZipConstants into ZipFile and JarFile 2073 check( 2074 checkDoclava1 = true, 2075 sourceFiles = *arrayOf( 2076 java( 2077 """ 2078 package test.pkg1; 2079 interface MyConstants { 2080 long CONSTANT1 = 12345; 2081 long CONSTANT2 = 67890; 2082 long CONSTANT3 = 42; 2083 } 2084 """ 2085 ), 2086 java( 2087 """ 2088 package test.pkg1; 2089 import java.io.Closeable; 2090 @SuppressWarnings("WeakerAccess") 2091 public class MyParent implements MyConstants, Closeable { 2092 } 2093 """ 2094 ), 2095 java( 2096 """ 2097 package test.pkg2; 2098 2099 import test.pkg1.MyParent; 2100 public class MyChild extends MyParent { 2101 } 2102 """ 2103 ) 2104 2105 ), 2106 api = """ 2107 package test.pkg1 { 2108 public class MyParent implements java.io.Closeable { 2109 ctor public MyParent(); 2110 field public static final long CONSTANT1 = 12345L; // 0x3039L 2111 field public static final long CONSTANT2 = 67890L; // 0x10932L 2112 field public static final long CONSTANT3 = 42L; // 0x2aL 2113 } 2114 } 2115 package test.pkg2 { 2116 public class MyChild extends test.pkg1.MyParent { 2117 ctor public MyChild(); 2118 field public static final long CONSTANT1 = 12345L; // 0x3039L 2119 field public static final long CONSTANT2 = 67890L; // 0x10932L 2120 field public static final long CONSTANT3 = 42L; // 0x2aL 2121 } 2122 } 2123 """ 2124 ) 2125 } 2126 2127 @Test Skip interfaces from packages explicitly hidden via argumentsnull2128 fun `Skip interfaces from packages explicitly hidden via arguments`() { 2129 // Real-world example: HttpResponseCache implements OkCacheContainer but hides the only inherited method 2130 check( 2131 checkDoclava1 = true, 2132 extraArguments = arrayOf( 2133 "--hide-package", "com.squareup.okhttp" 2134 ), 2135 sourceFiles = *arrayOf( 2136 java( 2137 """ 2138 package android.net.http; 2139 import com.squareup.okhttp.Cache; 2140 import com.squareup.okhttp.OkCacheContainer; 2141 import java.io.Closeable; 2142 import java.net.ResponseCache; 2143 @SuppressWarnings("JavaDoc") 2144 public final class HttpResponseCache implements Closeable, OkCacheContainer { 2145 /** @hide Needed for OkHttp integration. */ 2146 @Override 2147 public Cache getCache() { 2148 return delegate.getCache(); 2149 } 2150 } 2151 """ 2152 ), 2153 java( 2154 """ 2155 package com.squareup.okhttp; 2156 public interface OkCacheContainer { 2157 Cache getCache(); 2158 } 2159 """ 2160 ) 2161 ), 2162 api = """ 2163 package android.net.http { 2164 public final class HttpResponseCache implements java.io.Closeable { 2165 ctor public HttpResponseCache(); 2166 } 2167 } 2168 """ 2169 ) 2170 } 2171 2172 @Test Private API signaturesnull2173 fun `Private API signatures`() { 2174 check( 2175 checkDoclava1 = false, // doclava1 doesn't have the same behavior: see 2176 // https://android-review.googlesource.com/c/platform/external/doclava/+/589515 2177 sourceFiles = *arrayOf( 2178 java( 2179 """ 2180 package test.pkg; 2181 public class Class1 implements MyInterface { 2182 Class1(int arg) { } 2183 /** @hide */ 2184 public void method1() { } 2185 void method2() { } 2186 private void method3() { } 2187 public int field1 = 1; 2188 protected int field2 = 2; 2189 int field3 = 3; 2190 float[][] field4 = 3; 2191 long[] field5 = null; 2192 private int field6 = 4; 2193 void myVarargsMethod(int x, String... args) { } 2194 2195 public class Inner { // Fully public, should not be included 2196 public void publicMethod() { } 2197 } 2198 } 2199 """ 2200 ), 2201 2202 java( 2203 """ 2204 package test.pkg; 2205 class Class2 { 2206 public void method4() { } 2207 2208 private class Class3 { 2209 public void method5() { } 2210 } 2211 } 2212 """ 2213 ), 2214 2215 java( 2216 """ 2217 package test.pkg; 2218 /** @doconly */ 2219 class Class4 { 2220 public void method5() { } 2221 } 2222 """ 2223 ), 2224 2225 java( 2226 """ 2227 package test.pkg; 2228 /** @hide */ 2229 @SuppressWarnings("UnnecessaryInterfaceModifier") 2230 public interface MyInterface { 2231 public static final String MY_CONSTANT = "5"; 2232 } 2233 """ 2234 ) 2235 ), 2236 privateApi = """ 2237 package test.pkg { 2238 public class Class1 implements test.pkg.MyInterface { 2239 ctor Class1(int); 2240 method public void method1(); 2241 method void method2(); 2242 method private void method3(); 2243 method void myVarargsMethod(int, java.lang.String...); 2244 field int field3; 2245 field float[][] field4; 2246 field long[] field5; 2247 field private int field6; 2248 } 2249 class Class2 { 2250 ctor Class2(); 2251 method public void method4(); 2252 } 2253 private class Class2.Class3 { 2254 ctor private Class2.Class3(); 2255 method public void method5(); 2256 } 2257 class Class4 { 2258 ctor Class4(); 2259 method public void method5(); 2260 } 2261 public abstract interface MyInterface { 2262 field public static final java.lang.String MY_CONSTANT = "5"; 2263 } 2264 } 2265 """, 2266 privateDexApi = """ 2267 Ltest/pkg/Class1;-><init>(I)V 2268 Ltest/pkg/Class1;->method1()V 2269 Ltest/pkg/Class1;->method2()V 2270 Ltest/pkg/Class1;->method3()V 2271 Ltest/pkg/Class1;->myVarargsMethod(I[Ljava/lang/String;)V 2272 Ltest/pkg/Class1;->field3:I 2273 Ltest/pkg/Class1;->field4:[[F 2274 Ltest/pkg/Class1;->field5:[J 2275 Ltest/pkg/Class1;->field6:I 2276 Ltest/pkg/Class2; 2277 Ltest/pkg/Class2;-><init>()V 2278 Ltest/pkg/Class2;->method4()V 2279 Ltest/pkg/Class2${"$"}Class3; 2280 Ltest/pkg/Class2${"$"}Class3;-><init>()V 2281 Ltest/pkg/Class2${"$"}Class3;->method5()V 2282 Ltest/pkg/Class4; 2283 Ltest/pkg/Class4;-><init>()V 2284 Ltest/pkg/Class4;->method5()V 2285 Ltest/pkg/MyInterface; 2286 Ltest/pkg/MyInterface;->MY_CONSTANT:Ljava/lang/String; 2287 """ 2288 ) 2289 } 2290 2291 @Test Private API signature corner casesnull2292 fun `Private API signature corner cases`() { 2293 // Some corner case scenarios exposed by differences in output from doclava and metalava 2294 check( 2295 checkDoclava1 = false, 2296 sourceFiles = *arrayOf( 2297 java( 2298 """ 2299 package test.pkg; 2300 import android.os.Parcel; 2301 import android.os.Parcelable; 2302 import java.util.concurrent.FutureTask; 2303 2304 public class Class1 extends PrivateParent implements MyInterface { 2305 Class1(int arg) { } 2306 2307 @Override public String toString() { 2308 return "Class1"; 2309 } 2310 2311 private abstract class AmsTask extends FutureTask<String> { 2312 @Override 2313 protected void set(String bundle) { 2314 super.set(bundle); 2315 } 2316 } 2317 2318 /** @hide */ 2319 public abstract static class TouchPoint implements Parcelable { 2320 } 2321 } 2322 """ 2323 ), 2324 2325 java( 2326 """ 2327 package test.pkg; 2328 class PrivateParent { 2329 final String getValue() { 2330 return ""; 2331 } 2332 } 2333 """ 2334 ), 2335 2336 java( 2337 """ 2338 package test.pkg; 2339 /** @hide */ 2340 public enum MyEnum { 2341 FOO, BAR 2342 } 2343 """ 2344 ), 2345 2346 java( 2347 """ 2348 package test.pkg; 2349 @SuppressWarnings("UnnecessaryInterfaceModifier") 2350 public interface MyInterface { 2351 public static final String MY_CONSTANT = "5"; 2352 } 2353 """ 2354 ) 2355 ), 2356 privateApi = """ 2357 package test.pkg { 2358 public class Class1 extends test.pkg.PrivateParent implements test.pkg.MyInterface { 2359 ctor Class1(int); 2360 } 2361 private abstract class Class1.AmsTask extends java.util.concurrent.FutureTask { 2362 } 2363 public static abstract class Class1.TouchPoint implements android.os.Parcelable { 2364 ctor public Class1.TouchPoint(); 2365 } 2366 public final class MyEnum extends java.lang.Enum { 2367 ctor private MyEnum(); 2368 enum_constant public static final test.pkg.MyEnum BAR; 2369 enum_constant public static final test.pkg.MyEnum FOO; 2370 } 2371 class PrivateParent { 2372 ctor PrivateParent(); 2373 method final java.lang.String getValue(); 2374 } 2375 } 2376 """, 2377 privateDexApi = """ 2378 Ltest/pkg/Class1;-><init>(I)V 2379 Ltest/pkg/Class1${"$"}AmsTask; 2380 Ltest/pkg/Class1${"$"}TouchPoint; 2381 Ltest/pkg/Class1${"$"}TouchPoint;-><init>()V 2382 Ltest/pkg/MyEnum; 2383 Ltest/pkg/MyEnum;-><init>()V 2384 Ltest/pkg/MyEnum;->valueOf(Ljava/lang/String;)Ltest/pkg/MyEnum; 2385 Ltest/pkg/MyEnum;->values()[Ltest/pkg/MyEnum; 2386 Ltest/pkg/MyEnum;->BAR:Ltest/pkg/MyEnum; 2387 Ltest/pkg/MyEnum;->FOO:Ltest/pkg/MyEnum; 2388 Ltest/pkg/PrivateParent; 2389 Ltest/pkg/PrivateParent;-><init>()V 2390 Ltest/pkg/PrivateParent;->getValue()Ljava/lang/String; 2391 """ 2392 ) 2393 } 2394 2395 @Test Extend from multiple interfacesnull2396 fun `Extend from multiple interfaces`() { 2397 // Real-world example: XmlResourceParser 2398 check( 2399 checkDoclava1 = true, 2400 checkCompilation = true, 2401 sourceFiles = *arrayOf( 2402 java( 2403 """ 2404 package android.content.res; 2405 import android.util.AttributeSet; 2406 import org.xmlpull.v1.XmlPullParser; 2407 import my.AutoCloseable; 2408 2409 @SuppressWarnings("UnnecessaryInterfaceModifier") 2410 public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable { 2411 public void close(); 2412 } 2413 """ 2414 ), 2415 java( 2416 """ 2417 package android.util; 2418 @SuppressWarnings("WeakerAccess") 2419 public interface AttributeSet { 2420 } 2421 """ 2422 ), 2423 java( 2424 """ 2425 package my; 2426 public interface AutoCloseable { 2427 } 2428 """ 2429 ), 2430 java( 2431 """ 2432 package org.xmlpull.v1; 2433 @SuppressWarnings("WeakerAccess") 2434 public interface XmlPullParser { 2435 } 2436 """ 2437 ) 2438 ), 2439 api = """ 2440 package android.content.res { 2441 public abstract interface XmlResourceParser implements android.util.AttributeSet my.AutoCloseable org.xmlpull.v1.XmlPullParser { 2442 method public abstract void close(); 2443 } 2444 } 2445 package android.util { 2446 public abstract interface AttributeSet { 2447 } 2448 } 2449 package my { 2450 public abstract interface AutoCloseable { 2451 } 2452 } 2453 package org.xmlpull.v1 { 2454 public abstract interface XmlPullParser { 2455 } 2456 } 2457 """ 2458 ) 2459 } 2460 2461 @Test Including private interfaces from typesnull2462 fun `Including private interfaces from types`() { 2463 check( 2464 checkDoclava1 = true, 2465 sourceFiles = *arrayOf( 2466 java("""package test.pkg1; interface Interface1 { }"""), 2467 java("""package test.pkg1; abstract class Class1 { }"""), 2468 java("""package test.pkg1; abstract class Class2 { }"""), 2469 java("""package test.pkg1; abstract class Class3 { }"""), 2470 java("""package test.pkg1; abstract class Class4 { }"""), 2471 java("""package test.pkg1; abstract class Class5 { }"""), 2472 java("""package test.pkg1; abstract class Class6 { }"""), 2473 java("""package test.pkg1; abstract class Class7 { }"""), 2474 java("""package test.pkg1; abstract class Class8 { }"""), 2475 java("""package test.pkg1; abstract class Class9 { }"""), 2476 java( 2477 """ 2478 package test.pkg1; 2479 2480 import java.util.List; 2481 import java.util.Map; 2482 public abstract class Usage implements List<Class1> { 2483 <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T> list) {} 2484 public Class3 myClass1 = null; 2485 public List<? extends Class4> myClass2 = null; 2486 public Map<String, ? extends Class5> myClass3 = null; 2487 public <T extends Class6> void mySort(List<Class7> list, T element) {} 2488 public void ellipsisType(Class8... myargs); 2489 public void arrayType(Class9[] myargs); 2490 } 2491 """ 2492 ) 2493 ), 2494 2495 // TODO: Test annotations! (values, annotation classes, etc.) 2496 warnings = """ 2497 src/test/pkg1/Usage.java:12: warning: Parameter myargs references hidden type test.pkg1.Class9[]. [HiddenTypeParameter:121] 2498 src/test/pkg1/Usage.java:11: warning: Parameter myargs references hidden type test.pkg1.Class8.... [HiddenTypeParameter:121] 2499 src/test/pkg1/Usage.java:10: warning: Parameter list references hidden type class test.pkg1.Class7. [HiddenTypeParameter:121] 2500 src/test/pkg1/Usage.java:7: warning: Field Usage.myClass1 references hidden type test.pkg1.Class3. [HiddenTypeParameter:121] 2501 src/test/pkg1/Usage.java:8: warning: Field Usage.myClass2 references hidden type class test.pkg1.Class4. [HiddenTypeParameter:121] 2502 src/test/pkg1/Usage.java:9: warning: Field Usage.myClass3 references hidden type class test.pkg1.Class5. [HiddenTypeParameter:121] 2503 """, 2504 api = """ 2505 package test.pkg1 { 2506 public abstract class Usage implements java.util.List { 2507 ctor public Usage(); 2508 method public void arrayType(test.pkg1.Class9[]); 2509 method public void ellipsisType(test.pkg1.Class8...); 2510 method public <T extends test.pkg1.Class6> void mySort(java.util.List<test.pkg1.Class7>, T); 2511 field public test.pkg1.Class3 myClass1; 2512 field public java.util.List<? extends test.pkg1.Class4> myClass2; 2513 field public java.util.Map<java.lang.String, ? extends test.pkg1.Class5> myClass3; 2514 } 2515 } 2516 """ 2517 ) 2518 } 2519 }