Merge "Revert^2 "Runtime micro-optimizations"" into androidx-main
diff --git a/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/ActivityComposeIssueRegistry.kt b/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/ActivityComposeIssueRegistry.kt
index 5eb0a32..586ba0c 100644
--- a/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/ActivityComposeIssueRegistry.kt
+++ b/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/ActivityComposeIssueRegistry.kt
@@ -31,7 +31,8 @@
get() =
listOf(
ActivityResultLaunchDetector.LaunchDuringComposition,
- CollectProgressDetector.NoCollectCallFound
+ CollectProgressDetector.NoCollectCallFound,
+ LocalContextCastIssueDetector.ContextCastToActivity
)
override val vendor =
diff --git a/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/LocalContextCastIssueDetector.kt b/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/LocalContextCastIssueDetector.kt
new file mode 100644
index 0000000..fa22ec7
--- /dev/null
+++ b/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/LocalContextCastIssueDetector.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.activity.compose.lint
+
+import androidx.compose.lint.Name
+import androidx.compose.lint.Package
+import androidx.compose.lint.inheritsFrom
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiClassOwner
+import java.util.EnumSet
+import org.jetbrains.uast.UBinaryExpressionWithType
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.tryResolveNamed
+import org.jetbrains.uast.util.isTypeCast
+
+class LocalContextCastIssueDetector : Detector(), SourceCodeScanner {
+ private val activityType = Name(Package("android.app"), "Activity")
+ private val contextType = Name(Package("android.content"), "Context")
+
+ override fun getApplicableUastTypes() = listOf(UBinaryExpressionWithType::class.java)
+
+ override fun createUastHandler(context: JavaContext) =
+ object : UElementHandler() {
+ override fun visitBinaryExpressionWithType(node: UBinaryExpressionWithType) {
+ // Cast expression
+ if (node.isTypeCast()) {
+ // RHS is Activity
+ if (node.type.inheritsFrom(activityType)) {
+ // LHS is Context
+ if (node.operand.getExpressionType()?.inheritsFrom(contextType) == true) {
+ // Check to see if LHS is a call to LocalContext.current - the receiver
+ // will be LocalContext
+ val resolvedReceiver =
+ (node.operand as? UQualifiedReferenceExpression)
+ ?.receiver
+ ?.tryResolveNamed() ?: return
+ if (
+ resolvedReceiver.name == "LocalContext" &&
+ (resolvedReceiver.containingFile as? PsiClassOwner)
+ ?.packageName == "androidx.compose.ui.platform"
+ ) {
+ context.report(
+ ContextCastToActivity,
+ node,
+ context.getNameLocation(node),
+ DESCRIPTION
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ private const val DESCRIPTION =
+ "LocalContext should not be cast to Activity, use LocalActivity instead"
+ val ContextCastToActivity =
+ Issue.create(
+ "ContextCastToActivity",
+ DESCRIPTION,
+ "Casting Context to Activity is an error as Contexts are not always Activities. Use LocalActivity instead",
+ Category.CORRECTNESS,
+ 3,
+ Severity.ERROR,
+ Implementation(
+ LocalContextCastIssueDetector::class.java,
+ EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
+ )
+ )
+ }
+}
diff --git a/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/LocalContextCastIssueDetectorTest.kt b/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/LocalContextCastIssueDetectorTest.kt
new file mode 100644
index 0000000..fe8da96
--- /dev/null
+++ b/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/LocalContextCastIssueDetectorTest.kt
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.activity.compose.lint
+
+import androidx.compose.lint.test.Stubs
+import androidx.compose.lint.test.bytecodeStub
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class LocalContextCastIssueDetectorTest : LintDetectorTest() {
+ override fun getDetector(): Detector = LocalContextCastIssueDetector()
+
+ override fun getIssues(): MutableList =
+ mutableListOf(LocalContextCastIssueDetector.ContextCastToActivity)
+
+ val LocalActivityStub =
+ bytecodeStub(
+ "LocalActivity.kt",
+ "androidx/activity/compose",
+ 0xfc1de7e2,
+ """
+ package androidx.activity.compose
+
+ import android.app.Activity
+ import androidx.compose.runtime.compositionLocalOf
+
+ val LocalActivity = compositionLocalOf()
+ """
+ .trimIndent(),
+ """
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAA/2XLTQrCMBAF4BFBcFwUAoKCK5dS4hmKy7r0AiGNMJA/kqnU
+ 2xticOPAbN77HgCsAWBVfgvtsMej8lMKNC1SaaYX8Vvq4GLIRnT3oJUdWjwy
+ Sjz8dEMyzZ7JGSFuNSCm4Ouu+Cue/vxMMlrFz5Cc6IZvW30ugz3uipNmUS5a
+ IzYPk3nkM1zgA8GrRwe+AAAA
+ """,
+ """
+ androidx/activity/compose/LocalActivityKt.class:
+ H4sIAAAAAAAA/61STW/TQBB967itY9I2LdCPlM+0QAJSN0UgJFJVqipVskgT
+ RFEvPW1sN9o0sSt7HZVbfgu/gI8L4oAijvwoxKyTgJrCpcKSd2fezns7Mzs/
+ fn79BuAZHjOUReBFofTOuXCV7En1jrth9yyMfV4LXdHZHaGv1AwYQ74teoJ3
+ RNDijWbbdwnNENry1YVohhelcu239FgxSgIluz5/HYU96Ylmx99LT6SSYZAK
+ VBkaV2Nuj0lcnJ3xcSLVHVJcr4VRi7d91YyEDGIugiBUQjNjXg9VPenoe2cn
+ Knh+pfxzyMLOwsA1Bmvb7chAqh2GTKl8xPDkn4qTOrrd8wwFdwJvnGx4/olI
+ OoqhXaqdhopu4O1el58kgTssaX9kVapObfK5qld7lRwWsGgjj+sMB//5dRbG
+ VRz4SnhCCcKMbi9DE8r0ktULGNipNgw6PJfaqpDlbTFsDvpz9qBvGyvG8LeM
+ 4nJ+0C9Yi+aiUTEq7Pv7aYsiCqaVyZua9ZRh6e8J0SxfGIPNU2p09lC2AqGS
+ yGdYezOs1Ql6MpZU6e6fYWIw90KPguZrMvDrSbfpR291NxjswzCJXH9famd1
+ pHF0SQFbNDlmWm5BDxJ5G7po3MQD2qcJt1J/FVPkZfCQvFuE6s/8hNyHlPto
+ FKvXIX/mAt/CLObI1uwi0v7CZib7ghufkft4ScNAKVVZR5n2l4Qu0f3Lx8g4
+ WHGw6lC2aw4lctvBHdw9BotxD/ePMRUjG8OOUYy1Pf0LK8v1wXoEAAA=
+ """
+ )
+
+ val LocalContextStub =
+ bytecodeStub(
+ "AndroidLocals.kt",
+ "androidx/compose/ui/platform",
+ 0xac8d2426,
+ """
+ package androidx.compose.ui.platform
+
+ import android.content.Context
+ import androidx.compose.runtime.staticCompositionLocalOf
+
+ val LocalContext = staticCompositionLocalOf()
+ """,
+ """
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAA/2NgYGBmYGBgBGJOBijg0uOSSMxLKcrPTKnQS87PLcgvTtUr
+ Ks0rycxNFRJyBgtklmTm5/nkJyfmeJdw6XPJYKgvzdQryEksScsvyhXid4TI
+ gtUXAzWIcnED1emlViTmFuSkCrGFpBaXeJcoMWgxAACzjsPdkAAAAA==
+ """,
+ """
+ androidx/compose/ui/platform/AndroidLocalsKt.class:
+ H4sIAAAAAAAA/61Ty07bQBQ94xhw3JQE+oBAHxRoG9oKh6pVpQYhISQkq+Eh
+ qNiwmthONMGZQfY4Ysm39Av62FRdVKjLflTVO05QBYgNqiV77uucuWfm+vef
+ Hz8BvMELhldchokS4YkXqN6xSiMvE95xzHVbJT1vfZBsqoDH6Qc9BsZQ6fI+
+ 92IuO95OqxsFFC0wlDuRzss2lNTRiWZ4V1tqXiFPMqlFL/J2E9UXIW/F0Uae
+ EVoomeMbDHs3Q66egwhDPUjtDXtprBHpQlMlHa8b6VbChUw9LqXS3IBTb1vp
+ 7Sw2W5cuanh7IwUlFOEWYeEWg7MaxEIKvcZQqC0dMLy8lvEyjznvMsNcatoM
+ Lmd32oth1OZZTG12a80jpWkfr9vvee1MBgNdm0Or3vCbl2+tcbPbKWECky4q
+ uMOw+/9vaeJcyFakecg1p5jV6xdoXJn5FM0HDOzIGBYlT4Sx6mSFKwzLZ6fj
+ 7tmpa01bg9ex5qcqZ6czzqQ9adWtOvv1adShihnbKVRsg3rNUL22Jxr3C//A
+ 8hEdd3FfdCTXWRIxzO4NFPuyL1JBetf/zRWDvaFCKio3hYy2s14rSj6aM2Fw
+ 91WWBNGmME51yHFwhQErNEV2rnjGDBV5i0Y37uEpraMUd3K/ihHyCnhG3gOK
+ msf+itLnHPt8WAuMDfFjF/AObmOcbIOeR37EcJnNvuPuN5S+XOGwUMtZFrBE
+ 63uK3qf9pw5R8DHto+pTt7M+NfLQxyM8PgRLMYcnhxhJUUzhpphPjT36F/cv
+ 7rmKBAAA
+ """
+ )
+
+ val ContextStub =
+ bytecodeStub(
+ "Context.kt",
+ "android/content",
+ 0x7e746f3f,
+ """
+ package android.content
+
+ class Context()
+ """
+ .trimIndent(),
+ """
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAA/2NgYGBmYGBgBGJOBijg0uOSSMxLKcrPTKnQS87PLcgvTtUr
+ Ks0rycxNFRJyBgtklmTm5/nkJyfmeJdw6XPJYKgvzdQryEksScsvyhXid4TI
+ gtUXAzWIcnED1emlViTmFuSkCrGFpBaXeJcoMWgxAACzjsPdkAAAAA==
+ """,
+ """
+ android/content/Context.class:
+ H4sIAAAAAAAA/3VRy04CMRQ9twODjigPH4CvtbpwgLjTmCiJCQlqooYNq8JM
+ tDw6CVMIS77FP3Bl4sIQl36U8XZk6+b0PO5tb9vvn49PAGc4IJSkDsaRCvxe
+ pE2ojd+w68xkQIR8X06lP5T62b/v9sMeuw7BvVBamUuCc3TcziIN10MKGULK
+ vKiYUGn9s+c5odAaRGaotH8bGhlII9kTo6nD45CFVQsg0ID9mbKqyiyoEQ4X
+ c88TZeGJPLPFvLyY10WVrtNfr67IC1tVJ9vrLY87HRieqREFISHXUjq8m4y6
+ 4fhJdofsFFtRTw7bcqysXpreYzQZ98IbZUXlYaKNGoVtFStOr7SOjDQq0jFq
+ EHzl5aj2BRjLrPxEA+mTd6y8MRGoMLqJ6WCXMftXgFV4Sb6XYAn7yY8Q1jjL
+ duA0sd7ERhM55Jmi0EQRmx1QjC1scx7Di7ETw/0FYlRJz84BAAA=
+ """
+ )
+
+ @Test
+ fun errors() {
+ lint()
+ .files(
+ kotlin(
+ """
+ package com.example
+
+ import android.app.Activity
+ import androidx.compose.runtime.Composable
+ import androidx.compose.ui.platform.LocalContext
+
+ class MyActivity: Activity()
+
+ @Composable
+ fun Test() {
+ val activity: Activity = LocalContext.current as Activity
+ val activity2 = LocalContext.current as? Activity
+ val activity3 = LocalContext.current as? MyActivity
+ }
+ """
+ .trimIndent()
+ ),
+ Stubs.Composable,
+ Stubs.CompositionLocal,
+ LocalContextStub,
+ ContextStub
+ )
+ .run()
+ .expect(
+ """
+ src/com/example/MyActivity.kt:11: Error: LocalContext should not be cast to Activity, use LocalActivity instead [ContextCastToActivity]
+ val activity: Activity = LocalContext.current as Activity
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ src/com/example/MyActivity.kt:12: Error: LocalContext should not be cast to Activity, use LocalActivity instead [ContextCastToActivity]
+ val activity2 = LocalContext.current as? Activity
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ src/com/example/MyActivity.kt:13: Error: LocalContext should not be cast to Activity, use LocalActivity instead [ContextCastToActivity]
+ val activity3 = LocalContext.current as? MyActivity
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 3 errors, 0 warnings
+ """
+ .trimIndent()
+ )
+ }
+
+ @Test
+ fun clean() {
+ lint()
+ .files(
+ kotlin(
+ """
+ package com.example
+
+ import android.app.Activity
+ import androidx.activity.ComponentActivity
+ import androidx.activity.compose.LocalActivity
+ import androidx.compose.runtime.Composable
+ import androidx.compose.ui.platform.LocalContext
+
+ @Composable
+ fun Test() {
+ val context = LocalContext.current
+ val activity: Activity = LocalActivity.current as Activity
+ val activity2 = LocalContext.current as ComponentActivity
+ }
+ """
+ .trimIndent()
+ ),
+ Stubs.Composable,
+ Stubs.CompositionLocal,
+ LocalActivityStub,
+ LocalContextStub,
+ ContextStub,
+ COMPONENT_ACTIVITY
+ )
+ .run()
+ .expectClean()
+ }
+}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt
index a6081aa..2da4d5f 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt
@@ -96,9 +96,15 @@
Log.debug { "Empty capture session quirk completed" }
}
}
- Threading.runBlockingChecked(threads.backgroundDispatcher, 5000L) {
+ Threading.runBlockingCheckedOrNull(threads.backgroundDispatcher, CAMERA_CLOSE_TIMEOUT_MS) {
cameraDevice.closeWithTrace()
}
+ ?: run {
+ Log.error {
+ "Camera device close timed out after ${CAMERA_CLOSE_TIMEOUT_MS}ms. " +
+ "The camera is likely in a bad state."
+ }
+ }
if (camera2Quirks.shouldWaitForCameraDeviceOnClosed(cameraId)) {
Log.debug { "Waiting for OnClosed from $cameraId" }
if (androidCameraState.awaitCameraDeviceClosed(timeoutMillis = 5000)) {
@@ -158,4 +164,8 @@
}
sessionConfigured.await()
}
+
+ companion object {
+ const val CAMERA_CLOSE_TIMEOUT_MS = 8_000L // 8s
+ }
}
diff --git a/compose/lint/common-test/src/main/java/androidx/compose/lint/test/Stubs.kt b/compose/lint/common-test/src/main/java/androidx/compose/lint/test/Stubs.kt
index d01e748..96a6a6a 100644
--- a/compose/lint/common-test/src/main/java/androidx/compose/lint/test/Stubs.kt
+++ b/compose/lint/common-test/src/main/java/androidx/compose/lint/test/Stubs.kt
@@ -1460,6 +1460,143 @@
RlEikLgj4eZ2WcKWWJFYlaj8BpHq1rYeAwAA
"""
)
+
+ val CompositionLocal =
+ bytecodeStub(
+ filename = "CompositionLocal.kt",
+ filepath = "androidx/compose/runtime",
+ checksum = 0xa5bf3022,
+ """
+ package androidx.compose.runtime
+
+ sealed class CompositionLocal constructor(defaultFactory: (() -> T)? = null) {
+ val stubValue: T = defaultFactory!!.invoke()
+
+ inline val current: T
+ @Composable get() = stubValue
+ }
+
+ abstract class ProvidableCompositionLocal internal constructor(
+ defaultFactory: (() -> T)?
+ ) : CompositionLocal(defaultFactory)
+
+ internal class DynamicProvidableCompositionLocal constructor(
+ defaultFactory: (() -> T)?
+ ) : ProvidableCompositionLocal(defaultFactory)
+
+ internal class StaticProvidableCompositionLocal(
+ defaultFactory: (() -> T)?
+ ) : ProvidableCompositionLocal(defaultFactory)
+
+ fun compositionLocalOf(
+ defaultFactory: (() -> T)? = null
+ ): ProvidableCompositionLocal = DynamicProvidableCompositionLocal(defaultFactory)
+
+ fun staticCompositionLocalOf(
+ defaultFactory: (() -> T)? = null
+ ): ProvidableCompositionLocal = StaticProvidableCompositionLocal(defaultFactory)
+ """,
+ """
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAA/2NgYGBmYGBgBGJOBijg0uOSSMxLKcrPTKnQS87PLcgvTtUr
+ Ks0rycxNFRJyBgtklmTm5/nkJyfmeJdw6XPJYKgvzdQryEksScsvyhXid4TI
+ gtUXAzWIcnED1emlViTmFuSkCrGFpBaXeJcoMWgxAACzjsPdkAAAAA==
+ """,
+ """
+ androidx/compose/runtime/CompositionLocal.class:
+ H4sIAAAAAAAA/5VUXW/bVBh+juPEiZu2brKOfmylZdnIBzRZ2UZZQseWUQhK
+ O0ijSKgXyHXc7jSJPfnY0biZKm74DdzyC5gEFLhA1bjjR017j5N2XVsUJkvn
+ nPfxe573eT/sf1/+9TeAW/iKIWc6bc/l7adFy+09cYVd9ALH5z27WA1t7nPX
+ qbuW2dXAGLKV5t36vtk3i13T2Ss+2tm3Lb+8dh5iMM5iGlSGWIU73F9juJat
+ d1y/y53ifr9X3A0cS0YSxfXhqVTOtUjeKK9Kodksr4W+kWyulUQMCR1R6AwL
+ p25yx7c9x+wWa47vcUdwS2hIMiStx7bV2XT9zaDbZZjOns9Ekk5gUsc4jDdJ
+ L5CjIUU5cqfvdmyGS9nceb4kLmF6DGlcZkgIP9hpmd2AnFMXuc5gNgEFcwyq
+ /5gLhkL9fzeMejDRtnfNoOuvm5bvet8zLI4qOkNjZGNq9Ysq+3AQqkq+vhfI
+ eBum17G9sDffjCR9W07Z6SWdavMedXHP9rdeVzKazdFQMOgEVwPPsx2f4fqo
+ wpk7XZsqnsG0ZM0yTGZ4ZjdzmoPVZFRNvv+AIZ2xXuv6rhcKY1h+u0RobEOt
+ U8fXNmzfbJu+SZjS60foO2VyScgFJKFD+FMurRKd2jcZnh0dzOjKjKIfHeiK
+ QYvcyVTimtzjd2aODvJq/OjAYCtKSXkwG1dTRlwxInN6Sk0pq3SdldQXP8cU
+ I9pIGbE5Ca3+86NCUGxOjWtGvJE2EiFMkE5BxgjWjfiLHxhLShUrJKzJpL7U
+ cR6nR0qzjit4+7+78LXn9nlbduGCQU6fxZY7xJbY4nuO6QceNV2tum3aJuvc
+ sTeD3o7tNSWXVCT9W6bHpT0Ex7d80+psmE+G9nxjoKLm9LngBN13HNc3wyGl
+ QdpyA8+y17l0nR26ts45qks0GNGwTSn55dL+gCwFJUIVOTm0Vgl5hAidgHT+
+ EGP5wrd/YOpPvMPwG+afhxce0joB2WSVnijRqficrMuDa7iCq3Ic6LSAd0/C
+ xOn/FMMi2dXw9x6hW8DkFfXZT4iyer7ADnFtEGCd1ghYPIykh6wqRUxgSn4A
+ Q5lFOW+0R/O/Yv6XE2GxARgKSg7PA0EDGdeJ5AaRREKSMnlIei1Syf+O3Js0
+ pPkkL1m6PAohoXaG8Iuh//tAmOPSMMdVeiurFMsXDvHh87D0km9xgJ7UKTas
+ kzwtU17y1oA7gi/D/T5qtDfI5ybpWNlGpIaParhVw23coSM+rlG0T7bBBO6i
+ vI1xgasCFYFPBRYE1gQ0gXsCNwSmBWYEMgKzAp+9AtxYnCVtBwAA
+ """,
+ """
+ androidx/compose/runtime/CompositionLocalKt.class:
+ H4sIAAAAAAAA/51UW08TQRT+ZntfCpSi0gsoQlUuyhYQVKgkBkNsKJdIgzE8
+ TbcLmV52ye62gRfD3/Bf+KbRxPTZH2U8sy1RiwXTlzNn5nzznW/PObM/fn79
+ DuApnjPMc7NsW6J8pulW/dRyDM1umK6oG9qmtxeusMyCpfPathsCY4hVeJNr
+ NW6eaHuliqHTqY8hrneh944Z3s0UqpZbE6ZWada144apy7CjbXW87PpsoWf6
+ fdtqijIv1YxuIesMZ7niWqFbyPrGTfly88Xi+kZ/WXPeVYbpgmWfaBXDLdlc
+ EDk3Tcvl7US7lrvbqEmBmetQBJEZCLbWU8jrc5PXhd5bTwgqQzAnTOFukKqb
+ S30YRRSDKgYwxLDcRwVCiDEMlY1j3qi5W1x3LfucYfKmxAypq8OR6dAwVG5U
+ nr/a6f7mJooAgioU3GFIOLIdejdGju2LntwH3p3rKpRUkZL1nexFf/nhUSTa
+ WiYYRi4rsGO4vMxdTjVT6k0fvVEmTUQaMLCqdBQKngnpZckrLzKUWxcxtXWh
+ KglFVcKKt7YuUpkYmXDcH1feKFk25Q8TTFmKhZWYL6W2jxMs6ydc4D9gMtcS
+ w0qfL5YV6Sdx+Z1/DsdoN3ihSlPh37TKBsNwQZjGbqNeMuyiJJYcEnPIbSH3
+ ncPIgTgxuduwyU+/bcvJm03hCAq/+v306F12R/e5zeuGa9h/wQap03p1h592
+ EqgHVsPWjS0hN8kOx+EVfixSQ/2yWWSTctpo1Wi3Ch/1D4h+w8D7uc8YbmHk
+ k+wlsmSDXixJtwnRxiGOUVqXPEwIyx1U2PttAyEqKCJALIJbuE1+O4kCORaD
+ af+Hjwiw7bkvGGtnWSFLCsJeuiEPNUaECSIco8SJfwlNSaHpfwid6E/o+LVC
+ 7/YUmibCcSJMU3jVAy3gGa0vie0e1XjyCL487ucxlcc0Mnk8wMM8HmHmCMzB
+ LOaOEHQQcDDv4LGDuIMnDhK/AIiJIGwEBwAA
+ """,
+ """
+ androidx/compose/runtime/DynamicProvidableCompositionLocal.class:
+ H4sIAAAAAAAA/51S308TQRD+9lpaOKG0RRDwByhoBBKvoCaG1iaKITSp2EjT
+ F562dwtuudszd3sNvPVv8T/wycQH0/joH2WcbUtEE9KEl5lvZr/5dmZ2f/3+
+ /gPACzxh2OXKi0LpnTtuGHwOY+FEidIyEM67C8UD6TaisCs93vbF3oAgtQxV
+ PXS5nwVjaFSau/UO73LH5+rU+dDuCFeXq/VrZa/XqzSb5WqZ4fkNarNIM2Qq
+ UkldZVh7Wj8LtS+V0+kGzkmiXEOMnf0RKpU3Wgwb41iVrUFHhrteD6NTpyN0
+ O+KSOFypUPMh/zDxfdNTeRoZZG1MwGZI608yZqhcv4ix+6VV5DxxwhNf73NX
+ h9EFw+q4wRgKl5T3QnOPa045K+im6MWZMVPGgIGdUf5cmqhEyNtmOOj3ira1
+ aNn93r9ust9b7Pc20+TzbGeymC5aB6xkvZ0v5vKpZdvEr4jCSumfXzJWfsLo
+ 7dAVTYaXN/kK1HLxcoyrs839T3x2pmnXe6EnGGbrUonDJGiLqGlEjYbhtHgk
+ TTxKTh3JU8V1EhFe/zhspaa6MpZ03OARD4QW0Zu/D8xgH4VJ5Ip9aeqXRjWt
+ YcUVIrZh0euP1ms+A1JYoahKeYt8ZnPrG259JWRhlaw9yBaoZhYPCS0MWZjG
+ zEAlgxydMDwaVExijXzWSE8RSI3SKawP/AM8Jv+aTvMkWDhGqoZiDXM13MY8
+ QSzUcAeLx2AxlrB8jEyMmRh3Y9yLkYtxP0b2D5OoO78aBAAA
+ """,
+ """
+ androidx/compose/runtime/ProvidableCompositionLocal.class:
+ H4sIAAAAAAAA/41SXU9TQRA9e1vacsFSikLBLxBEgcRbURNjK0YxjTUFURpe
+ eNr2Lrjt7V6zd2+Db/0t/gOfTHwwjY/+KONsWyKSEHzZmT1z5szszP76/f0H
+ gMe4x/CIK1+H0j/xmmHnUxgJT8fKyI7w9nTYlT5vBGJ7EJFGhqoWNnmQBmOo
+ lOvPai3e5V7A1bH3rtESTVPaql2od16lXK+XtkoMa/+dkUaSIVWWSpothuX7
+ tXZoAqm8VrfjHcWqaYmRVxl5xdLaAalfxipvDPqw3JVaqI+9ljANzSVxuFKh
+ 4UP+bhwEdhbU8PtLC5+NS2WEVjzwXosjHgdmm6hGx00T6h2u20JT6Umk4LoY
+ wwRD0nyUEcOTiwd58WKouaw/LFPhtsJnhsXLmmWYPqXsCMN9bjhhTqeboD/C
+ 7DFuDzCwNuEn0t6K5PkPGd72e3nXKThuv/evyawW+r31ZKbfy7HNTD6Zd96w
+ ovNqjoB8NpdYcC30tN8rsGLy55eUkxuziptUpM6w8f+/iFrNn7Z/9k0z54kP
+ 2oaGux36gmGqJpXYjTsNoet2jlbDcg64lvY+Asf35bHiJtbkr3wYNlBVXRlJ
+ Cu9xzTuCdvvy7y9hcPfDWDdFRdr8+VHOwTDjDDG5BIfWPRorbT+NBBbp9oKs
+ Qza9vsG+YfIruQ6W6HQH8BWiTuAOebNDGiHZgUwaU8iR1PIgI4MVi1ntcXIS
+ IziBuwN7G6tkn1N0mrrIHyJRxUwVV6u4hllyMVdFAfOHYBEWcP0QqQjZCDci
+ 3IwwFeFWhPQfROtXvEUEAAA=
+ """,
+ """
+ androidx/compose/runtime/StaticProvidableCompositionLocal.class:
+ H4sIAAAAAAAA/51SXW8SQRQ9s1A+1pZSkNrWj1aLxraJS6smKkiiTZqSYG2E
+ 8MLTsDvFgWXX7M6S+sZv8R/4ZOKDIT76o4x3gMZqQpr05d5z75x75t478+v3
+ 9x8AnuERw0vuOYEvnXPL9gef/FBYQeQpORBWQ3El7dPAH0qHd1xxODmXSvpe
+ 3be5mwRjOK00X9V7fMgtl3td632nJ2xVrtbnqs7XqzSb5WqZ4ek1apOIMyQq
+ 0pOqyrD9uN73lSs9qzccWGeRZ2tiaB3NUKm802LYuYpV2Zt0pLnFuh90rZ5Q
+ nYBL4nDP8/V6NP8kcl3dU3kRCSRNLMBkiKuPMmQoz1/EVeulTWQcccYjVx1x
+ W/nBZ4atq+ZiWLmgvBOKO1xxyhmDYYzem2mT1gYMrE/5c6mjEiFnn+F4PMqZ
+ xpphjkf/utR4tDYe7cbJZ9lBKhfPGcesZLwt5DLZ2Iap4xdEYaX4zy8JI7ug
+ 9Q7oiibD8+v8BGo5dzHG5dny/xOf9BWt+tB3BMNyXXriJBp0RNDUolpDc1o8
+ kDqeJdMN2fW4igLCxQ/TVmreUIaSjk95wAdCieDN3/dlMBt+FNjiSOr69VlN
+ a1pxiYh9GPT4s/Xqv4AYNimqUt4gn9jd+4YbXwkZ2CJrTrIFqsnjPqHVKQuL
+ WJqoJJDBMik9mFSksE0+qaXTBGKzdAzFib+Hh+Rf02mWBFfaiNWQqyFfw00U
+ CGK1hltYa4OFWMdGG4kQSyFuh7gTIhPibojkH2XEsYYYBAAA
+ """
+ )
}
/**
diff --git a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/CompositionLocalNamingDetectorTest.kt b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/CompositionLocalNamingDetectorTest.kt
index 233445e..c4fdde3 100644
--- a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/CompositionLocalNamingDetectorTest.kt
+++ b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/CompositionLocalNamingDetectorTest.kt
@@ -18,7 +18,7 @@
package androidx.compose.runtime.lint
-import androidx.compose.lint.test.bytecodeStub
+import androidx.compose.lint.test.Stubs
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
@@ -35,132 +35,6 @@
override fun getIssues(): MutableList =
mutableListOf(CompositionLocalNamingDetector.CompositionLocalNaming)
- // Simplified CompositionLocal.kt stubs
- private val compositionLocalStub =
- bytecodeStub(
- filename = "CompositionLocal.kt",
- filepath = "androidx/compose/runtime",
- checksum = 0xeda1836e,
- """
- package androidx.compose.runtime
-
- sealed class CompositionLocal constructor(defaultFactory: (() -> T)? = null)
-
- abstract class ProvidableCompositionLocal internal constructor(
- defaultFactory: (() -> T)?
- ) : CompositionLocal(defaultFactory)
-
- internal class DynamicProvidableCompositionLocal constructor(
- defaultFactory: (() -> T)?
- ) : ProvidableCompositionLocal(defaultFactory)
-
- internal class StaticProvidableCompositionLocal(
- defaultFactory: (() -> T)?
- ) : ProvidableCompositionLocal(defaultFactory)
-
- fun compositionLocalOf(
- defaultFactory: (() -> T)? = null
- ): ProvidableCompositionLocal = DynamicProvidableCompositionLocal(defaultFactory)
-
- fun staticCompositionLocalOf(
- defaultFactory: (() -> T)? = null
- ): ProvidableCompositionLocal = StaticProvidableCompositionLocal(defaultFactory)
- """,
- """
- META-INF/main.kotlin_module:
- H4sIAAAAAAAA/2NgYGBmYGBgBGJOBijg0uOSSMxLKcrPTKnQS87PLcgvTtUr
- Ks0rycxNFRJyBgtklmTm5/nkJyfmeJdwqXHJ4FKvl5afL8QWklpc4l2ixKDF
- AAAiXiK7cAAAAA==
- """,
- """
- androidx/compose/runtime/CompositionLocal.class:
- H4sIAAAAAAAA/5VTS08TURT+7nT6YOQxFMWCqCCofShTiRoUQlQMSZMiCk03
- LMxlZsBL2xkyc9vgxjT+C7f+A1YkLkzD0h9lPHdalKCksjmv+51zvjPnzI+f
- 374DeAyLIcc9J/CFc2jZfuPAD10raHpSNFxrNfKFFL5X9m1eT4IxZJcrz8v7
- vMWtOvf2rI2dfdeWSyt/hxjM87EkdIbEsvCEXGGYzZZrvqwLz9pvNazdpmer
- TqG11rOKS7kq0euHWi5UKksrETaWzVUHkcCAgTgMBl1+ECFDofzfIxLrYcfd
- 5c26XOO29IOPDNP9aDJs9h2ldBYgPOkGHq9br7utVgkrg6bqt86DmhtE07zr
- W/SyNdW3GTWgIa2spLKuMozN2X+w7xsRmGH+csUZRk8T1l3JHS45xbRGK0Z3
- xpQYUAIMrEbxQ6G8IlnOI4aNTnvc0DKa0WkbmklC6Z6b0VJPM512Xk912iZb
- 0Iraq4mUnjZTmhmbNNJ6WlvstDOsqJ98TWhm/OQzYwlVdoE6VZhqmD4ldnZj
- Ty6+ibeB3xIO36m7/7iOsfOx+ZqkQ1v1HZdhpCw8902zseMGFZWveitMlQdC
- +b3gwJbY87hsBmQPbUlu19b5Qe/N2PKbge2uCeVMbHYpVUUo6PWl5/mSR0eg
- z9Du4uqDIkYWLZNklrxnNLBGOp4/xpUjMjTkSCYoDOjIkxzvAjCIoahAHMMY
- ofdChE6Z9IvCJF+VK1J5nfTIlP7pC+KsnC+wY4x1Cz+IurPU2Q5R9mgve5FA
- as+JfOEY146i9SsG093obwaJHgNljeN6lNVlE8PDSN/HPOkXhMkQ34ltxEqY
- LOFGCVO4SSZulXAb09tgIWZwZxvJEEMhZkPMhRgOcTdUkXu/AG89zFz4BAAA
- """,
- """
- androidx/compose/runtime/CompositionLocalKt.class:
- H4sIAAAAAAAA/51UW08TQRT+ZntfCpSiUIoXhKpclC0gqLSSGAyxoVwiDcbw
- NN0uZHrZJbvbBl4Mf8N/4ZtGE9Nnf5TxzLZELZSavpw5M+eb73x7zpn9+evb
- DwDP8IJhgZsl2xKlM023aqeWY2h23XRFzdA2vb1whWXmLZ1Xt90QGEOszBtc
- q3LzRNsrlg2dTn0Mcb0DvXfM8H42X7HcqjC1cqOmHddNXYYdbavtpTNz+a7p
- 922rIUq8WDU6hWQYzrKF9XynkMxGr3zZhUIhs9Ff1qx3lWEmb9knWtlwizYX
- RM5N03J5K9Gu5e7Wq1Jg6iYUQWQGgq13FfLm3OQ1oXfXE4LKEMwKU7gbpKp3
- qQ+jiGJQxQCGGFb6qEAIMYahknHM61V3i+uuZZ8zTPVKzJC8OhypNg1Duafy
- 3NVO9zc3UQQQVKFgjCHhyHbonRg5ti+7ch94d26q0ISKpKzvVDf6yw+PItHS
- cpdh5LICO4bLS9zlVDOl1vDRG2XSRKQBA6tIR6HgmZBemrzSEkOpeRFTmxeq
- klBUJax4a/MimYqRCcf9ceWtkmbT/jDBlOVYWIn5kmrrOMHSfsIF/gMmcy0z
- rPb5YlmBfhKX3/n3cIx2ghcrNBX+TatkMAznhWns1mtFwy5IYskhMYfcFnLf
- PowciBOTu3Wb/Ml3LTk5syEcQeHXf54evcvO6D63ec1wDfsf2CB1Wq/s8NN2
- AvXAqtu6sSXkZqLNcXiFH0vUUL9sFtkJOW20arRbg4/6B0S/Y+DD/BcMNzHy
- WfYSabJBL3aLbhOihUMco7Que5gQVtqosPfbBkJUUESAWISu3Sa/lUSBHIvB
- Sf/HTwiw7fmvGG9lWSVLCsJeuiEPFSfCUSKMk9DEdUKTUujkNUIT/Qm9c6PQ
- e12FjhHhOBGOUXjNAy3iOa2viO0+1XjqCL4cHuQwncMMUjk8xKMcHmP2CMzB
- HOaPEHQQcLDg4ImDuIOnDhK/AezqFjcEBwAA
- """,
- """
- androidx/compose/runtime/DynamicProvidableCompositionLocal.class:
- H4sIAAAAAAAA/51SXU8TQRQ9sy0tXaGUIljwAxQ0AolbUBNDaxPFEJpUJNLw
- wtN0d6jT7s6a3dkG3vpb/Ac+mfhgGh/9UcY7bYloQkh4mXvumXPP3Lkzv35/
- /wHgBZ4w7HDlRaH0zhw3DD6HsXCiRGkZCOfdueKBdA+jsCc93vLF7lAgtQxV
- I3S5nwVjOKw2dxod3uOOz1Xb+dDqCFdXao0rba/2qzablVqF4fkNarNIM2Sq
- UkldY1h92uiG2pfK6fQC5zRRrhHGzt4YlSvrxwzr16mqm8OOjHatEUZtpyN0
- K+KSNFypUPOR/iDxfdNTZQoZZG1MwGZI608yZqhePYhr50ujyHvilCe+3uOu
- DqNzhpXrLsYweyF5LzT3uObEWUEvRS/OzJIzCxhYl/gzabIyIW+LYX/QL9pW
- ybIH/X/D5KBfGvQ30hQLbHuymC5a+6xsvZ0v5gupJdvkr0jCyumfXzJWYcL4
- bdMRTYaXN/kK1HLx4hqX7zb3v/BZV9Osd0NPMMw0pBIHSdASUdOYGg+jOeaR
- NPmYzB3JtuI6iQivfRy1Ulc9GUvaPuQRD4QW0Zu/D8xgH4VJ5Io9aeoXxzXH
- o4pLQmzBotcfj9d8BqSwTFmNeItiZmPzG259JWRhhVZ7yE6ZH4OHhBZGKmKm
- hy4Z5DFDTo+GFZNYpZg11jkCqTGdwtowPsBjiq9pt0CGsydI1VGsY66O25gn
- iIU67qB0AhZjEUsnyMSYjnE3xr0Y+Rj3Y2T/AJbWL04aBAAA
- """,
- """
- androidx/compose/runtime/ProvidableCompositionLocal.class:
- H4sIAAAAAAAA/41SXU9TQRA9e1vacsVSikLBLxBEgcRbURNjK0YxjTUFURpe
- eNr2Lrjt7V6zd2+Db/0t/gOfTHwwjY/+KONsWyKSEHjZmT1z5szszP7+8+Mn
- gCe4z/CYK1+H0j/2mmHncxgJT8fKyI7wdnXYlT5vBGJrEJFGhqoWNnmQBmOo
- lOvPay3e5V7A1ZH3vtESTVParJ2rd1alXK+XNksMq5fOSCPJkCpLJc0mw9KD
- Wjs0gVReq9vxDmPVtMTIq4y8Yml1n9QvYpXXB31Y7nIt1EdeS5iG5pI4XKnQ
- 8CF/Jw4COwtq+MOFhU/HpTJCKx54b8QhjwOzRVSj46YJ9TbXbaGp9ARScF2M
- 4QpD0nySEcPT8wd5/mKouaw/LFPhtsIXhoWLmmWYOqFsC8N9bjhhTqeboD/C
- 7DFuDzCwNuHH0t6K5PmPGN71e3nXKThuv/e/yawU+r21ZKbfy7GNTD6Zd96y
- ovN6loB8NpeYdy30rN8rsGLy19eUkxuzihtUpM6wfvlfRK3mT9o//abps8SH
- bUPD3Qp9wTBZk0rsxJ2G0HU7R6thOftcS3sfgeN78khxE2vylz8OG6iqrowk
- hXe55h1Bu33175cwuHthrJuiIm3+3Chnf5hxiphchEPrHo2Vtp9GAgt0e0nW
- IZteW2ffMfGNXAeLdLoDOEPUFO6SNzOk4SqyA5k0JpEjqaVBRgbLFrPa4+Qk
- RnAC9wb2DlbIvqDoFHWRP0CiiukqrlVxHTPkYraKAuYOwCLM48YBUhGyEW5G
- uBVhMsLtCOm/jQDw8EUEAAA=
- """,
- """
- androidx/compose/runtime/StaticProvidableCompositionLocal.class:
- H4sIAAAAAAAA/51SXW8SQRQ9s1A+1pZSaiutH60WjW0Tl1ZNVJBEmzQlwUqE
- 8MLTsDvFgWXX7M6S+sZv8R/4ZOKDIT76o4x3gMZqQpr0Ze65Z849c+fO/Pr9
- /QeAZ3jE8JJ7TuBL59yy/cEnPxRWEHlKDoTVUFxJux74Q+nwjiuOJvtSSd+r
- +TZ3k2AM9XLzVa3Hh9xyude13nd6wlalSm2u63y/crNZqpQYnl6jNok4Q6Is
- PakqDDuPa31fudKzesOBdRZ5thaG1vEMFUu7LYbdq1Tl/UlHWluo+UHX6gnV
- CbgkDfc8X49H608j19U9lRaRQNLEAkyGuPooQ4bS/EFcNV6aRMYRZzxy1TG3
- lR98Zti+6l4MKxeSd0JxhytOnDEYxui9mV7SegED6xN/LnVWJOQcMJyMRznT
- yBvmePRvSI1H+fFoL04xyw5TuXjOOGFF4+1aLpONbZo6f0ESVoz//JIwsgva
- 75COaDI8v85PoJZzF9e4fLfV/4VP+opGfeQ7gmG5Jj1xGg06ImhqU+2hNS0e
- SJ3PyHRDdj2uooBw4cO0lao3lKGk7ToP+EAoEbz5+74MZsOPAlscS12/Matp
- TSsuCXEAgx5/Nl79FxDDFmUV4g2Kib39b7jxlZCBbVrNCZulmgzuE1qfqrCI
- pYlLgvhlcnowqUhhh2JSW6cJxGZ0DIVJvIeHFF/TrjZcaSNWRa6K1SpuYo0g
- 1qu4hXwbLMQGNttIhFgKcTvEnRCZEHdDJP8AhWEFiBgEAAA=
- """
- )
-
@Test
fun noLocalPrefix() {
lint()
@@ -187,7 +61,7 @@
}
"""
),
- compositionLocalStub
+ Stubs.CompositionLocal
)
.run()
.expect(
@@ -229,7 +103,7 @@
}
"""
),
- compositionLocalStub
+ Stubs.CompositionLocal
)
.run()
.expectClean()
diff --git a/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetectorTest.kt b/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetectorTest.kt
index f4c3192..3b1f2d1 100644
--- a/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetectorTest.kt
+++ b/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetectorTest.kt
@@ -16,6 +16,7 @@
package androidx.compose.ui.lint
+import androidx.compose.lint.test.Stubs
import androidx.compose.ui.lint.SuspiciousCompositionLocalModifierReadDetector.Companion.SuspiciousCompositionLocalModifierRead
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector
@@ -64,29 +65,6 @@
"""
)
- private val CompositionLocalStub =
- kotlin(
- """
- package androidx.compose.runtime
-
- import java.lang.RuntimeException
-
- class CompositionLocal(defaultFactory: () -> T)
-
- class ProvidedValue internal constructor(
- val compositionLocal: CompositionLocal,
- val value: T,
- val canOverride: Boolean
- )
-
- fun compositionLocalOf(defaultFactory: () -> T): CompositionLocal =
- throw RuntimeException("Not implemented in lint stubs.")
-
- fun staticCompositionLocalOf(defaultFactory: () -> T): CompositionLocal =
- throw RuntimeException("Not implemented in lint stubs.")
- """
- )
-
@Test
fun testCompositionLocalReadInModifierAttachAndDetach() {
lint()
@@ -116,7 +94,7 @@
}
"""
),
- CompositionLocalStub,
+ Stubs.CompositionLocal,
CompositionLocalConsumerModifierStub,
ModifierNodeStub
)
@@ -167,7 +145,7 @@
}
"""
),
- CompositionLocalStub,
+ Stubs.CompositionLocal,
CompositionLocalConsumerModifierStub,
ModifierNodeStub
)
@@ -201,7 +179,7 @@
}
"""
),
- CompositionLocalStub,
+ Stubs.CompositionLocal,
CompositionLocalConsumerModifierStub,
ModifierNodeStub
)
@@ -243,7 +221,7 @@
}
"""
),
- CompositionLocalStub,
+ Stubs.CompositionLocal,
CompositionLocalConsumerModifierStub,
ModifierNodeStub
)
@@ -275,7 +253,7 @@
}
"""
),
- CompositionLocalStub,
+ Stubs.CompositionLocal,
CompositionLocalConsumerModifierStub,
ModifierNodeStub
)
@@ -319,7 +297,7 @@
}
"""
),
- CompositionLocalStub,
+ Stubs.CompositionLocal,
CompositionLocalConsumerModifierStub,
ModifierNodeStub
)
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/demos/src/main/java/androidx/constraintlayout/compose/demos/AllDemos.kt b/constraintlayout/constraintlayout-compose/integration-tests/demos/src/main/java/androidx/constraintlayout/compose/demos/AllDemos.kt
index d3330d3..74ee699 100644
--- a/constraintlayout/constraintlayout-compose/integration-tests/demos/src/main/java/androidx/constraintlayout/compose/demos/AllDemos.kt
+++ b/constraintlayout/constraintlayout-compose/integration-tests/demos/src/main/java/androidx/constraintlayout/compose/demos/AllDemos.kt
@@ -16,8 +16,8 @@
package androidx.constraintlayout.compose.demos
-import android.app.Activity
import androidx.activity.compose.BackHandler
+import androidx.activity.compose.LocalActivity
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
@@ -46,7 +46,6 @@
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -159,7 +158,7 @@
}
}
- val activity = LocalContext.current as? Activity
+ val activity = LocalActivity.current
// If there's a demo being displayed, return to demo list, otherwise, exit app
BackHandler {
if (displayedDemoIndex >= 0) {
diff --git a/libraryversions.toml b/libraryversions.toml
index 99b1bb5c..00fd408 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -7,7 +7,7 @@
ARCH_CORE = "2.3.0-alpha01"
ASYNCLAYOUTINFLATER = "1.1.0-alpha02"
AUTOFILL = "1.3.0-beta01"
-BENCHMARK = "1.4.0-alpha03"
+BENCHMARK = "1.4.0-alpha04"
BIOMETRIC = "1.4.0-alpha02"
BLUETOOTH = "1.0.0-alpha02"
BROWSER = "1.9.0-alpha01"
@@ -19,12 +19,12 @@
CAMERA_VIEWFINDER = "1.4.0-alpha09"
CARDVIEW = "1.1.0-alpha01"
CAR_APP = "1.7.0-beta02"
-COLLECTION = "1.5.0-alpha04"
-COMPOSE = "1.8.0-alpha04"
+COLLECTION = "1.5.0-alpha05"
+COMPOSE = "1.8.0-alpha05"
COMPOSE_MATERIAL3 = "1.4.0-alpha02"
COMPOSE_MATERIAL3_ADAPTIVE = "1.1.0-alpha05"
COMPOSE_MATERIAL3_COMMON = "1.0.0-alpha01"
-COMPOSE_RUNTIME = "1.8.0-alpha04"
+COMPOSE_RUNTIME = "1.8.0-alpha05"
CONSTRAINTLAYOUT = "2.2.0-beta01"
CONSTRAINTLAYOUT_COMPOSE = "1.1.0-beta01"
CONSTRAINTLAYOUT_CORE = "1.1.0-beta01"
@@ -91,7 +91,7 @@
LEANBACK_TAB = "1.1.0-beta01"
LEGACY = "1.1.0-alpha01"
LIBYUV = "0.1.0-dev01"
-LIFECYCLE = "2.9.0-alpha05"
+LIFECYCLE = "2.9.0-alpha06"
LIFECYCLE_EXTENSIONS = "2.2.0"
LINT = "1.0.0-alpha02"
LOADER = "1.2.0-alpha01"
@@ -117,9 +117,9 @@
RECYCLERVIEW_SELECTION = "1.2.0-alpha02"
REMOTECALLBACK = "1.0.0-alpha02"
RESOURCEINSPECTION = "1.1.0-alpha01"
-ROOM = "2.7.0-alpha10"
+ROOM = "2.7.0-alpha11"
SAFEPARCEL = "1.0.0-alpha01"
-SAVEDSTATE = "1.3.0-alpha03"
+SAVEDSTATE = "1.3.0-alpha04"
SECURITY = "1.1.0-alpha07"
SECURITY_APP_AUTHENTICATOR = "1.0.0-rc01"
SECURITY_APP_AUTHENTICATOR_TESTING = "1.0.0-rc01"
@@ -133,7 +133,7 @@
SLICE_BUILDERS_KTX = "1.0.0-alpha09"
SLICE_REMOTECALLBACK = "1.0.0-alpha01"
SLIDINGPANELAYOUT = "1.3.0-alpha01"
-SQLITE = "2.5.0-alpha10"
+SQLITE = "2.5.0-alpha11"
SQLITE_INSPECTOR = "2.1.0-alpha01"
STABLE_AIDL = "1.0.0-alpha01"
STARTUP = "1.2.0-rc01"
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt b/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt
index 28f9f0c..bf4537a 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt
@@ -16,8 +16,10 @@
package androidx.room.ext
+import androidx.room.compiler.processing.XConstructorElement
import androidx.room.compiler.processing.XElement
import androidx.room.compiler.processing.XExecutableParameterElement
+import androidx.room.compiler.processing.XFieldElement
import androidx.room.compiler.processing.XTypeElement
import kotlin.contracts.contract
@@ -26,7 +28,7 @@
return this.hasAnnotation(androidx.room.Entity::class)
}
-fun XTypeElement.getValueClassUnderlyingElement(): XExecutableParameterElement {
+fun XTypeElement.getValueClassUnderlyingInfo(): ValueClassInfo {
check(this.isValueClass()) {
"Can't get value class property, type element '$this' is not a value class"
}
@@ -34,12 +36,21 @@
// * Primary constructor is required for value class
// * Value class must have exactly one primary constructor parameter
// * Value class primary constructor must only have final read-only (val) property parameter
- return checkNotNull(this.findPrimaryConstructor()) {
+ val constructor =
+ checkNotNull(this.findPrimaryConstructor()) {
"Couldn't find primary constructor for value class."
}
- .parameters
- .single()
+ val param = constructor.parameters.first()
+ val field = getDeclaredFields().first { it.name == param.name }
+ return ValueClassInfo(constructor, param, field)
}
+/** Store information about the underlying value property of a Kotlin value class */
+class ValueClassInfo(
+ val constructor: XConstructorElement,
+ val parameter: XExecutableParameterElement,
+ val field: XFieldElement,
+)
+
/** Suffix of the Kotlin synthetic class created interface method implementations. */
const val DEFAULT_IMPLS_CLASS_NAME = "DefaultImpls"
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
index 798bfeb..86c5e95 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
@@ -28,7 +28,7 @@
import androidx.room.ext.CollectionTypeNames.LONG_SPARSE_ARRAY
import androidx.room.ext.CommonTypeNames
import androidx.room.ext.GuavaTypeNames
-import androidx.room.ext.getValueClassUnderlyingElement
+import androidx.room.ext.getValueClassUnderlyingInfo
import androidx.room.ext.isByteBuffer
import androidx.room.ext.isEntityElement
import androidx.room.ext.isNotByte
@@ -377,12 +377,15 @@
val typeElement = type.typeElement
if (typeElement?.isValueClass() == true) {
// Extract the type value of the Value class element
- val underlyingProperty = typeElement.getValueClassUnderlyingElement()
+ val underlyingInfo = typeElement.getValueClassUnderlyingInfo()
+ if (underlyingInfo.constructor.isPrivate() || underlyingInfo.field.getter == null) {
+ return null
+ }
val underlyingTypeColumnAdapter =
findColumnTypeAdapter(
// Find an adapter for the non-null underlying type, nullability will be handled
// by the value class adapter.
- out = underlyingProperty.asMemberOf(type).makeNonNullable(),
+ out = underlyingInfo.parameter.asMemberOf(type).makeNonNullable(),
affinity = affinity,
skipDefaultConverter = false
) ?: return null
@@ -391,7 +394,7 @@
valueTypeColumnAdapter = underlyingTypeColumnAdapter,
affinity = underlyingTypeColumnAdapter.typeAffinity,
out = type,
- valuePropertyName = underlyingProperty.name
+ valuePropertyName = underlyingInfo.parameter.name
)
}
return when {
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
index 1e314bf..db835d4 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
@@ -24,7 +24,7 @@
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.XTestInvocation
import androidx.room.compiler.processing.util.compileFiles
-import androidx.room.runKspTestWithK1
+import androidx.room.compiler.processing.util.runKspTest
import androidx.room.runProcessorTestWithK1
import org.junit.Test
import org.junit.runner.RunWith
@@ -225,25 +225,44 @@
"""
package foo
class Subject {
- fun makeULong(): ULong {
- TODO()
- }
+ fun uLongFunction(): ULong = TODO()
+ fun durationFunction(): kotlin.time.Duration = TODO()
}
"""
.trimIndent()
)
- runKspTestWithK1(
+ runKspTest(
sources = listOf(src),
config =
XProcessingEnvConfig.DEFAULT.copy(excludeMethodsWithInvalidJvmSourceNames = false)
) { invocation ->
val subject = invocation.processingEnv.requireTypeElement("foo.Subject")
- val returnType =
- subject.getDeclaredMethods().single { it.name == "makeULong" }.returnType
- val prop = checkNotNull(returnType.typeElement).getValueClassUnderlyingElement()
- assertThat(prop.name).isEqualTo("data")
- assertThat(prop.type)
- .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
+ subject
+ .getDeclaredMethods()
+ .first { it.name == "uLongFunction" }
+ .let { uLongFunction ->
+ val returnType = uLongFunction.returnType
+ val info = checkNotNull(returnType.typeElement).getValueClassUnderlyingInfo()
+ assertThat(info.parameter.name).isEqualTo("data")
+ assertThat(info.field.name).isEqualTo("data")
+ assertThat(info.parameter.type)
+ .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
+ assertThat(info.field.type)
+ .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
+ }
+ subject
+ .getDeclaredMethods()
+ .first { it.name == "durationFunction" }
+ .let { durationFunction ->
+ val returnType = durationFunction.returnType
+ val info = checkNotNull(returnType.typeElement).getValueClassUnderlyingInfo()
+ assertThat(info.parameter.name).isEqualTo("rawValue")
+ assertThat(info.field.name).isEqualTo("rawValue")
+ assertThat(info.parameter.type)
+ .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
+ assertThat(info.field.type)
+ .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
+ }
}
}
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
index 29cbd79..d43a813 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
@@ -30,6 +30,7 @@
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.XTestInvocation
import androidx.room.compiler.processing.util.compileFiles
+import androidx.room.compiler.processing.util.runKspTest
import androidx.room.compiler.processing.util.runProcessorTest
import androidx.room.ext.CommonTypeNames
import androidx.room.ext.GuavaUtilConcurrentTypeNames
@@ -195,7 +196,6 @@
Source.java(
"foo.bar.Fruit",
""" package foo.bar;
- import androidx.room.*;
enum Fruit {
APPLE,
BANANA,
@@ -222,7 +222,6 @@
Source.kotlin(
"Foo.kt",
"""
- import androidx.room.*
@JvmInline
value class IntValueClass(val data: Int)
@JvmInline
@@ -282,7 +281,6 @@
Source.kotlin(
"Foo.kt",
"""
- import androidx.room.*
@JvmInline
value class Foo(val value : Int) {
val double
@@ -292,15 +290,78 @@
.trimIndent()
)
- runProcessorTestWithK1(sources = listOf(source)) { invocation ->
- TypeAdapterStore.create(
- context = invocation.context,
- builtInConverterFlags = BuiltInConverterFlags.DEFAULT
- )
+ runKspTest(sources = listOf(source)) { invocation ->
+ val store =
+ TypeAdapterStore.create(
+ context = invocation.context,
+ builtInConverterFlags = BuiltInConverterFlags.DEFAULT
+ )
val typeElement = invocation.processingEnv.requireTypeElement("Foo")
- assertThat(typeElement.getDeclaredFields()).hasSize(1)
- assertThat(typeElement.getDeclaredFields().single().type.asTypeName())
- .isEqualTo(PRIMITIVE_INT)
+ val result =
+ store.findColumnTypeAdapter(
+ out = typeElement.type,
+ affinity = null,
+ skipDefaultConverter = false
+ )
+ assertThat(result).isInstanceOf()
+ }
+ }
+
+ @Test
+ fun testValueClassWithPrivateVal() {
+ val source =
+ Source.kotlin(
+ "Foo.kt",
+ """
+ @JvmInline
+ value class Foo(private val value : Int)
+ """
+ .trimIndent()
+ )
+
+ runKspTest(sources = listOf(source)) { invocation ->
+ val store =
+ TypeAdapterStore.create(
+ context = invocation.context,
+ builtInConverterFlags = BuiltInConverterFlags.DEFAULT
+ )
+ val typeElement = invocation.processingEnv.requireTypeElement("Foo")
+ val result =
+ store.findColumnTypeAdapter(
+ out = typeElement.type,
+ affinity = null,
+ skipDefaultConverter = false
+ )
+ assertThat(result).isNull()
+ }
+ }
+
+ @Test
+ fun testValueClassWithPrivateConstructor() {
+ val source =
+ Source.kotlin(
+ "Foo.kt",
+ """
+ @JvmInline
+ value class Foo private constructor(val value : Int)
+ """
+ .trimIndent()
+ )
+
+ runKspTest(sources = listOf(source)) { invocation ->
+ val store =
+ TypeAdapterStore.create(
+ context = invocation.context,
+ builtInConverterFlags = BuiltInConverterFlags.DEFAULT
+ )
+ val typeElement = invocation.processingEnv.requireTypeElement("Foo")
+ val result =
+ store.findColumnTypeAdapter(
+ out = typeElement.type,
+ affinity = null,
+ skipDefaultConverter = false
+ )
+ assertThat(result).isNull()
}
}