1 /* 2 * Copyright (C) 2021 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.metalava.model.VisibilityLevel 20 import com.android.tools.metalava.model.noOpAnnotationManager 21 import com.android.tools.metalava.model.testsuite.BaseModelTest 22 import com.android.tools.metalava.testing.KnownSourceFiles.jetbrainsNullableTypeUseSource 23 import com.android.tools.metalava.testing.java 24 import com.android.tools.metalava.testing.kotlin 25 import com.google.common.truth.Truth.assertThat 26 import kotlin.test.Test 27 import kotlin.test.assertEquals 28 import kotlin.test.assertFalse 29 import kotlin.test.assertTrue 30 31 class PsiModifierItemTest : BaseModelTest() { 32 @Test Test type-use nullability annotation used from Java and Kotlin sourcenull33 fun `Test type-use nullability annotation used from Java and Kotlin source`() { 34 val javaSource = 35 java( 36 """ 37 package test.pkg; 38 public class Foo { 39 public @org.jetbrains.annotations.Nullable String foo() {} 40 } 41 """ 42 .trimIndent() 43 ) 44 val kotlinSource = 45 kotlin( 46 """ 47 package test.pkg 48 class Foo { 49 fun foo(): String? 50 } 51 """ 52 .trimIndent() 53 ) 54 55 runCodebaseTest( 56 inputSet(javaSource, jetbrainsNullableTypeUseSource), 57 inputSet(kotlinSource, jetbrainsNullableTypeUseSource), 58 testFixture = 59 TestFixture( 60 // Use the noOpAnnotationManager to avoid annotation name normalizing as the 61 // annotation names are important for this test. 62 annotationManager = noOpAnnotationManager, 63 ), 64 ) { 65 val method = codebase.assertClass("test.pkg.Foo").methods().single() 66 // For now, the nullability annotation needs to be attached to the method. 67 assertThat(method.annotationNames()) 68 .containsExactly("org.jetbrains.annotations.Nullable") 69 } 70 } 71 72 @Test Kotlin implicit internal visibility inheritancenull73 fun `Kotlin implicit internal visibility inheritance`() { 74 runCodebaseTest( 75 kotlin( 76 """ 77 open class Base { 78 internal open fun method(): Int = 1 79 internal open val property: Int = 2 80 } 81 82 class Inherited : Base() { 83 override fun method(): Int = 3 84 override val property = 4 85 } 86 """ 87 ) 88 ) { 89 val inherited = codebase.assertClass("Inherited") 90 val method = inherited.methods().first { it.name().startsWith("method") } 91 val property = inherited.properties().single() 92 93 assertEquals(VisibilityLevel.INTERNAL, method.modifiers.getVisibilityLevel()) 94 assertEquals(VisibilityLevel.INTERNAL, property.modifiers.getVisibilityLevel()) 95 } 96 } 97 98 @Test Kotlin class visibility modifiersnull99 fun `Kotlin class visibility modifiers`() { 100 runCodebaseTest( 101 kotlin( 102 """ 103 internal class Internal 104 public class Public 105 class DefaultPublic 106 abstract class Outer { 107 private class Private 108 protected class Protected 109 } 110 """ 111 ) 112 ) { 113 assertTrue(codebase.assertResolvedClass("Internal").isInternal) 114 assertTrue(codebase.assertClass("Public").isPublic) 115 assertTrue(codebase.assertClass("DefaultPublic").isPublic) 116 assertTrue(codebase.assertClass("Outer.Private").isPrivate) 117 assertTrue(codebase.assertClass("Outer.Protected").isProtected) 118 } 119 } 120 121 @Test Kotlin class abstract and final modifiersnull122 fun `Kotlin class abstract and final modifiers`() { 123 runCodebaseTest( 124 kotlin( 125 """ 126 abstract class Abstract 127 sealed class Sealed 128 open class Open 129 final class Final 130 class FinalDefault 131 interface Interface 132 annotation class Annotation 133 """ 134 ) 135 ) { 136 codebase.assertClass("Abstract").modifiers.let { 137 assertTrue(it.isAbstract()) 138 assertFalse(it.isSealed()) 139 assertFalse(it.isFinal()) 140 } 141 142 codebase.assertClass("Sealed").modifiers.let { 143 assertTrue(it.isAbstract()) 144 assertTrue(it.isSealed()) 145 assertFalse(it.isFinal()) 146 } 147 148 codebase.assertClass("Open").modifiers.let { 149 assertFalse(it.isAbstract()) 150 assertFalse(it.isFinal()) 151 } 152 153 codebase.assertClass("Final").modifiers.let { 154 assertFalse(it.isAbstract()) 155 assertTrue(it.isFinal()) 156 } 157 158 codebase.assertClass("FinalDefault").modifiers.let { 159 assertFalse(it.isAbstract()) 160 assertTrue(it.isFinal()) 161 } 162 163 codebase.assertClass("Interface").modifiers.let { 164 assertTrue(it.isAbstract()) 165 assertFalse(it.isFinal()) 166 } 167 168 codebase.assertClass("Annotation").modifiers.let { 169 assertTrue(it.isAbstract()) 170 assertFalse(it.isFinal()) 171 } 172 } 173 } 174 175 @Test Kotlin class type modifiersnull176 fun `Kotlin class type modifiers`() { 177 runCodebaseTest( 178 kotlin( 179 """ 180 inline class Inline(val value: Int) 181 value class Value(val value: Int) 182 data class Data(val data: Int) { 183 companion object { 184 const val DATA = 0 185 } 186 } 187 fun interface FunInterface { 188 fun foo() 189 } 190 """ 191 ) 192 ) { 193 assertTrue(codebase.assertClass("Inline").modifiers.isInline()) 194 assertTrue(codebase.assertClass("Value").modifiers.isValue()) 195 assertTrue(codebase.assertClass("Data").modifiers.isData()) 196 assertTrue(codebase.assertClass("Data.Companion").modifiers.isCompanion()) 197 assertTrue(codebase.assertClass("FunInterface").modifiers.isFunctional()) 198 } 199 } 200 201 @Test Kotlin class static modifiersnull202 fun `Kotlin class static modifiers`() { 203 runCodebaseTest( 204 kotlin( 205 """ 206 class TopLevel { 207 inner class Inner 208 class Nested 209 interface Interface 210 annotation class Annotation 211 object Object 212 } 213 object Object 214 """ 215 ) 216 ) { 217 assertFalse(codebase.assertClass("TopLevel").modifiers.isStatic()) 218 assertFalse(codebase.assertClass("TopLevel.Inner").modifiers.isStatic()) 219 assertFalse(codebase.assertClass("Object").modifiers.isStatic()) 220 221 assertTrue(codebase.assertClass("TopLevel.Nested").modifiers.isStatic()) 222 assertTrue(codebase.assertClass("TopLevel.Interface").modifiers.isStatic()) 223 assertTrue(codebase.assertClass("TopLevel.Annotation").modifiers.isStatic()) 224 assertTrue(codebase.assertClass("TopLevel.Object").modifiers.isStatic()) 225 } 226 } 227 228 @Test Kotlin vararg parametersnull229 fun `Kotlin vararg parameters`() { 230 runCodebaseTest( 231 kotlin( 232 "Foo.kt", 233 """ 234 fun varArg(vararg parameter: Int) { TODO() } 235 fun nonVarArg(parameter: Int) { TODO() } 236 """ 237 ) 238 ) { 239 val facade = codebase.assertClass("FooKt") 240 val varArg = facade.methods().single { it.name() == "varArg" }.parameters().single() 241 val nonVarArg = 242 facade.methods().single { it.name() == "nonVarArg" }.parameters().single() 243 244 assertTrue(varArg.modifiers.isVarArg()) 245 assertFalse(nonVarArg.modifiers.isVarArg()) 246 } 247 } 248 } 249