[go: nahoru, domu]

blob: 7eb3408dcd506c8d2ee12b71991a36a7fc2a960d [file] [log] [blame]
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +00001/*
2 * Copyright 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@file:Suppress("UnstableApiUsage")
18
19package androidx.compose.animation.core.lint
20
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +010021import androidx.compose.lint.test.Stubs
Louis Pullen-Freilichbaed27e2023-01-19 20:35:46 +000022import androidx.compose.lint.test.bytecodeStub
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +000023import com.android.tools.lint.checks.infrastructure.LintDetectorTest
24import com.android.tools.lint.detector.api.Detector
25import com.android.tools.lint.detector.api.Issue
26import org.junit.Test
27import org.junit.runner.RunWith
28import org.junit.runners.JUnit4
29
30/* ktlint-disable max-line-length */
31@RunWith(JUnit4::class)
32
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +000033/**
34 * Test for [TransitionDetector].
35 */
36class TransitionDetectorTest : LintDetectorTest() {
37 override fun getDetector(): Detector = TransitionDetector()
38
39 override fun getIssues(): MutableList<Issue> =
40 mutableListOf(TransitionDetector.UnusedTransitionTargetStateParameter)
41
42 // Simplified Transition.kt stubs
Louis Pullen-Freilichbaed27e2023-01-19 20:35:46 +000043 private val TransitionStub = bytecodeStub(
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +010044 filename = "Transition.kt",
45 filepath = "androidx/compose/animation/core",
Louis Pullen-Freiliche0a94762023-11-27 17:52:24 +090046 checksum = 0x7997109d,
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +000047 """
48 package androidx.compose.animation.core
49
50 import androidx.compose.runtime.Composable
51
52 class Transition<S> {
53 class Segment<S>
54 }
55
56 @Composable
57 inline fun <S> Transition<S>.animateFloat(
58 noinline transitionSpec: @Composable Transition.Segment<S>.() -> Unit = {},
59 label: String = "FloatAnimation",
60 targetValueByState: @Composable (state: S) -> Float
61 ): Float = 5f
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +010062 """,
63"""
Louis Pullen-Freilich9675ba22021-08-10 00:37:06 +010064 META-INF/main.kotlin_module:
Louis Pullen-Freiliche0a94762023-11-27 17:52:24 +090065 H4sIAAAAAAAA/2NgYGBmYGBgBGJOBijg0ueST8xLKcrPTKnQS87PLcgvTtVL
66 zMvMTSzJzM8DihSlCvGEFCXmFWeCBLxLuHi5mNPy84XYQlKLS7xLlBi0GAD5
67 +CagWAAAAA==
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +010068 """,
69 """
70 androidx/compose/animation/core/Transition$Segment.class:
Louis Pullen-Freiliche0a94762023-11-27 17:52:24 +090071 H4sIAAAAAAAA/5VRTW/TQBB9u3bixnWpW74SvqGVKDngNqqEBFUlqIRkyYCE
72 q1xy2sSrdBt7jbybqsf8Fv4BJyQOKOLIj0KMTSQkuMDlzbw3M7tvZ7//+PIV
73 wCF2GQZCZ1WpsstoUhYfSiMjoVUhrCo1KZWMTiuhjar5biqnhdTWA2PYO0qf
74 J+fiQkS50NPo3fhcTuyL478lhvBPzYPL0D5SWtljBmfvyTBAG56PFtYYXHum
75 DMNh8v/O6LKtZFbaXOnojbQiE1aQxosLh97LaujUAAY2I/1S1WyfsuyA4fFy
76 Efi8y/3lwuchwXLRXS767hoL2YDv81etbx/bPHTq9gGdkLL6oP6/2/TQY/BW
77 Xhk2fleezoi7J2UmGTYTpeXbeTGW1akY56RsJ+VE5ENRqZqvxCDWWlYnuTBG
78 0ro6qZpqYecVlfy0nFcT+VrVfb33c21VIYfKKBp8qXVpG3cGB+C08tU+6h8g
79 vEssajjQ6n9G5xMlHPcI243o4T5h8KsBPtYpunhA6JPGcQu30cPDZsrBoybe
80 wQ7FZ1QPaGZjBCfGlRibMUJsUYrtGFdxbQRmcB03RnAN1g1uGnQNvJ/VVf1q
81 rwIAAA==
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +010082 """,
83 """
Louis Pullen-Freilich9675ba22021-08-10 00:37:06 +010084 androidx/compose/animation/core/Transition.class:
Louis Pullen-Freiliche0a94762023-11-27 17:52:24 +090085 H4sIAAAAAAAA/41RTW/TQBB9u3HsxE1bt3wlfEN7KBHCbcQpVJWgEpIlAxKu
86 cslpE6/Sbew18m6qHvNb+AeckDigiCM/CjE2kZDgUll6M+/tvNnZ8c9f374D
87 eIl9hr7QaVmo9CqcFvmnwshQaJULqwpNSinDs1JooyrugTEcHCfD+EJcijAT
88 ehZ+mFzIqX118r/EEPyreXAY3GOllT1haBw8G3XgwvPRRIvBsefKMDyPrz8R
89 XbITzwubKR2+k1akwgrSeH7ZoPexCtoVgIHNSb9SFTukLD2im1bLLZ93ub9a
90 +jyooMW7q2Xfaa2WARvwQz5kzpvmj88uDxqVZ0BtElZ18xI5y6W2DIPrT7u/
91 Nnm4y7D5V38xpz7OaZFKhu1Yafl+kU9keSYmGSm7cTEV2UiUquJrsRNpLcvT
92 TBgjaWftRM20sIuSjvykWJRT+VZVdb2PC21VLkfKKDK+1rqw9WwGR+C09/Vy
93 qt9A+IBYWHOg2f+K9hdKOB4SurXo4hFh508BfGxQdPCY0CftHtX26HtSuxp4
94 Wsf72KM4pPMOeTbHaETYirAdIcAOpdiNcAM3x2AGt3B7jKbBhsEdg66BZ9D7
95 DXTP2E6vAgAA
Louis Pullen-Freilich9675ba22021-08-10 00:37:06 +010096 """,
97 """
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +010098 androidx/compose/animation/core/TransitionKt$animateFloat$1.class:
Louis Pullen-Freiliche0a94762023-11-27 17:52:24 +090099 H4sIAAAAAAAA/81WX1MbVRT/3U0gyZLyJ6V/AEUssYWAXYLYKkmxkRJZCSk2
100 kRmHp5vkNixs7nZ2Nxl846EfwU/gJ2h1xjo64zA++qEcz91sKbHRFnzxIfee
101 e875nX855yR//PnLbwBWUGXIcdlwHatxZNSd1hPHEwaXVov7liOJ4wqj6nLp
102 Weq95ae7MlG0He6nszEwhqelQ8e3LWkcdFqGJX3hSm4bJd6qNXjurOxxW9aV
103 Gc8ohlQ2X3p77+mKaLaE9PPVSm7t1PDX0vLpyTD5z1HEEGWY/vdIYhhkGMxb
104 ZG6NITI3v8sQnTPnd5OIQ9cxgCFi+PuWx3DvHFG/VjMKddCSHedQMNydu0D+
105 ORVa/iLIbuUUfLbkuE3jQPg1l1tUBi6l4/NuScqOX27bNsWpp1W+aUmvOC73
106 lvC0xKb0XTJh1b0YrjBcqe+L+mFoY4e7vCVIkeHWXOmAd7hhc9k0HtYORN3P
107 neFUlJFmTpX7Gq7ruIoJhpWLVIfhZh9X86+zGJbPbz6Gd5MYwagODe8xDJ3p
108 whjeZ4ib5Uq1UF7fYLjU06JJzCKdwA18wKA9yTKk+kUUz9ftoAVV1yWUk4wC
109 DieIWmQYe2lyW/i8wX1OEK3VidAsM3Uk1AEGdqiICAmPLEU9I6pBPldOjof1
110 k2NdG9WC67q6Rk+OJ7UldiMaJ1rLxFPRlLapLUU29d+/H9TiUYVdplTzXDry
111 25bT9mhAlJMKw+J5BiGGewzjPdPQEI952/YZvjtPP79pq/RprDchzD4tU0zi
112 M9xnyLx9ZDF8zhALe4Va4JXk9iG9M31XZcVpu3XxQNTazY0jXxCAUmQY6HC7
113 TUviaWW7sKP3WNK3AjN6pjLzkirqCzPZmV6t/7Cl9ExJz85mF7N3Vone0Gn3
114 rTsNodrWqXN7l7sWr9miqg6GkZIlRbndqgk35CQqVlNyv+0SnX7Ulr7VEqbs
115 WJ5F4tO1UHi1dhiSppTCXbe55wl6jmzIuu149OVRs+87DVpH3UIVLeVgvF/V
116 GCZCX7tdTz0Opv4exxkpsjRhA9TV9JOGCTVyNDZRomkM6TTplSYNanwMZqIv
117 kHweDNqXdCa7XFwKMGNqOyASIHKE0OiOLaTGf8akgmjYCpTpR4CACn61qxLC
118 FXUZUyQvBdpj2FY8mjakgNECWX8njOd+aD2ZWTjB9E+Y+QE3n/W4QI+L5KmL
119 JG5hLsht/jS7a4EOMPQrtG9eYOFHfPg8jKdMZ4rE01jHAypOV3ECD4MSraEQ
120 xhrBTnBv4Cu6/xdti0cUySqleJu+XGMPERNLJrImlvGRSf9/PjZxB3f3wDx8
121 gk/3MOBh1UPOQ97DlEfFrhB+mPBF+nwR6G3+BSprltw9CQAA
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +0100122 """,
123 """
Louis Pullen-Freilich9675ba22021-08-10 00:37:06 +0100124 androidx/compose/animation/core/TransitionKt.class:
Louis Pullen-Freiliche0a94762023-11-27 17:52:24 +0900125 H4sIAAAAAAAA/8VWz1PbVhD+nizbsjFgFKDgJG5KnAQIRMZQt40dGkKhqDFO
126 pqZcOHQe9sMRyBIjyUxy6dBe+g/0klunhx576CnTQ4ch00v/pk6nK2EbgztD
127 3EsP2h9v3367+96+tf/8+7ffASzhOcMct2qObdRealW7cWi7QuOW0eCeYVu0
128 4ghty+GWa/j6Uy8KxpDc50dcM7lV157t7osqrYYYEmduYt20ucfw7XTp3YEL
129 pQPbMw1L2z9qaHtNq+ovutp6S1oolM5DVjzHsOpXesysM/xVrDwsXU62sNxP
130 ZsWtSmH5qmDF+T4QMxVRbwjLu4j8lWV4vtpvncV5gunyCk6fgPzy7/Rm5TQt
131 z2gIbTXQ+a4pCgy3S7ZT1/aFt+twg8C5ZdkePwtUtr1y0zRpV6TovTDcZQVx
132 hnRXUoblCcfipqZbfsauUXWjSDCMVV+I6kHL/zl3eEPQRoZ7071X0lv2zHYC
133 QxiOYxBJhiGvc3yVQ1FVoDKETb4rTAWjDKrHnbrwtrnZFE9eVSh3oWBcfvwj
134 wDCSMTJ7mYvNyXRyyvj1XDLM9dO0DLeu6kIK01sbw2h31ExN7PGmSdF/+J/f
135 jN57M34fFfqZEBcONLMQxQcMil6ubK2UV9cYHvVRYQ9YIYHbyMQwhTsXe/Bf
136 ioniHvVN4LjSDqBghuFm771/3cwtdS5hpH1Km8LjNe5xui+pcRSiecl8EvMJ
137 9RU78AWJjC8NX8qSVFtg+OPkOBc/OY5LyWjAJqQ2C76k1JGDTUMdqyKlvOTJ
138 cUrKsilZOTlOSrOKKqvShpQN5TJKPCmn0mpcba9FfJ6NZsOnP0UkRQloLKco
139 UjJOEAO5u8lEakq9po5sSGRLKIOqogypsqJMDweerO25cfq98vYNOzk+/U6K
140 xsPK6etclvnF5FhQZ8Vv4taZdHf20n8YeuSWbmOtvfQEmW2rDbr16tAfR+Pt
141 DZ2hUSZGBtkiTg/f9R84Q67/8FE8Zph9d78onjBEW84Mg+eWBweky6t2jRIZ
142 LhmWKDcbu8LZ8keqf152lZvb3DF8vbUYqxh1i3tNh+TrX54NYt06MlyDzCvn
143 M5chc9naOYkL2wZp0lUPNvlhK0BCtyzhrJrcdQWZ4xW76VTFuuHbJluQ2z3h
144 sAAJst/TxCcRRoS0ddIOSQ8TT8+qA28wcl+9RnROHSM6r75HNJSX1YlfAr/P
145 iUaoWa5jGBvBP4swySHCSwXYadJuBDHSUHGTdvrSKH1SII3TWgh6gBXFFy00
146 hfhT+iZlUmLBq7tEkzG8j1sk+wn/TM4R4vkxWf7mNeK/4u4Jpktjcpi0iDq7
147 eWUhIZSIypCGYkFJqQBvgFLyf40GMEY/RxPEF7vKXOwqM4/7rTLznTLznTLz
148 rTJD2CRNpbUVrOIz8p4KfCZRDg5gDc+I75D3HOHP7yCk44EOTUcWCzpyWNQp
149 8oe0wSXMj3aQdOlR4GMXn7i44UJ18dBFIVhRXBRdjAbyuItHLpZdfPoPx8wC
150 mQAKAAA=
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +0000151 """
152 )
153
154 @Test
155 fun unreferencedParameters() {
156 lint().files(
157 kotlin(
158 """
159 package foo
160
161 import androidx.compose.animation.core.*
162 import androidx.compose.runtime.*
163
164 val transition = Transition<Boolean>()
165
166 var foo = false
167
168 @Composable
169 fun Test() {
170 transition.animateFloat { if (foo) 1f else 0f }
171 transition.animateFloat(targetValueByState = { if (foo) 1f else 0f })
172 transition.animateFloat { param -> if (foo) 1f else 0f }
173 transition.animateFloat(targetValueByState = { param -> if (foo) 1f else 0f })
174 transition.animateFloat { _ -> if (foo) 1f else 0f }
175 transition.animateFloat(targetValueByState = { _ -> if (foo) 1f else 0f })
176 }
177 """
178 ),
179 TransitionStub,
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +0100180 Stubs.Composable
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +0000181 )
182 .run()
183 .expect(
184 """
185src/foo/test.kt:13: Error: Target state parameter it is not used [UnusedTransitionTargetStateParameter]
186 transition.animateFloat { if (foo) 1f else 0f }
187 ~~~~~~~~~~~~~~~~~~~~~~~
188src/foo/test.kt:14: Error: Target state parameter it is not used [UnusedTransitionTargetStateParameter]
189 transition.animateFloat(targetValueByState = { if (foo) 1f else 0f })
190 ~~~~~~~~~~~~~~~~~~~~~~~
191src/foo/test.kt:15: Error: Target state parameter param is not used [UnusedTransitionTargetStateParameter]
192 transition.animateFloat { param -> if (foo) 1f else 0f }
193 ~~~~~
194src/foo/test.kt:16: Error: Target state parameter param is not used [UnusedTransitionTargetStateParameter]
195 transition.animateFloat(targetValueByState = { param -> if (foo) 1f else 0f })
196 ~~~~~
197src/foo/test.kt:17: Error: Target state parameter _ is not used [UnusedTransitionTargetStateParameter]
198 transition.animateFloat { _ -> if (foo) 1f else 0f }
199 ~
200src/foo/test.kt:18: Error: Target state parameter _ is not used [UnusedTransitionTargetStateParameter]
201 transition.animateFloat(targetValueByState = { _ -> if (foo) 1f else 0f })
202 ~
2036 errors, 0 warnings
204 """
205 )
206 }
207
208 @Test
209 fun unreferencedParameter_shadowedNames() {
210 lint().files(
211 kotlin(
212 """
213 package foo
214
215 import androidx.compose.animation.core.*
216 import androidx.compose.runtime.*
217
218 val transition = Transition<Boolean>()
219
220 var foo = false
221
222 @Composable
223 fun Test() {
224 transition.animateFloat {
225 foo.let {
Louis Pullen-Freilich087f4452021-03-22 21:26:17 +0000226 // These `it`s refer to the `let`, not the `animateFloat`, so we
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +0000227 // should still report an error
228 it.let {
229 if (it) 1f else 0f
230 }
231 }
232 }
233 transition.animateFloat { param ->
234 foo.let { param ->
Louis Pullen-Freilich087f4452021-03-22 21:26:17 +0000235 // This `param` refers to the `let`, not the `animateFloat`, so we
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +0000236 // should still report an error
237 if (param) 1f else 0f
238 }
239 }
240 }
241 """
242 ),
243 TransitionStub,
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +0100244 Stubs.Composable
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +0000245 )
246 .run()
247 .expect(
248 """
249src/foo/test.kt:13: Error: Target state parameter it is not used [UnusedTransitionTargetStateParameter]
250 transition.animateFloat {
251 ^
252src/foo/test.kt:22: Error: Target state parameter param is not used [UnusedTransitionTargetStateParameter]
253 transition.animateFloat { param ->
254 ~~~~~
2552 errors, 0 warnings
256 """
257 )
258 }
259
260 @Test
261 fun noErrors() {
262 lint().files(
263 kotlin(
264 """
265 package foo
266
267 import androidx.compose.animation.core.*
268 import androidx.compose.runtime.*
269
270 val transition = Transition<Boolean>()
271
272 var foo = false
273
274 @Composable
275 fun Test() {
276 transition.animateFloat { if (it) 1f else 0f }
277 transition.animateFloat(targetValueByState = { if (it) 1f else 0f })
278 transition.animateFloat { param -> if (param) 1f else 0f }
279 transition.animateFloat(targetValueByState = { param -> if (param) 1f else 0f })
280 transition.animateFloat { param ->
281 foo.let {
282 it.let {
283 if (param && it) 1f else 0f
284 }
285 }
286 }
287 transition.animateFloat {
288 foo.let { param ->
289 param.let { param ->
290 if (param && it) 1f else 0f
291 }
292 }
293 }
294
295 transition.animateFloat {
296 foo.run {
297 run {
298 if (this && it) 1f else 0f
299 }
300 }
301 }
302
Louis Pullen-Freilich087f4452021-03-22 21:26:17 +0000303 fun multipleParameterLambda(lambda: (Boolean, Boolean) -> Float): Float
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +0000304 = lambda(true, true)
305
306 transition.animateFloat {
307 multipleParameterLambda { _, _ ->
308 multipleParameterLambda { param1, _ ->
309 if (param1 && it) 1f else 0f
310 }
311 }
312 }
313 }
314 """
315 ),
316 TransitionStub,
Louis Pullen-Freilichcafae152021-06-02 21:40:39 +0100317 Stubs.Composable
Louis Pullen-Freilich0f84a102021-03-16 22:41:00 +0000318 )
319 .run()
320 .expectClean()
321 }
322}
323/* ktlint-enable max-line-length */