@@ -4,7 +4,7 @@ use syntax::ast::{
44 Annotation , Expression , ImportAlias , Pattern , SelectArm , SelectArmPattern , StructSpread ,
55} ;
66use syntax:: program:: File ;
7- use syntax:: program:: { DefinitionBody , Module } ;
7+ use syntax:: program:: { DefinitionBody , DotAccessKind , Module } ;
88use syntax:: types:: { Symbol , Type , unqualified_name} ;
99
1010use super :: reference_graph:: { EnumVariantId , ModuleItemId , ReferenceGraph , StructFieldId } ;
@@ -38,6 +38,10 @@ impl AliasMap {
3838 }
3939 self . aliases . get ( name) . cloned ( )
4040 }
41+
42+ fn is_import_alias ( & self , name : & str ) -> bool {
43+ self . aliases . contains_key ( name)
44+ }
4145}
4246
4347pub fn extract_references (
@@ -83,18 +87,20 @@ fn walk_expression(
8387 }
8488
8589 Expression :: DotAccess {
86- expression, member, ..
90+ expression,
91+ member,
92+ dot_access_kind,
93+ ..
8794 } => {
8895 walk_expression ( module, expression, graph, alias_map, ctx) ;
8996 if let Some ( ty_name) = type_name ( & expression. get_type ( ) ) {
9097 graph. mark_struct_field_used ( StructFieldId :: new ( & ty_name, member) ) ;
9198 }
92- // Also track method references: when calling Type.method() or instance.method(),
93- // add a reference to the method if it exists in the module.
94- // The add_reference is a no-op if the target doesn't exist.
95- if let Some ( from) = ctx {
96- let method_id = ModuleItemId :: new ( member) ;
97- graph. add_reference ( from, method_id) ;
99+ if let Some ( from) = ctx
100+ && is_method_access ( dot_access_kind)
101+ && credits_local_method ( & expression. get_type ( ) , module)
102+ {
103+ graph. add_reference ( from, ModuleItemId :: new ( member) ) ;
98104 }
99105 }
100106
@@ -513,19 +519,7 @@ fn walk_pattern(
513519 ty,
514520 ..
515521 } => {
516- let variant_name = unqualified_name ( identifier) ;
517-
518- let enum_name = type_name ( ty) . or_else ( || {
519- let mut segments = identifier. split ( '.' ) ;
520- let first = segments. next ( ) . unwrap_or ( "" ) ;
521- segments. next ( ) . is_some ( ) . then ( || first. to_string ( ) )
522- } ) ;
523-
524- if let Some ( ref enum_name) = enum_name {
525- add_ref ( graph, ctx, alias_map, module, enum_name) ;
526- graph. mark_enum_variant_used ( EnumVariantId :: new ( enum_name, variant_name) ) ;
527- }
528-
522+ mark_constructor_pattern ( module, identifier, ty, graph, alias_map, ctx) ;
529523 for f in fields {
530524 walk_pattern ( module, f, graph, alias_map, ctx) ;
531525 }
@@ -536,17 +530,7 @@ fn walk_pattern(
536530 ty,
537531 ..
538532 } => {
539- add_ref ( graph, ctx, alias_map, module, identifier) ;
540- // Mark enum variant as used for struct variant patterns (e.g., Enum.Variant { ... })
541- let variant_name = unqualified_name ( identifier) ;
542- let enum_name = type_name ( ty) . or_else ( || {
543- let mut segments = identifier. split ( '.' ) ;
544- let first = segments. next ( ) . unwrap_or ( "" ) ;
545- segments. next ( ) . is_some ( ) . then ( || first. to_string ( ) )
546- } ) ;
547- if let Some ( ref enum_name) = enum_name {
548- graph. mark_enum_variant_used ( EnumVariantId :: new ( enum_name, variant_name) ) ;
549- }
533+ mark_constructor_pattern ( module, identifier, ty, graph, alias_map, ctx) ;
550534 for f in fields {
551535 walk_pattern ( module, & f. value , graph, alias_map, ctx) ;
552536 graph. mark_struct_field_used ( StructFieldId :: new ( identifier, & f. name ) ) ;
@@ -693,6 +677,58 @@ fn add_ref(
693677 }
694678}
695679
680+ fn mark_constructor_pattern (
681+ module : & Module ,
682+ identifier : & str ,
683+ ty : & Type ,
684+ graph : & mut ReferenceGraph ,
685+ alias_map : & AliasMap ,
686+ ctx : Option < & ModuleItemId > ,
687+ ) {
688+ if let Some ( ( alias, _) ) = identifier. split_once ( '.' )
689+ && alias_map. is_import_alias ( alias)
690+ {
691+ add_ref ( graph, ctx, alias_map, module, alias) ;
692+ return ;
693+ }
694+
695+ let enum_name = type_name ( ty) . or_else ( || {
696+ identifier
697+ . split_once ( '.' )
698+ . map ( |( first, _) | first. to_string ( ) )
699+ } ) ;
700+ if let Some ( enum_name) = enum_name {
701+ add_ref ( graph, ctx, alias_map, module, & enum_name) ;
702+ graph. mark_enum_variant_used ( EnumVariantId :: new ( & enum_name, unqualified_name ( identifier) ) ) ;
703+ }
704+ }
705+
706+ fn is_method_access ( kind : & Option < DotAccessKind > ) -> bool {
707+ matches ! (
708+ kind,
709+ Some (
710+ DotAccessKind :: InstanceMethod { .. }
711+ | DotAccessKind :: InstanceMethodValue { .. }
712+ | DotAccessKind :: StaticMethod { .. }
713+ )
714+ )
715+ }
716+
717+ fn credits_local_method ( receiver_ty : & Type , module : & Module ) -> bool {
718+ let mut current = receiver_ty. strip_refs ( ) ;
719+ while let Some ( next) = current. get_underlying ( ) . cloned ( ) {
720+ current = next;
721+ }
722+ current = match current {
723+ Type :: Function ( f) => ( * f. return_type ) . clone ( ) ,
724+ other => other,
725+ } ;
726+ match current {
727+ Type :: Nominal { id, .. } => id. as_str ( ) . starts_with ( & format ! ( "{}." , module. id) ) ,
728+ _ => false ,
729+ }
730+ }
731+
696732fn type_name ( ty : & Type ) -> Option < String > {
697733 let mut current = ty. strip_refs ( ) ;
698734 while let Some ( next) = current. get_underlying ( ) . cloned ( ) {
0 commit comments