Skip to main content

ktrs_compose/rules/
state_parameter.rs

1//! Port of `rules/StateParameter.kt`.
2
3use std::sync::LazyLock;
4
5use ktrs_ast::Ast;
6use ktrs_ast::psi::KtFunction;
7use ktrs_lint::rules::internal::KotlinRegex;
8
9use crate::core::compose_kt_config::ComposeKtConfig;
10use crate::core::compose_kt_visitor::ComposeKtVisitor;
11use crate::core::emitter::Emitter;
12
13pub struct StateParameter;
14
15impl ComposeKtVisitor for StateParameter {
16    fn visit_composable(&self, ast: &mut Ast, function: KtFunction, emitter: &mut dyn Emitter, _config: &dyn ComposeKtConfig) {
17        let parameters: Vec<_> = function
18            .value_parameters(ast)
19            .into_iter()
20            .filter(|it| it.type_reference(ast).is_some_and(|t| STATE_REGEX.matches(&t.text(ast))))
21            .collect();
22        for parameter in parameters {
23            emitter.report(ast, parameter.node(), STATE_PARAMETER_IN_COMPOSE, false);
24        }
25    }
26}
27
28static STATE_REGEX: LazyLock<KotlinRegex> = LazyLock::new(|| KotlinRegex::new("(State<.*>|(Int|Float|Double|Long)State)\\??"));
29
30pub const STATE_PARAMETER_IN_COMPOSE: &str = "\
31State shouldn't be used as a parameter in a @Composable function, as it encourages components that are not fully stateless.
32Instead, pass the snapshot state value and provide event callbacks for changes.
33See https://github.com/androidx/androidx/blob/androidx-main/compose/docs/compose-component-api-guidelines.md#statet-as-a-parameter for more information.";