Skip to main content

ktrs_compose/rules/
composable_annotation_naming.rs

1//! Port of `rules/ComposableAnnotationNaming.kt`.
2
3use ktrs_ast::Ast;
4use ktrs_ast::psi::KtClass;
5
6use crate::core::compose_kt_config::ComposeKtConfig;
7use crate::core::compose_kt_visitor::ComposeKtVisitor;
8use crate::core::emitter::Emitter;
9
10pub struct ComposableAnnotationNaming;
11
12impl ComposeKtVisitor for ComposableAnnotationNaming {
13    fn visit_class(&self, ast: &mut Ast, clazz: KtClass, emitter: &mut dyn Emitter, _config: &dyn ComposeKtConfig) {
14        if !clazz.is_annotation(ast) {
15            return;
16        }
17        if !is_composable_target_marker_annotation(ast, clazz) {
18            return;
19        }
20        let name = clazz.name_as_safe_name(ast);
21        if !name.ends_with("Composable") {
22            emitter.report(ast, clazz.node(), COMPOSABLE_ANNOTATION_DOES_NOT_END_WITH_COMPOSABLE, false);
23        }
24    }
25}
26
27/// `KtAnnotated.isComposableTargetMarkerAnnotation`.
28fn is_composable_target_marker_annotation(ast: &Ast, clazz: KtClass) -> bool {
29    clazz
30        .annotation_entries(ast)
31        .into_iter()
32        .any(|it| it.callee_expression(ast).is_some_and(|c| ast.text(c).contains("ComposableTargetMarker")))
33}
34
35pub const COMPOSABLE_ANNOTATION_DOES_NOT_END_WITH_COMPOSABLE: &str = "\
36Composable annotations (e.g. tagged with `@ComposableTargetMarker`) should have the `Composable` suffix.
37See https://mrmans0n.github.io/compose-rules/rules/#naming-composable-annotations-properly for more information.";