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 Check java typedef extraction and warning about non-source retention of typedefsnull26 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 Check Kotlin and referencing hidden constants from typedefnull105 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 Include merged annotations in exported source annotationsnull182 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 }