Merge "Add Scaffold content padding lint check" into androidx-main
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/layout/LayoutBasics.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/layout/LayoutBasics.kt
index 443615f..b390058 100644
--- a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/layout/LayoutBasics.kt
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/layout/LayoutBasics.kt
@@ -22,6 +22,7 @@
package androidx.compose.integration.docs.layout
+import android.annotation.SuppressLint
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
@@ -257,6 +258,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object LayoutBasicsSnippet16 {
@Composable
fun HomeScreen(/*...*/) {
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/layout/Material.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/layout/Material.kt
index 3d240ca..67ddde2 100644
--- a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/layout/Material.kt
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/layout/Material.kt
@@ -22,6 +22,7 @@
package androidx.compose.integration.docs.layout
+import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
@@ -137,6 +138,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet5 {
@Composable
fun MyTopAppBar() {
@@ -150,6 +152,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet6 {
@Composable
fun MyBottomAppBar() {
@@ -163,6 +166,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet7 {
@Composable
fun MyFAB() {
@@ -178,6 +182,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet8 {
@Composable
fun MyFAB() {
@@ -195,6 +200,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet9 {
@Composable
fun MyFAB() {
@@ -215,6 +221,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet10 {
@Composable
fun MyFAB() {
@@ -241,6 +248,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet11 {
@Composable
fun MySnackbar() {
@@ -265,6 +273,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet12 {
@Composable
fun MySnackbar() {
@@ -302,6 +311,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet13 {
@Composable
fun MyDrawer() {
@@ -317,6 +327,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet14 {
@Composable
fun MyDrawer() {
@@ -332,6 +343,7 @@
}
}
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
private object MaterialSnippet15 {
@Composable
fun MyDrawer() {
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/navigation/Navigation.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/navigation/Navigation.kt
index 2d9e0c7..0ac03ae 100644
--- a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/navigation/Navigation.kt
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/navigation/Navigation.kt
@@ -22,6 +22,7 @@
import android.app.PendingIntent
import android.content.Intent
import androidx.annotation.StringRes
+import androidx.compose.foundation.layout.padding
import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.Button
@@ -32,6 +33,7 @@
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.app.TaskStackBuilder
@@ -177,9 +179,12 @@
}
}
}
- ) {
-
- NavHost(navController, startDestination = Screen.Profile.route) {
+ ) { innerPadding ->
+ NavHost(
+ navController,
+ startDestination = Screen.Profile.route,
+ modifier = Modifier.padding(innerPadding)
+ ) {
composable(Screen.Profile.route) { Profile(navController) }
composable(Screen.FriendsList.route) { FriendsList(navController) }
}
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/sideeffects/SideEffects.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/sideeffects/SideEffects.kt
index 7429a97..d2f586f 100644
--- a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/sideeffects/SideEffects.kt
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/sideeffects/SideEffects.kt
@@ -21,9 +21,11 @@
package androidx.compose.integration.docs.sideeffects
+import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
@@ -73,6 +75,7 @@
* No action required if it's modified.
*/
+@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@ExperimentalMaterialApi
private object SideEffectsSnippet1 {
@Composable
@@ -112,8 +115,8 @@
// Creates a CoroutineScope bound to the MoviesScreen's lifecycle
val scope = rememberCoroutineScope()
- Scaffold(scaffoldState = scaffoldState) {
- Column {
+ Scaffold(scaffoldState = scaffoldState) { innerPadding ->
+ Column(Modifier.padding(innerPadding)) {
/* ... */
Button(
>
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/state/State.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/state/State.kt
index a8ed7dec2..b531c3e4 100644
--- a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/state/State.kt
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/state/State.kt
@@ -192,13 +192,14 @@
val scaffoldState = rememberScaffoldState()
val coroutineScope = rememberCoroutineScope()
- Scaffold(scaffoldState = scaffoldState) {
+ Scaffold(scaffoldState = scaffoldState) { innerPadding ->
MyContent(
showSnackbar = { message ->
coroutineScope.launch {
scaffoldState.snackbarHostState.showSnackbar(message)
}
- }
+ },
+ modifier = Modifier.padding(innerPadding)
)
}
}
@@ -261,8 +262,12 @@
)
}
}
- ) {
- NavHost(navController = myAppState.navController, "initial") { /* ... */ }
+ ) { innerPadding ->
+ NavHost(
+ navController = myAppState.navController,
+ startDestination = "initial",
+ modifier = Modifier.padding(innerPadding)
+ ) { /* ... */ }
}
}
}
@@ -286,7 +291,7 @@
private fun MyTheme(content: @Composable () -> Unit) {}
@Composable
-private fun MyContent(showSnackbar: (String) -> Unit) {}
+private fun MyContent(showSnackbar: (String) -> Unit, modifier: Modifier = Modifier) {}
@Composable
private fun BottomBar(tabs: Unit, navigateToRoute: (String) -> Unit) {}
diff --git a/compose/lint/common/src/main/java/androidx/compose/lint/Names.kt b/compose/lint/common/src/main/java/androidx/compose/lint/Names.kt
index 016e112..7423dbe 100644
--- a/compose/lint/common/src/main/java/androidx/compose/lint/Names.kt
+++ b/compose/lint/common/src/main/java/androidx/compose/lint/Names.kt
@@ -28,6 +28,9 @@
object AnimationCore {
val PackageName = Package("androidx.compose.animation.core")
}
+ object Material {
+ val PackageName = Package("androidx.compose.material")
+ }
object Runtime {
val PackageName = Package("androidx.compose.runtime")
diff --git a/compose/material/material-lint/src/main/java/androidx/compose/material/lint/ColorsDetector.kt b/compose/material/material-lint/src/main/java/androidx/compose/material/lint/ColorsDetector.kt
index 2f4c445..11cbd84 100644
--- a/compose/material/material-lint/src/main/java/androidx/compose/material/lint/ColorsDetector.kt
+++ b/compose/material/material-lint/src/main/java/androidx/compose/material/lint/ColorsDetector.kt
@@ -19,7 +19,7 @@
package androidx.compose.material.lint
import androidx.compose.lint.Name
-import androidx.compose.lint.Package
+import androidx.compose.lint.Names
import androidx.compose.lint.isInPackageName
import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.Category
@@ -55,7 +55,7 @@
override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
override fun visitCallExpression(node: UCallExpression) {
val method = node.resolve() ?: return
- if (!method.isInPackageName(MaterialPackageName)) return
+ if (!method.isInPackageName(Names.Material.PackageName)) return
if (node.isConstructorCall()) {
if (method.containingClass?.name != Colors.shortName) return
@@ -229,7 +229,6 @@
"error" to "onError"
)
-private val MaterialPackageName = Package("androidx.compose.material")
-private val LightColors = Name(MaterialPackageName, "lightColors")
-private val DarkColors = Name(MaterialPackageName, "darkColors")
-private val Colors = Name(MaterialPackageName, "Colors")
+private val LightColors = Name(Names.Material.PackageName, "lightColors")
+private val DarkColors = Name(Names.Material.PackageName, "darkColors")
+private val Colors = Name(Names.Material.PackageName, "Colors")
diff --git a/compose/material/material-lint/src/main/java/androidx/compose/material/lint/MaterialIssueRegistry.kt b/compose/material/material-lint/src/main/java/androidx/compose/material/lint/MaterialIssueRegistry.kt
index 4553ca9..75ce926 100644
--- a/compose/material/material-lint/src/main/java/androidx/compose/material/lint/MaterialIssueRegistry.kt
+++ b/compose/material/material-lint/src/main/java/androidx/compose/material/lint/MaterialIssueRegistry.kt
@@ -28,7 +28,8 @@
override val api = 13
override val minApi = CURRENT_API
override val issues get() = listOf(
- ColorsDetector.ConflictingOnColor
+ ColorsDetector.ConflictingOnColor,
+ ScaffoldPaddingDetector.UnusedMaterialScaffoldPaddingParameter
)
override val vendor = Vendor(
vendorName = "Jetpack Compose",
diff --git a/compose/material/material-lint/src/main/java/androidx/compose/material/lint/ScaffoldPaddingDetector.kt b/compose/material/material-lint/src/main/java/androidx/compose/material/lint/ScaffoldPaddingDetector.kt
new file mode 100644
index 0000000..252ab25
--- /dev/null
+++ b/compose/material/material-lint/src/main/java/androidx/compose/material/lint/ScaffoldPaddingDetector.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2022 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.compose.material.lint
+
+import androidx.compose.lint.Name
+import androidx.compose.lint.Names
+import androidx.compose.lint.findUnreferencedParameters
+import androidx.compose.lint.isInPackageName
+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.android.tools.lint.detector.api.computeKotlinArgumentMapping
+import com.intellij.psi.PsiMethod
+import java.util.EnumSet
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.ULambdaExpression
+
+/**
+ * [Detector] that checks `Scaffold` usages for correctness.
+ *
+ * Scaffold provides an padding parameter to the `content` lambda. If this value is unused,
+ * then the content may be obscured by app bars defined by the scaffold.
+ */
+class ScaffoldPaddingDetector : Detector(), SourceCodeScanner {
+ override fun getApplicableMethodNames(): List<String> = listOf(Scaffold.shortName)
+
+ override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+ if (method.isInPackageName(Names.Material.PackageName)) {
+ val contentArgument = computeKotlinArgumentMapping(node, method)
+ .orEmpty()
+ .filter { (_, parameter) ->
+ parameter.name == "content"
+ }
+ .keys
+ .filterIsInstance<ULambdaExpression>()
+ .firstOrNull() ?: return
+
+ contentArgument.findUnreferencedParameters().forEach { unreferencedParameter ->
+ val location = unreferencedParameter.parameter
+ ?.let { context.getLocation(it) }
+ ?: context.getLocation(contentArgument)
+ val name = unreferencedParameter.name
+ context.report(
+ UnusedMaterialScaffoldPaddingParameter,
+ node,
+ location,
+ "Content padding parameter $name is not used"
+ )
+ }
+ }
+ }
+
+ companion object {
+ val UnusedMaterialScaffoldPaddingParameter = Issue.create(
+ "UnusedMaterialScaffoldPaddingParameter",
+ "Scaffold content should use the padding provided as a lambda parameter",
+ "The `content` lambda in Scaffold has a padding parameter " +
+ "which will include any inner padding for the content due to app bars. If this " +
+ "parameter is ignored, then content may be obscured by the app bars resulting in " +
+ "visual issues or elements that can't be interacted with.",
+ Category.CORRECTNESS, 3, Severity.ERROR,
+ Implementation(
+ ScaffoldPaddingDetector::class.java,
+ EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
+ )
+ )
+ }
+}
+
+private val Scaffold = Name(Names.Material.PackageName, "Scaffold")
\ No newline at end of file
diff --git a/compose/material/material-lint/src/test/java/androidx/compose/material/lint/ScaffoldPaddingDetectorTest.kt b/compose/material/material-lint/src/test/java/androidx/compose/material/lint/ScaffoldPaddingDetectorTest.kt
new file mode 100644
index 0000000..88b9576
--- /dev/null
+++ b/compose/material/material-lint/src/test/java/androidx/compose/material/lint/ScaffoldPaddingDetectorTest.kt
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2022 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.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.compose.material.lint
+
+import androidx.compose.lint.test.Stubs
+import androidx.compose.lint.test.compiledStub
+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
+
+/* ktlint-disable max-line-length */
+@RunWith(JUnit4::class)
+
+/**
+ * Test for [ScaffoldPaddingDetector].
+ */
+class ScaffoldPaddingDetectorTest : LintDetectorTest() {
+ override fun getDetector(): Detector = ScaffoldPaddingDetector()
+
+ override fun getIssues(): MutableList<Issue> =
+ mutableListOf(ScaffoldPaddingDetector.UnusedMaterialScaffoldPaddingParameter)
+
+ private val PaddingValuesStub = compiledStub(
+ filename = "Padding.kt",
+ filepath = "androidx/compose/foundation/layout",
+ checksum = 0xeedd3f96,
+ """
+
+ package androidx.compose.foundation.layout
+
+ import androidx.compose.ui.Modifier
+
+ interface PaddingValues
+
+ """,
+ """
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGI2BijgUueSTMxLKcrPTKnQS87PLcgvTtXL
+ TSxJLcpMzBHiCk5OTEvLz0nxLuHi5WJOy88XYgtJLS7xLlFi0GIAACJwI+tQ
+ AAAA
+ """,
+ """
+ androidx/compose/foundation/layout/PaddingValues.class:
+ H4sIAAAAAAAAAJVOTUvDQBB9s9Gkxq9ULdQ/YdrizZMXIVBRFHrJaZtsyzbp
+ rnQ3pd76uzxIz/4ocVL9A87Amzfz4L35+v74BHCLHmEgTbmyutykhV2+WafS
+ mW1MKb22Jq3lu218+izLUpv5RNaNchGIkCzkWrJs5unTdKEKHyEgdMeV9bU2
+ 6aPyki3kHUEs1wFnUQthCyBQxfeNbrcBs3JI6O22nVj0RSwSZrP+bjsSA2rF
+ EWE0/u+THMw58d/tpvK8vNpmVagHXSvC9UtjvF6qiXZ6Wqt7Y6zfu7mQM3GA
+ 3xK43OMFrngO2fKQO8wRZIgydDIcIWaK4wwnOM1BDmc4zyEcEofuD692uKBp
+ AQAA
+ """
+
+ )
+
+ // Simplified Scaffold.kt stubs
+ private val ScaffoldStub = compiledStub(
+ filename = "Scaffold.kt",
+ filepath = "androidx/compose/material",
+ checksum = 0x2dde3750,
+ """
+ package androidx.compose.material
+
+ import androidx.compose.foundation.layout.PaddingValues
+ import androidx.compose.runtime.Composable
+ import androidx.compose.ui.Modifier
+
+ @Composable
+ fun Scaffold(
+ modifier: Modifier = Modifier,
+ topBar: @Composable () -> Unit = {},
+ bottomBar: @Composable () -> Unit = {},
+ content: @Composable (PaddingValues) -> Unit
+ ) {}
+
+ """,
+ """
+ META-INF/main.kotlin_module:
+ H4sIAAAAAAAAAGNgYGBmYGBgBGI2BijgUueSTMxLKcrPTKnQS87PLcgvTtXL
+ TSxJLcpMzBHiCk5OTEvLz0nxLuHi5WJOy88XYgtJLS7xLlFi0GIAACJwI+tQ
+ AAAA
+ """,
+ """
+ androidx/compose/material/ScaffoldKt$Scaffold$1.class:
+ H4sIAAAAAAAAAKVU604TQRT+Zlt6xxZEuYj3qi0o2+LdNiSEQNxQMLHYxPBr
+ 2t3C0N1Z091t8B8P4RP4BKKJJJoY4k8fynhmaQ2GiBo32bMn53zfmXOb/fb9
+ 0xcA9/CEQefS7LrC3NVbrvPK9Szd4b7VFdzW6y3ebru2uernB2q+HAdjWK11
+ XN8WUt/pObqQhJeEr3GnafLKcV87kC1fuNLTV/paqTrwv5DCryxUGKZ+HyyO
+ KMOl0wPGEWOIVQWFW2CIFIoNhmjBKDYySCCVwhDSZPC3hcdQrv1juZReTMie
+ 27EYxgrF2g7vcd3mckt/1tyxWn4lgyySKWgYYUgfqyyOswwJY72+sbi+tMww
+ /EvZGZzD+STGME6gassOk1f5hqGmlPtMkrRphpEBcc3yucl9TilpTi9CA2RK
+ xJQAA+soJULOXaG0EmlmmWH6cC+ROtxLaTmNPrnDvSmtxJ6mvr6NaQlNYeYp
+ 8SqXrnztuIFHLaRg+b9pUxy3GXI/e2VabR7YPsObwskuB0Jfc03RFlb3Twvy
+ n/5yxTg5JbUMc9Cp0kG6cx3KNLrkmjTY0Zrb4naDU31N29pQgiFbE9JaD5ym
+ 1e1bMoaUVnfJ5p5n0S5ll2XLdj0ht2gy267JkKyLLcn9oEvgVN0Nui1rRSjm
+ 5PNA+sKxGsITFGpRStfnYdoo0ZSHqON0rzCpxk6ji9JLq0CWedLyhGBq0DOR
+ A2T2w2HfJZk5smI45IyoPewzZkMMvQqs0T1XMGVIHyOyI2JukYi5PnFe7ZE6
+ fOYjRt9j4t0p/ET/4ASlPTh4nNDqSX+G9vIAFz7g4n5oGMJ9kimCHQEm8CCs
+ 8w7V/zA8JIJH4beMx+Gvia49sS5vImLgioGrBq7hukHNuGHgJm5tgnkooEh+
+ DzMeZj1kfwB7t1DT1wQAAA==
+ """,
+ """
+ androidx/compose/material/ScaffoldKt$Scaffold$2.class:
+ H4sIAAAAAAAAAKVU604TQRT+Zlt6WYotiHIR71VbULatd9uQECJxQ8HEYhPD
+ r2l3C0O3s6a72+A/HsIn8AlEE0k0McSfPpTxzNIqhogaN9mzJ+d835lzm/36
+ 7eNnAHfwiMHg0uq6wtoxmm7npevZRof7dldwx6g1eavlOtaKnx2o2VIcjGGl
+ 2nZ9R0hju9cxhCS8JHyVdxoWLx/1tQLZ9IUrPWO5rxUqA/9zKfzyQplh+vfB
+ 4ogyXDg5YBwxhlhFULgFhkguX2eI5sx8PYUEdB1DGCaDvyU8hmL1H8ul9GJC
+ 9ty2zTCey1e3eY8bDpebxtPGtt30yymkkdShYZRh+EhlcZxmSJhrtfXFtaXH
+ DCO/lJ3CGZxNYhwTBKo0nTB5lW8Yalq5TyVJm2EYHRBXbZ9b3OeUktbpRWiA
+ TImYEmBgbaVEyLkjlFYgzSoyzBzsJvSDXV3LaPTJHOxOawX2RP/yJqYlNIUp
+ UeIVLl35quMGHrWQgmX/pk1x3GTI/OiVZbd44PgMr3PHuxwIY9W1REvY3T8t
+ yH/6i2Xz+JTUMszDoEoH6c63KdPokmvRYMeqbpM7dU71NRx7XQmGdFVIey3o
+ NOxu35IypbS7Sw73PJt2Kf1YNh3XE3KTJrPlWgzJmtiU3A+6BNZrbtBt2stC
+ MaeeBdIXHbsuPEGhFqV0fR6mjQJNeYg6TvcKU2rsNLoovbQKZCmRliUEU4Oe
+ jewjtRcO+zbJ1KEVIyFnVO1hnzEXYuhVYI3uuYKxkPKTyA6JmUUiZvrEktoj
+ dfjsB4y9w+TbE/iJ/sEJSntw8ASh1TP8CdqLfZx7j/N7oWEId0nqBDsETOJe
+ WOctqv9+eEgED8JvEQ/DXxNde2Jd3EDExCUTl01cwVWTmnHNxHXc2ADzkEOe
+ /B5mPcx5SH8Hm6I3JNcEAAA=
+ """,
+ """
+ androidx/compose/material/ScaffoldKt.class:
+ H4sIAAAAAAAAAMVVS3PbVBT+rl+SFSd1lThN3BJK49I0jyo25elQSE3Titim
+ g9tssrqWZaNYusrokSkbJgx/gQ1b/gGsOiwYD0v+BX+E6ZFshzTupGTKDAvd
+ e173nO+ce+7Rn3//9juAu2gwlLjoeK7VeaYZrnPo+qbm8MD0LG5rLYN3u67d
+ 2Q0kMIb8AT/ims1FT/uqfWAaJE0yyGMrhu9X6hPOQktruB2ra5letd53A9sS
+ 2sGRo3VDYQSWK3xtZ0RtvqG+XL29x/DXm2HYGuufCiuo3vtvzctbG5Pgum4o
+ OjxSU2m/dcNAe8w7HUv09rgdmn71TIQox5uTXrxQBJZjarWY523brDIs112v
+ px2YQdvjFuHgQrgBH2JqukEztG2ykp1RbWQoDEunMrAENYKgRtBF4JEDy/Al
+ 5BgKxjem0R95eMw97phkyHBrpX62RaqnJK3ISY8yyGEGlxRMI8+QCdzD+5xi
+ qwzZthsErhOzcwyS4RIAEciYJ1znXyvD9dd1z2tNymSSH3dzqWN2eWgHDD/+
+ z12tTxY1aoJr54GS8BaVM2oGLsgJw/k5lE4sqzm8jetZLOEdBu3fjIbSScXK
+ EpapnfRm68l2s/aAoTwZ9HwHFP0m3s2ihFsvd+Ir6ibh9oURViSsXRxWJYa1
+ kcU67uSQRkZBApsMl8c31zADTk+YU/8knKMkTVYWLZloAQPrR0SClM+siKKj
+ iU6Z4YfB8Q1lcKwk8ol4WzjZ4k9OjOni0/zguJjYZBVZJmOikpVZolLFaTWl
+ knwz/cfPmYSciaXShPRKXi7OxjJlpMkONY+kCEqFRSjVcTanX8yEMHojlYsP
+ MYapcTnv9OlNpWpux2S4VLeE2Qydtuk9iWZWFNA1uL3H6TKIHwmzLasneBB6
+ RF/9ejjpdHFk+Rapt/8ZavQzO6s9mU4vmU23Am70G/xwFCCnC2F6NZv7vklq
+ peWGnmHuWJFuceRybyIcytQHqeiOaV+MGoO4GnF8JF9cVaee4/KaOkvrulqg
+ dUO9Qusv8ZEvoh6hyi/QOHxA9OrwEBSSIKZU+lhMzdGXiKl5FJHETuxBwsOR
+ D5n2R5E+RUw2brszaz6Lq7hGdITQoVAZ2iuFVOq7n6D8ihsDLO0WUukhtzLA
+ ar2QkoacRlxjdW194znKQ+g6rWkkZ6an4yyWCAkoiETYZ2gvYIpCZbGMHGWV
+ Jbxfkl6lg6U4swV6SsN9N3Z3H3Xa6wSuQm7f20dSx10d7+v4AB/q+Agf6/gE
+ 1X0wH1v4dB9TPtI+7vlQfCz4UH185kP2Medj3sfnPrZfADvMWafjCAAA
+ """
+ )
+
+ @Test
+ fun unreferencedParameters() {
+ lint().files(
+ kotlin(
+ """
+ package foo
+
+ import androidx.compose.material.*
+ import androidx.compose.runtime.*
+ import androidx.compose.ui.*
+
+ @Composable
+ fun Test() {
+ Scaffold { /**/ }
+ Scaffold(Modifier) { /**/ }
+ Scaffold(Modifier, topBar = {}, bottomBar = {}) { /**/ }
+ Scaffold(Modifier, topBar = {}, bottomBar = {}, content = { /**/ })
+ Scaffold(Modifier, topBar = {}, bottomBar = {}) { _ -> /**/ }
+ Scaffold(Modifier, topBar = {}, bottomBar = {}) { innerPadding -> /**/ }
+ }
+ """
+ ),
+ PaddingValuesStub,
+ ScaffoldStub,
+ Stubs.Modifier,
+ Stubs.Composable
+ )
+ .run()
+ .expect(
+ """
+src/foo/test.kt:10: Error: Content padding parameter it is not used [UnusedMaterialScaffoldPaddingParameter]
+ Scaffold { /**/ }
+ ~~~~~~~~
+src/foo/test.kt:11: Error: Content padding parameter it is not used [UnusedMaterialScaffoldPaddingParameter]
+ Scaffold(Modifier) { /**/ }
+ ~~~~~~~~
+src/foo/test.kt:12: Error: Content padding parameter it is not used [UnusedMaterialScaffoldPaddingParameter]
+ Scaffold(Modifier, topBar = {}, bottomBar = {}) { /**/ }
+ ~~~~~~~~
+src/foo/test.kt:13: Error: Content padding parameter it is not used [UnusedMaterialScaffoldPaddingParameter]
+ Scaffold(Modifier, topBar = {}, bottomBar = {}, content = { /**/ })
+ ~~~~~~~~
+src/foo/test.kt:14: Error: Content padding parameter _ is not used [UnusedMaterialScaffoldPaddingParameter]
+ Scaffold(Modifier, topBar = {}, bottomBar = {}) { _ -> /**/ }
+ ~
+src/foo/test.kt:15: Error: Content padding parameter innerPadding is not used [UnusedMaterialScaffoldPaddingParameter]
+ Scaffold(Modifier, topBar = {}, bottomBar = {}) { innerPadding -> /**/ }
+ ~~~~~~~~~~~~
+6 errors, 0 warnings
+ """
+ )
+ }
+
+ @Test
+ fun unreferencedParameter_shadowedNames() {
+ lint().files(
+ kotlin(
+ """
+ package foo
+
+ import androidx.compose.material.*
+ import androidx.compose.runtime.*
+ import androidx.compose.ui.*
+
+ val foo = false
+
+ @Composable
+ fun Test() {
+ Scaffold {
+ foo.let {
+ // These `it`s refer to the `let`, not the `Scaffold`, so we
+ // should still report an error
+ it.let {
+ if (it) { /**/ } else { /**/ }
+ }
+ }
+ }
+ Scaffold(Modifier, topBar = {}, bottomBar = {}) { innerPadding ->
+ foo.let { innerPadding ->
+ // These `innerPadding`s refer to the `let`, not the `Scaffold`, so we
+ // should still report an error
+ innerPadding.let {
+ if (innerPadding) { /**/ } else { /**/ }
+ }
+ }
+ }
+ }
+ """
+ ),
+ PaddingValuesStub,
+ ScaffoldStub,
+ Stubs.Modifier,
+ Stubs.Composable
+ )
+ .run()
+ .expect(
+ """
+src/foo/test.kt:12: Error: Content padding parameter it is not used [UnusedMaterialScaffoldPaddingParameter]
+ Scaffold {
+ ^
+src/foo/test.kt:21: Error: Content padding parameter innerPadding is not used [UnusedMaterialScaffoldPaddingParameter]
+ Scaffold(Modifier, topBar = {}, bottomBar = {}) { innerPadding ->
+ ~~~~~~~~~~~~
+2 errors, 0 warnings
+ """
+ )
+ }
+
+ @Test
+ fun noErrors() {
+ lint().files(
+ kotlin(
+ """
+ package foo
+
+ import androidx.compose.material.*
+ import androidx.compose.runtime.*
+ import androidx.compose.ui.*
+
+ @Composable
+ fun Test() {
+ Scaffold {
+ it
+ }
+ Scaffold(Modifier, topBar = {}, bottomBar = {}) { innerPadding ->
+ innerPadding
+ }
+ }
+ """
+ ),
+ PaddingValuesStub,
+ ScaffoldStub,
+ Stubs.Modifier,
+ Stubs.Composable
+ )
+ .run()
+ .expectClean()
+ }
+}
+/* ktlint-enable max-line-length */
diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/keyinput/InterceptEnterToSendMessageDemo.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/keyinput/InterceptEnterToSendMessageDemo.kt
index 52bcfa6..3c839a9 100644
--- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/keyinput/InterceptEnterToSendMessageDemo.kt
+++ b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/keyinput/InterceptEnterToSendMessageDemo.kt
@@ -52,8 +52,8 @@
val scaffoldState = rememberScaffoldState()
val coroutineScope = rememberCoroutineScope()
var textFieldValue by remember { mutableStateOf(TextFieldValue("")) }
- Scaffold(scaffoldState = scaffoldState) {
- Column {
+ Scaffold(scaffoldState = scaffoldState) { innerPadding ->
+ Column(Modifier.padding(innerPadding)) {
Text(
text = "Use a physical keyboard with this demo. As you enter text into this " +
"textfield, notice how the enter key is intercepted to show a snackbar." +
diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/modifier/CommunicatingModifierDemo.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/modifier/CommunicatingModifierDemo.kt
index 8bc83e7f..6e04d4c 100644
--- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/modifier/CommunicatingModifierDemo.kt
+++ b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/modifier/CommunicatingModifierDemo.kt
@@ -64,10 +64,11 @@
}
}
- Scaffold(scaffoldState = scaffoldState) {
+ Scaffold(scaffoldState = scaffoldState) { innerPadding ->
Column(
Modifier
.background(Gray)
+ .padding(innerPadding)
.modifierLocalProvider(ModifierLocalColor) { "Gray" }
) {
Text("Click the red box to read the parent's ModifierLocalColor")