Add lint rule to remember getBackstackEntry()

You should always remember the value returned from
navController.getBackStackEntry() when using compose.

Test: added test
Bug: 197675882
Change-Id: I92249572af057ce5969f734cf3db2ca1f6606323
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/libraries/Libraries.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/libraries/Libraries.kt
index f160221..89e8c65 100644
--- a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/libraries/Libraries.kt
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/libraries/Libraries.kt
@@ -35,6 +35,7 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -138,9 +139,8 @@
             navigation(startDestination = innerStartRoute, route = "Parent") {
                 // ...
                 composable("exampleWithRoute") { backStackEntry ->
-                    val parentViewModel = hiltViewModel<ParentViewModel>(
-                        navController.getBackStackEntry("Parent")
-                    )
+                    val parentEntry = remember { navController.getBackStackEntry("Parent") }
+                    val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry)
                     ExampleWithRouteScreen(parentViewModel)
                 }
             }
diff --git a/hilt/hilt-navigation-compose/samples/src/main/java/androidx/hilt/navigation/compose/samples/HiltViewModelSamples.kt b/hilt/hilt-navigation-compose/samples/src/main/java/androidx/hilt/navigation/compose/samples/HiltViewModelSamples.kt
index e52fb79..30b2111 100644
--- a/hilt/hilt-navigation-compose/samples/src/main/java/androidx/hilt/navigation/compose/samples/HiltViewModelSamples.kt
+++ b/hilt/hilt-navigation-compose/samples/src/main/java/androidx/hilt/navigation/compose/samples/HiltViewModelSamples.kt
@@ -20,6 +20,7 @@
 
 import androidx.annotation.Sampled
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
 import androidx.hilt.navigation.compose.hiltViewModel
 import androidx.lifecycle.ViewModel
 import androidx.navigation.compose.NavHost
@@ -47,14 +48,12 @@
     NavHost(navController, startDestination = "Parent") {
         navigation(startDestination = "InnerRouteA", route = "Parent") {
             composable("InnerRouteA") {
-                val viewModel = hiltViewModel<ParentViewModel>(
-                    navController.getBackStackEntry("Parent")
-                )
+                val parentEntry = remember { navController.getBackStackEntry("Parent") }
+                val viewModel = hiltViewModel<ParentViewModel>(parentEntry)
             }
             composable("InnerRouteB") {
-                val viewModel = hiltViewModel<ParentViewModel>(
-                    navController.getBackStackEntry("Parent")
-                )
+                val parentEntry = remember { navController.getBackStackEntry("Parent") }
+                val viewModel = hiltViewModel<ParentViewModel>(parentEntry)
             }
         }
     }
diff --git a/navigation/navigation-compose-lint/build.gradle b/navigation/navigation-compose-lint/build.gradle
new file mode 100644
index 0000000..aacd3fdd
--- /dev/null
+++ b/navigation/navigation-compose-lint/build.gradle
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 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.
+ */
+
+import androidx.build.BundleInsideHelper
+import androidx.build.LibraryGroups
+import androidx.build.LibraryType
+
+plugins {
+    id("AndroidXPlugin")
+    id("kotlin")
+}
+
+BundleInsideHelper.forInsideLintJar(project)
+
+dependencies {
+    compileOnly(libs.androidLintMinComposeApi)
+    compileOnly(libs.kotlinStdlib)
+    bundleInside(projectOrArtifact(":compose:lint:common"))
+
+    testImplementation(projectOrArtifact(":compose:lint:common-test"))
+    testImplementation(libs.kotlinStdlib)
+    testImplementation(libs.kotlinReflect)
+    testImplementation(libs.kotlinStdlibJdk8)
+    testImplementation(libs.androidLint)
+    testImplementation(libs.androidLintTests)
+    testImplementation(libs.junit)
+    testImplementation(libs.truth)
+}
+
+androidx {
+    name = "Navigation Compose Lint"
+    type = LibraryType.LINT
+    mavenGroup = LibraryGroups.NAVIGATION
+    inceptionYear = "2021"
+    description = "Lint checks for Navigation Compose"
+}
diff --git a/navigation/navigation-compose-lint/src/main/java/androidx/navigation/compose/lint/NavigationComposeIssueRegistry.kt b/navigation/navigation-compose-lint/src/main/java/androidx/navigation/compose/lint/NavigationComposeIssueRegistry.kt
new file mode 100644
index 0000000..92e1225
--- /dev/null
+++ b/navigation/navigation-compose-lint/src/main/java/androidx/navigation/compose/lint/NavigationComposeIssueRegistry.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 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.navigation.compose.lint
+
+import com.android.tools.lint.client.api.IssueRegistry
+import com.android.tools.lint.client.api.Vendor
+import com.android.tools.lint.detector.api.CURRENT_API
+
+/**
+ * [IssueRegistry] containing runtime specific lint issues.
+ */
+class NavigationComposeIssueRegistry : IssueRegistry() {
+    // Tests are run with this version. We ensure that with ApiLintVersionsTest
+    override val api = 11
+    override val minApi = CURRENT_API
+    override val issues get() = listOf(
+        UnrememberedGetBackStackEntryDetector.UnrememberedGetBackStackEntry
+    )
+    override val vendor = Vendor(
+        vendorName = "Jetpack Navigation Compose",
+        identifier = "androidx.navigation.compose"
+    )
+}
\ No newline at end of file
diff --git a/navigation/navigation-compose-lint/src/main/java/androidx/navigation/compose/lint/UnrememberedGetBackStackEntryDetector.kt b/navigation/navigation-compose-lint/src/main/java/androidx/navigation/compose/lint/UnrememberedGetBackStackEntryDetector.kt
new file mode 100644
index 0000000..00a0b44
--- /dev/null
+++ b/navigation/navigation-compose-lint/src/main/java/androidx/navigation/compose/lint/UnrememberedGetBackStackEntryDetector.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2021 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.navigation.compose.lint
+
+import androidx.compose.lint.Name
+import androidx.compose.lint.Package
+import androidx.compose.lint.invokedInComposableBodyAndNotRemembered
+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.intellij.psi.PsiMethod
+import org.jetbrains.uast.UCallExpression
+import java.util.EnumSet
+
+/**
+ * [Detector] that checks `getBackStackEntry` calls to make sure that if they are called inside a
+ * Composable body, they are `remember`ed.
+ */
+class UnrememberedGetBackStackEntryDetector : Detector(), SourceCodeScanner {
+    override fun getApplicableMethodNames(): List<String> = listOf(
+        GetBackStackEntry.shortName
+    )
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        if (!method.isInPackageName(PackageName)) return
+
+        if (node.invokedInComposableBodyAndNotRemembered()) {
+            context.report(
+                UnrememberedGetBackStackEntry,
+                node,
+                context.getNameLocation(node),
+                "Calling getBackStackEntry during composition without using `remember`"
+            )
+        }
+    }
+
+    companion object {
+        val UnrememberedGetBackStackEntry = Issue.create(
+            "UnrememberedGetBackStackEntry",
+            "Calling getBackStackEntry during composition with using `remember`",
+            "Backstack entries retrieved during composition need to be `remember`ed, otherwise " +
+                "they will be retrieved from the navController again, and be changed. Either " +
+                "hoist the state to an object that is not created during composition, or wrap " +
+                "the state in a call to `remember`.",
+            Category.CORRECTNESS, 3, Severity.ERROR,
+            Implementation(
+                UnrememberedGetBackStackEntryDetector::class.java,
+                EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
+            )
+        )
+    }
+}
+
+private val PackageName = Package("androidx.navigation")
+private val GetBackStackEntry = Name(PackageName, "getBackStackEntry")
diff --git a/navigation/navigation-compose-lint/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry b/navigation/navigation-compose-lint/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry
new file mode 100644
index 0000000..796abf7
--- /dev/null
+++ b/navigation/navigation-compose-lint/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry
@@ -0,0 +1 @@
+androidx.navigation.compose.lint.NavigationComposeIssueRegistry
diff --git a/navigation/navigation-compose-lint/src/test/java/androidx/navigation/compose/lint/Stubs.kt b/navigation/navigation-compose-lint/src/test/java/androidx/navigation/compose/lint/Stubs.kt
new file mode 100644
index 0000000..984a6000
--- /dev/null
+++ b/navigation/navigation-compose-lint/src/test/java/androidx/navigation/compose/lint/Stubs.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2021 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.navigation.compose.lint
+
+import androidx.compose.lint.test.compiledStub
+
+internal val NAV_BACK_STACK_ENTRY = compiledStub(
+    filename = "NavBackStackEntry.kt",
+    filepath = "androidx/navigation",
+    checksum = 0x6920c3ac,
+    source = """
+    package androidx.navigation
+
+    public class NavBackStackEntry
+""",
+    """
+    META-INF/main.kotlin_module:
+    H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3AJcTFnZyfq5dakZhbkJMqxBzvXaLE
+    oMUAAMRK5d0sAAAA
+    """,
+    """
+    androidx/navigation/NavBackStackEntry.class:
+    H4sIAAAAAAAAAI2Ru04CQRSG/zPAoisKKiqosTNeCleMncZEjCYkiIkYGqqB
+    3eBwmU12hw12PItvYGViYYilD2U8u9rZOMWX8/9nMucyn19v7wBOsU3YldoN
+    fOVOHC0j1ZNG+dppyKgqu4OmYVxrEzxlQYRCX0bSGUrdc+46fa9rskgRrHOl
+    lbkgpPYPWjlkYNlII0tIm0cVEvbq/6pwRliuD3wzVNq59Yx0pZHsiVGU4lYp
+    RoZAA7YmKlbHHLkVws5satuiJGxR4Gg2Lc2mJ+KYqpmPZ0sURHzrhPgFFP/U
+    PBoYbvPKdz1Cvq601xiPOl7wIDtDdlbqflcOWzJQsf417aY/DrrejYpF+X6s
+    jRp5LRUqzl5q7ZtkvBAVCN5CfLjpeCnMDVZOonmWw1fMvXAgUGJaiZlGmZn7
+    uYB52El+M+E6tpIvIyxwLtdGqobFGpaYyMco1LCMlTYoxCqKnA9hh1gLYX0D
+    +QLjIO8BAAA=
+    """
+)
+
+internal val NAV_CONTROLLER = compiledStub(
+    filename = "NavController.kt",
+    filepath = "androidx/navigation",
+    checksum = 0xa6eda16e,
+    source = """
+    package androidx.navigation
+
+    public class NavController {
+        public fun getBackStackEntry(route: String) = NavBackStackEntry()
+    }
+""",
+    """
+    META-INF/main.kotlin_module:
+    H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM3AJcTFnZyfq5dakZhbkJMqxBzvXaLE
+    oMUAAMRK5d0sAAAA
+    """,
+    """
+    androidx/navigation/NavController.class:
+    H4sIAAAAAAAAAI1SW08TQRT+Ztru4oJlQbkrioDclAXikzVGIZqU1GrEkBie
+    pttJmXY7m+xOG3zjt/gL9AmjiSE++qOMZ8pGrGhkkz1nzjnf+WbO5fuPz18B
+    PMA6w5zQ9SRW9aNAi65qCKNiHVRFdyfWJomjSCYuGIPfFF0RREI3gpe1pgyN
+    ixyD80hpZR4z5JZX9odQgOMhD5chbw5VyjBf+S97iWGkIc22CFt7hsQzCrxj
+    KC1Xzm/cM4nSjdLKv9j6k0v23jhpBE1paolQOg2E1rHpwdOgGptqJ4oIVUji
+    jpEDKDLMtmITKR00u+1AaSMTLaKgrO29qQpTFz7DWHgow1aW/kokoi0JyLD0
+    +1PPmlP6y+OpP6O45mEE1xkWL1WJi3EPE7afoxcJqW+V7NUvpBF1YQT5eLub
+    o9EyKwoMrEWuI2WtDTrVNxkenh6Pe3ySe9w/Pfb4AO8Z9ugXJ0+Pt/gG2y58
+    e+9wn+8W/dw038hvOX6BtGMZthixY+nSo/D7pr3eMrQcO3FdMgxXlJbVTrsm
+    kzeiFklbZRyKaF8kytqZc+Z1RxvVlmXdVaki19PzYTIs/Bn9NZg+mLcXd5JQ
+    PleWcSrL2b/Ah01wWmD7caqS9tnWSlZAmtmWrp5g4GMvvEzS6TnzWCE5dAbA
+    FXikRzBInlwveZvQnHRxbXT4E8a+YOLtCSY/9LE4lGlZxs+QGYs9FTFF8dUM
+    d5X0Gv0uywyOez15F/dJPyHvNFHNHCBXxo0ybpLErBW3yriNuQOwFHcwfwA3
+    hZdiIYWTYjDFYooimT8B9qxp7xsEAAA=
+    """
+)
diff --git a/navigation/navigation-compose-lint/src/test/java/androidx/navigation/compose/lint/UnrememberedGetBackStackEntryDetectorTest.kt b/navigation/navigation-compose-lint/src/test/java/androidx/navigation/compose/lint/UnrememberedGetBackStackEntryDetectorTest.kt
new file mode 100644
index 0000000..defabf5
--- /dev/null
+++ b/navigation/navigation-compose-lint/src/test/java/androidx/navigation/compose/lint/UnrememberedGetBackStackEntryDetectorTest.kt
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2021 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.navigation.compose.lint
+
+import androidx.compose.lint.test.Stubs
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestMode
+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 [UnrememberedGetBackStackEntryDetector].
+ */
+class UnrememberedGetBackStackEntryDetectorTest : LintDetectorTest() {
+    override fun getDetector(): Detector = UnrememberedGetBackStackEntryDetector()
+
+    override fun getIssues(): MutableList<Issue> =
+        mutableListOf(UnrememberedGetBackStackEntryDetector.UnrememberedGetBackStackEntry)
+
+    @Test
+    fun notRemembered() {
+        lint().files(
+            kotlin(
+                """
+                package com.example
+
+                import androidx.compose.runtime.*
+                import androidx.navigation.NavController
+
+                @Composable
+                fun Test() {
+                    val navController = NavController()
+                    navController.getBackStackEntry("test")
+                }
+
+                val lambda = @Composable {
+                    val navController = NavController()
+                    navController.getBackStackEntry("test")
+                }
+
+                val lambda2: @Composable () -> Unit = {
+                    val navController = NavController()
+                    navController.getBackStackEntry("test")
+                }
+
+                @Composable
+                fun LambdaParameter(content: @Composable () -> Unit) {}
+
+                @Composable
+                fun Test2() {
+                    LambdaParameter(content = {
+                        val navController = NavController()
+                        navController.getBackStackEntry("test")
+                    })
+                    LambdaParameter {
+                        val navController = NavController()
+                        navController.getBackStackEntry("test")
+                    }
+                }
+
+                fun test3() {
+                    val localLambda1 = @Composable {
+                        val navController = NavController()
+                        navController.getBackStackEntry("test")
+                    }
+
+                    val localLambda2: @Composable () -> Unit = {
+                        val navController = NavController()
+                        navController.getBackStackEntry("test")
+                    }
+                }
+
+                @Composable
+                fun Test4() {
+                    val localObject = object {
+                        val navController = NavController()
+                        val entry = navController.getBackStackEntry("test")
+                    }
+                }
+            """
+            ),
+            Stubs.Composable,
+            NAV_CONTROLLER
+        )
+            .skipTestModes(TestMode.TYPE_ALIAS)
+            .run()
+            .expect(
+                """
+src/com/example/{.kt:10: Error: Calling getBackStackEntry during composition without using remember [UnrememberedGetBackStackEntry]
+                    navController.getBackStackEntry("test")
+                                  ~~~~~~~~~~~~~~~~~
+src/com/example/{.kt:15: Error: Calling getBackStackEntry during composition without using remember [UnrememberedGetBackStackEntry]
+                    navController.getBackStackEntry("test")
+                                  ~~~~~~~~~~~~~~~~~
+src/com/example/{.kt:20: Error: Calling getBackStackEntry during composition without using remember [UnrememberedGetBackStackEntry]
+                    navController.getBackStackEntry("test")
+                                  ~~~~~~~~~~~~~~~~~
+src/com/example/{.kt:30: Error: Calling getBackStackEntry during composition without using remember [UnrememberedGetBackStackEntry]
+                        navController.getBackStackEntry("test")
+                                      ~~~~~~~~~~~~~~~~~
+src/com/example/{.kt:34: Error: Calling getBackStackEntry during composition without using remember [UnrememberedGetBackStackEntry]
+                        navController.getBackStackEntry("test")
+                                      ~~~~~~~~~~~~~~~~~
+src/com/example/{.kt:41: Error: Calling getBackStackEntry during composition without using remember [UnrememberedGetBackStackEntry]
+                        navController.getBackStackEntry("test")
+                                      ~~~~~~~~~~~~~~~~~
+src/com/example/{.kt:46: Error: Calling getBackStackEntry during composition without using remember [UnrememberedGetBackStackEntry]
+                        navController.getBackStackEntry("test")
+                                      ~~~~~~~~~~~~~~~~~
+src/com/example/{.kt:54: Error: Calling getBackStackEntry during composition without using remember [UnrememberedGetBackStackEntry]
+                        val entry = navController.getBackStackEntry("test")
+                                                  ~~~~~~~~~~~~~~~~~
+8 errors, 0 warnings
+            """
+            )
+    }
+
+    @Test
+    fun rememberedInsideComposableBody() {
+        lint().files(
+            kotlin(
+                """
+                package com.example
+
+                import androidx.compose.runtime.*
+                import androidx.navigation.NavController
+
+                @Composable
+                fun Test() {
+                    val navController = NavController()
+                    val entry = remember { navController.getBackStackEntry("test") }
+                }
+
+                val lambda = @Composable {
+                    val navController = NavController()
+                    val entry = remember { navController.getBackStackEntry("test") }
+                }
+
+                val lambda2: @Composable () -> Unit = {
+                    val navController = NavController()
+                    val entry = remember { navController.getBackStackEntry("test") }
+                }
+
+                @Composable
+                fun LambdaParameter(content: @Composable () -> Unit) {}
+
+                @Composable
+                fun Test2() {
+                    LambdaParameter(content = {
+                        val navController = NavController()
+                        val entry = remember { navController.getBackStackEntry("test") }
+                    })
+                    LambdaParameter {
+                        val navController = NavController()
+                        val entry = remember { navController.getBackStackEntry("test") }
+                    }
+                }
+
+                fun test3() {
+                    val localLambda1 = @Composable {
+                        val navController = NavController()
+                        val entry = remember { navController.getBackStackEntry("test") }
+                    }
+
+                    val localLambda2: @Composable () -> Unit = {
+                        val navController = NavController()
+                        val entry = remember { navController.getBackStackEntry("test") }
+                    }
+                }
+            """
+            ),
+            Stubs.Composable,
+            Stubs.Remember,
+            NAV_CONTROLLER
+        )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun noErrors() {
+        lint().files(
+            kotlin(
+                """
+                package com.example
+
+                import androidx.compose.runtime.*
+                import androidx.navigation.NavController
+
+                fun test() {
+                    val navController = NavController()
+                    navController.getBackStackEntry("test")
+                }
+
+                val lambda = {
+                    val navController = NavController()
+                    navController.getBackStackEntry("test")
+                }
+
+                val lambda2: () -> Unit = {
+                    val navController = NavController()
+                    navController.getBackStackEntry("test")
+                }
+
+                fun LambdaParameter(content: () -> Unit) {}
+
+                fun test2() {
+                    LambdaParameter(content = {
+                        val navController = NavController()
+                        navController.getBackStackEntry("test")
+                    })
+                    LambdaParameter {
+                        val navController = NavController()
+                        navController.getBackStackEntry("test")
+                    }
+                }
+
+                fun test3() {
+                    val localLambda1 = {
+                        val navController = NavController()
+                        navController.getBackStackEntry("test")
+                    }
+
+                    val localLambda2: () -> Unit = {
+                        val navController = NavController()
+                        navController.getBackStackEntry("test")
+                    }
+                }
+
+                fun test3() {
+                    class Foo {
+                        val navController = NavController()
+                        val entry = navController.getBackStackEntry("test")
+                    }
+
+                    val localObject = object {
+                        val navController = NavController()
+                        val entry = navController.getBackStackEntry("test")
+                    }
+                }
+
+                @Composable
+                fun Test4() {
+                    class Foo {
+                        val navController = NavController()
+                        val entry = navController.getBackStackEntry("test")
+                    }
+                }
+            """
+            ),
+            Stubs.Composable,
+            Stubs.Remember,
+            NAV_CONTROLLER
+        )
+            .run()
+            .expectClean()
+    }
+}
+/* ktlint-enable max-line-length */
diff --git a/navigation/navigation-compose/build.gradle b/navigation/navigation-compose/build.gradle
index 6448a7e..12e1b2f 100644
--- a/navigation/navigation-compose/build.gradle
+++ b/navigation/navigation-compose/build.gradle
@@ -48,6 +48,9 @@
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.truth)
+
+    lintChecks(projectOrArtifact(":navigation:navigation-compose-lint"))
+    lintPublish(projectOrArtifact(":navigation:navigation-compose-lint"))
 }
 
 androidx {
diff --git a/settings.gradle b/settings.gradle
index 12807502..538a36a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -522,6 +522,7 @@
 includeProject(":navigation:navigation-compose", "navigation/navigation-compose", [BuildType.COMPOSE])
 includeProject(":navigation:navigation-compose:navigation-compose-samples", "navigation/navigation-compose/samples", [BuildType.COMPOSE])
 includeProject(":navigation:navigation-compose:integration-tests:navigation-demos", "navigation/navigation-compose/integration-tests/navigation-demos", [BuildType.COMPOSE])
+includeProject(":navigation:navigation-compose-lint", "navigation/navigation-compose-lint", [BuildType.COMPOSE])
 includeProject(":navigation:navigation-dynamic-features-fragment", "navigation/navigation-dynamic-features-fragment", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":navigation:navigation-dynamic-features-runtime", "navigation/navigation-dynamic-features-runtime", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":navigation:navigation-fragment", "navigation/navigation-fragment", [BuildType.MAIN, BuildType.FLAN])