Home | History | Annotate | Download | only in metalava
      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 package com.android.tools.metalava
     18 
     19 import org.junit.Ignore
     20 import org.junit.Test
     21 
     22 @SuppressWarnings("ALL") // Sample code
     23 class ExtractAnnotationsTest : DriverTest() {
     24 
     25     @Test
     26     fun `Check java typedef extraction and warning about non-source retention of typedefs`() {
     27         check(
     28             sourceFiles = *arrayOf(
     29                 java(
     30             """
     31                     package test.pkg;
     32 
     33                     import android.annotation.IntDef;
     34                     import android.annotation.IntRange;
     35 
     36                     import java.lang.annotation.Retention;
     37                     import java.lang.annotation.RetentionPolicy;
     38 
     39                     @SuppressWarnings({"UnusedDeclaration", "WeakerAccess"})
     40                     public class IntDefTest {
     41                         @IntDef({STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT})
     42                         @IntRange(from = 20)
     43                         private @interface DialogStyle {}
     44 
     45                         public static final int STYLE_NORMAL = 0;
     46                         public static final int STYLE_NO_TITLE = 1;
     47                         public static final int STYLE_NO_FRAME = 2;
     48                         public static final int STYLE_NO_INPUT = 3;
     49                         public static final int UNRELATED = 3;
     50 
     51                         public void setStyle(@DialogStyle int style, int theme) {
     52                         }
     53 
     54                         public void testIntDef(int arg) {
     55                         }
     56                         @IntDef(value = {STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT, 3, 3 + 1}, flag=true)
     57                         @Retention(RetentionPolicy.SOURCE)
     58                         private @interface DialogFlags {}
     59 
     60                         public void setFlags(Object first, @DialogFlags int flags) {
     61                         }
     62 
     63                         public static final String TYPE_1 = "type1";
     64                         public static final String TYPE_2 = "type2";
     65                         public static final String UNRELATED_TYPE = "other";
     66 
     67                         public static class Inner {
     68                             public void setInner(@DialogFlags int flags) {
     69                             }
     70                         }
     71                     }
     72                     """
     73                 ).indented(),
     74                 intDefAnnotationSource,
     75                 intRangeAnnotationSource
     76             ),
     77             warnings = "src/test/pkg/IntDefTest.java:11: error: This typedef annotation class should have @Retention(RetentionPolicy.SOURCE) [AnnotationExtraction:146]",
     78             extractAnnotations = mapOf("test.pkg" to """
     79                 <?xml version="1.0" encoding="UTF-8"?>
     80                 <root>
     81                   <item name="test.pkg.IntDefTest void setFlags(java.lang.Object, int) 1">
     82                     <annotation name="androidx.annotation.IntDef">
     83                       <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 4}" />
     84                       <val name="flag" val="true" />
     85                     </annotation>
     86                   </item>
     87                   <item name="test.pkg.IntDefTest void setStyle(int, int) 0">
     88                     <annotation name="androidx.annotation.IntDef">
     89                       <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT}" />
     90                     </annotation>
     91                   </item>
     92                   <item name="test.pkg.IntDefTest.Inner void setInner(int) 0">
     93                     <annotation name="androidx.annotation.IntDef">
     94                       <val name="value" val="{test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 4}" />
     95                       <val name="flag" val="true" />
     96                     </annotation>
     97                   </item>
     98                 </root>
     99                 """
    100             )
    101         )
    102     }
    103 
    104     @Test
    105     fun `Check Kotlin and referencing hidden constants from typedef`() {
    106         check(
    107             sourceFiles = *arrayOf(
    108                 kotlin(
    109                     """
    110                     @file:Suppress("unused", "UseExpressionBody")
    111 
    112                     package test.pkg
    113 
    114                     import android.annotation.LongDef
    115 
    116                     const val STYLE_NORMAL = 0L
    117                     const val STYLE_NO_TITLE = 1L
    118                     const val STYLE_NO_FRAME = 2L
    119                     const val STYLE_NO_INPUT = 3L
    120                     const val UNRELATED = 3L
    121                     private const val HIDDEN = 4
    122 
    123                     const val TYPE_1 = "type1"
    124                     const val TYPE_2 = "type2"
    125                     const val UNRELATED_TYPE = "other"
    126 
    127                     class LongDefTest {
    128 
    129                         /** @hide */
    130                         @LongDef(STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT, HIDDEN)
    131                         @Retention(AnnotationRetention.SOURCE)
    132                         private annotation class DialogStyle
    133 
    134                         fun setStyle(@DialogStyle style: Int, theme: Int) {}
    135 
    136                         fun testLongDef(arg: Int) {
    137                         }
    138 
    139                         @LongDef(STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT, 3L, 3L + 1L, flag = true)
    140                         @Retention(AnnotationRetention.SOURCE)
    141                         private annotation class DialogFlags
    142 
    143                         fun setFlags(first: Any, @DialogFlags flags: Int) {}
    144 
    145                         class Inner {
    146                             fun setInner(@DialogFlags flags: Int) {}
    147                             fun isNull(value: String?): Boolean
    148                         }
    149                     }"""
    150                 ).indented(),
    151                 longDefAnnotationSource
    152             ),
    153             warnings = "src/test/pkg/LongDefTest.kt:12: error: Typedef class references hidden field field LongDefTestKt.HIDDEN: removed from typedef metadata [HiddenTypedefConstant:148]",
    154             extractAnnotations = mapOf("test.pkg" to """
    155                 <?xml version="1.0" encoding="UTF-8"?>
    156                 <root>
    157                   <item name="test.pkg.LongDefTest void setFlags(java.lang.Object, int) 1">
    158                     <annotation name="androidx.annotation.LongDef">
    159                       <val name="flag" val="true" />
    160                       <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT, 3, 4}" />
    161                     </annotation>
    162                   </item>
    163                   <item name="test.pkg.LongDefTest void setStyle(int, int) 0">
    164                     <annotation name="androidx.annotation.LongDef">
    165                       <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT}" />
    166                     </annotation>
    167                   </item>
    168                   <item name="test.pkg.LongDefTest.Inner void setInner(int) 0">
    169                     <annotation name="androidx.annotation.LongDef">
    170                       <val name="flag" val="true" />
    171                       <val name="value" val="{test.pkg.LongDefTestKt.STYLE_NORMAL, test.pkg.LongDefTestKt.STYLE_NO_TITLE, test.pkg.LongDefTestKt.STYLE_NO_FRAME, test.pkg.LongDefTestKt.STYLE_NO_INPUT, 3, 4}" />
    172                     </annotation>
    173                   </item>
    174                 </root>
    175                 """
    176             )
    177         )
    178     }
    179 
    180     @Ignore("Not working reliably")
    181     @Test
    182     fun `Include merged annotations in exported source annotations`() {
    183         check(
    184             compatibilityMode = false,
    185             outputKotlinStyleNulls = false,
    186             includeSystemApiAnnotations = false,
    187             omitCommonPackages = false,
    188             warnings = "error: Unexpected reference to Nonexistent.Field [AnnotationExtraction:146]",
    189             sourceFiles = *arrayOf(
    190                 java(
    191                     """
    192                     package test.pkg;
    193 
    194                     public class MyTest {
    195                         public void test(int arg) { }
    196                     }"""
    197                 )
    198             ),
    199             mergeXmlAnnotations = """<?xml version="1.0" encoding="UTF-8"?>
    200                 <root>
    201                   <item name="test.pkg.MyTest void test(int) 0">
    202                     <annotation name="org.intellij.lang.annotations.MagicConstant">
    203                       <val name="intValues" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR, Nonexistent.Field}" />
    204                     </annotation>
    205                   </item>
    206                 </root>
    207                 """,
    208             extractAnnotations = mapOf("test.pkg" to """
    209                 <?xml version="1.0" encoding="UTF-8"?>
    210                 <root>
    211                   <item name="test.pkg.MyTest void test(int) 0">
    212                     <annotation name="androidx.annotation.IntDef">
    213                       <val name="value" val="{java.util.Calendar.ERA, java.util.Calendar.YEAR, java.util.Calendar.MONTH, java.util.Calendar.WEEK_OF_YEAR}" />
    214                     </annotation>
    215                   </item>
    216                 </root>
    217                 """
    218             )
    219         )
    220     }
    221 }