@@ -76,26 +76,6 @@ pub enum MethodType {
7676 Custom , // all other user methods
7777}
7878
79- /// Checks whether a single `annotation` node's `identifier` child has text
80- /// equal to `expected_name`.
81- fn annotation_identifier_matches (
82- annotation_node : Node ,
83- content : & str ,
84- expected_name : & str ,
85- ) -> bool {
86- let count = annotation_node. child_count ( ) ;
87- let mut child_index = 0 ;
88- while child_index < count {
89- if let Some ( child) = annotation_node. child ( child_index as u32 ) {
90- if GDScriptNodeKind :: get_kind_from_ast_node ( child) == GDScriptNodeKind :: Identifier {
91- return get_node_text ( child, content) == expected_name;
92- }
93- }
94- child_index += 1 ;
95- }
96- false
97- }
98-
9979/// Slice the source string at a node's byte range.
10080/// Tree-sitter byte offsets are always on UTF-8 char boundaries.
10181fn get_node_text < ' a > ( node : Node < ' a > , content : & ' a str ) -> & ' a str {
@@ -496,11 +476,55 @@ fn classify_child<'a>(node: Node<'a>, content: &'a str) -> ChildClassification<'
496476}
497477
498478fn classify_variable < ' a > ( node : Node < ' a > , content : & ' a str ) -> ChildClassification < ' a > {
479+ fn get_annotation_identifier < ' a > ( annotation : Node < ' a > , content : & ' a str ) -> Option < & ' a str > {
480+ let child_count = annotation. child_count ( ) ;
481+ let mut child_index = 0 ;
482+ while child_index < child_count {
483+ if let Some ( child) = annotation. child ( child_index as u32 ) {
484+ if GDScriptNodeKind :: get_kind_from_ast_node ( child) == GDScriptNodeKind :: Identifier {
485+ return Some ( get_node_text ( child, content) ) ;
486+ }
487+ }
488+ child_index += 1 ;
489+ }
490+ None
491+ }
492+
499493 let name = extract_name ( node, content) . unwrap_or ( "unknown_var" ) ;
500494
501- if has_annotation_with_name ( node, content, "export" ) {
495+ let mut has_export_annotation = false ;
496+ let mut has_onready_annotation = false ;
497+ for child_index in 0 ..node. child_count ( ) {
498+ let Some ( child) = node. child ( child_index as u32 ) else {
499+ continue ;
500+ } ;
501+ if GDScriptNodeKind :: get_kind_from_ast_node ( child) != GDScriptNodeKind :: Annotations {
502+ continue ;
503+ }
504+
505+ for annotation_index in 0 ..child. child_count ( ) {
506+ let Some ( annotation) = child. child ( annotation_index as u32 ) else {
507+ continue ;
508+ } ;
509+ if GDScriptNodeKind :: get_kind_from_ast_node ( annotation) != GDScriptNodeKind :: Annotation
510+ {
511+ continue ;
512+ }
513+
514+ let Some ( annotation_name) = get_annotation_identifier ( annotation, content) else {
515+ continue ;
516+ } ;
517+ if annotation_name. starts_with ( "export" ) {
518+ has_export_annotation = true ;
519+ } else if annotation_name == "onready" {
520+ has_onready_annotation = true ;
521+ }
522+ }
523+ }
524+
525+ if has_export_annotation {
502526 ChildClassification :: new ( DeclarationKind :: ExportVariable , name)
503- } else if has_annotation_with_name ( node , content , "onready" ) {
527+ } else if has_onready_annotation {
504528 ChildClassification :: new ( DeclarationKind :: OnReadyVariable , name)
505529 } else if has_static_keyword_child ( node) {
506530 ChildClassification :: new ( DeclarationKind :: StaticVariable , name)
@@ -554,44 +578,6 @@ fn has_static_keyword_child(node: Node) -> bool {
554578 false
555579}
556580
557- /// Returns true if `node` has an `annotations` child containing an
558- /// `annotation` whose identifier matches `annotation_name`.
559- ///
560- /// This replaces fragile source-text checks like `text.contains("@export")`
561- /// which can falsely match comments or strings containing those substrings.
562- fn has_annotation_with_name ( node : Node , content : & str , annotation_name : & str ) -> bool {
563- let count = node. child_count ( ) ;
564- let mut child_index = 0 ;
565- while child_index < count {
566- if let Some ( child) = node. child ( child_index as u32 ) {
567- if GDScriptNodeKind :: get_kind_from_ast_node ( child) == GDScriptNodeKind :: Annotations
568- && annotations_contain_name ( child, content, annotation_name)
569- {
570- return true ;
571- }
572- }
573- child_index += 1 ;
574- }
575- false
576- }
577-
578- /// Walks the children of an `annotations` container node and checks whether
579- /// any `annotation` child has an `identifier` whose text matches `name`.
580- fn annotations_contain_name ( annotations_node : Node , content : & str , name : & str ) -> bool {
581- let count = annotations_node. child_count ( ) ;
582- let mut child_index = 0 ;
583- while child_index < count {
584- if let Some ( child) = annotations_node. child ( child_index as u32 ) {
585- if GDScriptNodeKind :: get_kind_from_ast_node ( child) == GDScriptNodeKind :: Annotation
586- && annotation_identifier_matches ( child, content, name)
587- {
588- return true ;
589- }
590- }
591- child_index += 1 ;
592- }
593- false
594- }
595581/// Maps built-in virtual method names to Godot lifecycle priority.
596582fn get_builtin_virtual_priority ( method_name : & str ) -> u8 {
597583 match method_name {
0 commit comments