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