11use syn:: { Expr , Pat , Stmt } ;
22
33use crate :: {
4- CollectionResult ,
4+ CollectionResult , RuleRunnerData ,
55 node_type_set:: NodeTypeSet ,
66 utils:: { astkind_variant_from_path, is_node_kind_call} ,
77} ;
88
99/// Detects top-level `let AstKind::... = node.kind() else { return; }` patterns in the `run` method.
10- pub struct LetElseDetector {
10+ pub struct LetElseDetector < ' a > {
1111 node_types : NodeTypeSet ,
12+ rule_runner_data : & ' a RuleRunnerData ,
1213}
1314
14- impl LetElseDetector {
15- pub fn from_run_func ( run_func : & syn:: ImplItemFn ) -> Option < NodeTypeSet > {
15+ impl < ' a > LetElseDetector < ' a > {
16+ pub fn from_run_func (
17+ run_func : & syn:: ImplItemFn ,
18+ rule_runner_data : & ' a RuleRunnerData ,
19+ ) -> Option < NodeTypeSet > {
1620 // Only consider when the body's first statement is `let AstKind::... = node.kind() else { ... }`,
1721 // and the body of the `else` is just `return`.
1822 let block = & run_func. block ;
@@ -37,14 +41,14 @@ impl LetElseDetector {
3741 return None ;
3842 }
3943
40- let mut detector = Self { node_types : NodeTypeSet :: new ( ) } ;
44+ let mut detector = Self { node_types : NodeTypeSet :: new ( ) , rule_runner_data } ;
4145
4246 if is_node_kind_as_call ( & init. expr ) {
4347 // If the initializer is `node.kind().as_<variant>()`, extract that variant.
4448 if let Expr :: MethodCall ( mc) = & * init. expr
45- && let Some ( variant ) = extract_variant_from_as_call ( mc)
49+ && let Some ( variants ) = detector . extract_variants_from_as_call ( mc)
4650 {
47- detector. node_types . insert ( variant ) ;
51+ detector. node_types . extend ( variants ) ;
4852 }
4953 } else {
5054 // Otherwise, the initializer is `node.kind()`, so extract from the pattern.
@@ -74,6 +78,25 @@ impl LetElseDetector {
7478 _ => CollectionResult :: Incomplete ,
7579 }
7680 }
81+
82+ fn extract_variants_from_as_call ( & self , mc : & syn:: ExprMethodCall ) -> Option < NodeTypeSet > {
83+ // Looking for `node.kind().as_<snake_case_variant>()`
84+ let method_ident = mc. method . to_string ( ) ;
85+ if !method_ident. starts_with ( "as_" ) || !mc. args . is_empty ( ) {
86+ return None ;
87+ }
88+ // Receiver must be `node.kind()`
89+ if !is_node_kind_call ( & mc. receiver ) {
90+ return None ;
91+ }
92+ let snake_variant = & method_ident[ 3 ..] ; // strip `as_`
93+ if snake_variant == "member_expression_kind" {
94+ return Some ( self . rule_runner_data . member_expression_kinds . clone ( ) ) ;
95+ }
96+ let mut node_type_set = NodeTypeSet :: new ( ) ;
97+ node_type_set. insert ( snake_to_pascal_case ( snake_variant) ) ;
98+ Some ( node_type_set)
99+ }
77100}
78101
79102/// Checks if is `node.kind().as_some_ast_kind()`
@@ -88,23 +111,6 @@ pub fn is_node_kind_as_call(expr: &Expr) -> bool {
88111 false
89112}
90113
91- fn extract_variant_from_as_call ( mc : & syn:: ExprMethodCall ) -> Option < String > {
92- // Looking for `node.kind().as_<snake_case_variant>()`
93- let method_ident = mc. method . to_string ( ) ;
94- if !method_ident. starts_with ( "as_" ) || !mc. args . is_empty ( ) {
95- return None ;
96- }
97- // Receiver must be `node.kind()`
98- if !is_node_kind_call ( & mc. receiver ) {
99- return None ;
100- }
101- let snake_variant = & method_ident[ 3 ..] ; // strip `as_`
102- if snake_variant == "member_expression_kind" {
103- return None ;
104- }
105- Some ( snake_to_pascal_case ( snake_variant) )
106- }
107-
108114fn snake_to_pascal_case ( s : & str ) -> String {
109115 s. split ( '_' )
110116 . filter ( |seg| !seg. is_empty ( ) )
0 commit comments