@@ -361,34 +361,31 @@ impl<'a> RubyIndexer<'a> {
361361 } )
362362 }
363363
364- // Runs the given closure if the given call `node` is invoked directly on `self` for each one of its string or
365- // symbol arguments
364+ // Runs the given closure for each string or symbol argument in the given call `node`
366365 fn each_string_or_symbol_arg < F > ( node : & ruby_prism:: CallNode , mut f : F )
367366 where
368367 F : FnMut ( String , ruby_prism:: Location ) ,
369368 {
370- let receiver = node. receiver ( ) ;
369+ let Some ( arguments) = node. arguments ( ) else {
370+ return ;
371+ } ;
371372
372- if ( receiver. is_none ( ) || receiver. unwrap ( ) . as_self_node ( ) . is_some ( ) )
373- && let Some ( arguments) = node. arguments ( )
374- {
375- for argument in & arguments. arguments ( ) {
376- match argument {
377- ruby_prism:: Node :: SymbolNode { .. } => {
378- let symbol = argument. as_symbol_node ( ) . unwrap ( ) ;
379-
380- if let Some ( value_loc) = symbol. value_loc ( ) {
381- let name = Self :: location_to_string ( & value_loc) ;
382- f ( name, value_loc) ;
383- }
384- }
385- ruby_prism:: Node :: StringNode { .. } => {
386- let string = argument. as_string_node ( ) . unwrap ( ) ;
387- let name = String :: from_utf8_lossy ( string. unescaped ( ) ) . to_string ( ) ;
388- f ( name, argument. location ( ) ) ;
373+ for argument in & arguments. arguments ( ) {
374+ match argument {
375+ ruby_prism:: Node :: SymbolNode { .. } => {
376+ let symbol = argument. as_symbol_node ( ) . unwrap ( ) ;
377+
378+ if let Some ( value_loc) = symbol. value_loc ( ) {
379+ let name = Self :: location_to_string ( & value_loc) ;
380+ f ( name, value_loc) ;
389381 }
390- _ => { }
391382 }
383+ ruby_prism:: Node :: StringNode { .. } => {
384+ let string = argument. as_string_node ( ) . unwrap ( ) ;
385+ let name = String :: from_utf8_lossy ( string. unescaped ( ) ) . to_string ( ) ;
386+ f ( name, argument. location ( ) ) ;
387+ }
388+ _ => { }
392389 }
393390 }
394391 }
@@ -1104,11 +1101,22 @@ impl<'a> RubyIndexer<'a> {
11041101 return Some ( name_id) ;
11051102 }
11061103
1104+ let new_name_id = self . make_singleton_name_id ( name_id) ;
1105+
1106+ let location = receiver. map_or ( fallback_location, ruby_prism:: Node :: location) ;
1107+ let offset = Offset :: from_prism_location ( & location) ;
1108+ self . local_graph
1109+ . add_constant_reference ( ConstantReference :: new ( new_name_id, self . uri_id , offset) ) ;
1110+ Some ( new_name_id)
1111+ }
1112+
1113+ /// Creates a singleton class `NameId` (`<ClassName>`) attached to the given constant `NameId`.
1114+ fn make_singleton_name_id ( & mut self , attached_name_id : NameId ) -> NameId {
11071115 let singleton_class_name = {
11081116 let name = self
11091117 . local_graph
11101118 . names ( )
1111- . get ( & name_id )
1119+ . get ( & attached_name_id )
11121120 . expect ( "Indexed constant name should exist" ) ;
11131121
11141122 let target_str = self
@@ -1121,15 +1129,8 @@ impl<'a> RubyIndexer<'a> {
11211129 } ;
11221130
11231131 let string_id = self . local_graph . intern_string ( singleton_class_name) ;
1124- let new_name_id = self
1125- . local_graph
1126- . add_name ( Name :: new ( string_id, ParentScope :: Attached ( name_id) , None ) ) ;
1127-
1128- let location = receiver. map_or ( fallback_location, ruby_prism:: Node :: location) ;
1129- let offset = Offset :: from_prism_location ( & location) ;
11301132 self . local_graph
1131- . add_constant_reference ( ConstantReference :: new ( new_name_id, self . uri_id , offset) ) ;
1132- Some ( new_name_id)
1133+ . add_name ( Name :: new ( string_id, ParentScope :: Attached ( attached_name_id) , None ) )
11331134 }
11341135}
11351136
@@ -1540,6 +1541,11 @@ impl Visit<'_> for RubyIndexer<'_> {
15401541 }
15411542
15421543 let mut index_attr = |kind : AttrKind , call : & ruby_prism:: CallNode | {
1544+ let receiver = call. receiver ( ) ;
1545+ if receiver. as_ref ( ) . is_some_and ( |r| r. as_self_node ( ) . is_none ( ) ) {
1546+ return ;
1547+ }
1548+
15431549 let call_offset = Offset :: from_prism_location ( & call. location ( ) ) ;
15441550
15451551 Self :: each_string_or_symbol_arg ( call, |name, location| {
@@ -1653,8 +1659,22 @@ impl Visit<'_> for RubyIndexer<'_> {
16531659 let new_name_str_id = self . local_graph . intern_string ( format ! ( "{new_name}()" ) ) ;
16541660 let old_name_str_id = self . local_graph . intern_string ( format ! ( "{old_name}()" ) ) ;
16551661
1656- let method_receiver = self . method_receiver ( node. receiver ( ) . as_ref ( ) , node. location ( ) ) ;
1657- let reference = MethodRef :: new ( old_name_str_id, self . uri_id , old_offset. clone ( ) , method_receiver) ;
1662+ // Only constant receivers get a Receiver since self.alias_method is the same as bare alias_method
1663+ let recv_node = node. receiver ( ) ;
1664+ let receiver = recv_node. as_ref ( ) . and_then ( |recv_node| match recv_node {
1665+ ruby_prism:: Node :: ConstantPathNode { .. } | ruby_prism:: Node :: ConstantReadNode { .. } => self
1666+ . index_constant_reference ( recv_node, true )
1667+ . map ( Receiver :: ConstantReceiver ) ,
1668+ _ => None ,
1669+ } ) ;
1670+
1671+ // alias_method references instance methods, so we use the class NameId directly
1672+ let method_ref_receiver = match & receiver {
1673+ Some ( Receiver :: ConstantReceiver ( name_id) ) => Some ( * name_id) ,
1674+ Some ( Receiver :: SelfReceiver ( _) ) | None => self . method_receiver ( recv_node. as_ref ( ) , node. location ( ) ) ,
1675+ } ;
1676+
1677+ let reference = MethodRef :: new ( old_name_str_id, self . uri_id , old_offset. clone ( ) , method_ref_receiver) ;
16581678 self . local_graph . add_method_reference ( reference) ;
16591679
16601680 let offset = Offset :: from_prism_location ( & node. location ( ) ) ;
@@ -1668,6 +1688,7 @@ impl Visit<'_> for RubyIndexer<'_> {
16681688 comments,
16691689 flags,
16701690 self . current_nesting_definition_id ( ) ,
1691+ receiver,
16711692 ) ) ) ;
16721693
16731694 let definition_id = self . local_graph . add_definition ( definition) ;
@@ -1978,6 +1999,7 @@ impl Visit<'_> for RubyIndexer<'_> {
19781999 comments,
19792000 flags,
19802001 self . current_nesting_definition_id ( ) ,
2002+ None ,
19812003 ) ) ) ;
19822004
19832005 let definition_id = self . local_graph . add_definition ( definition) ;
@@ -4909,6 +4931,105 @@ mod tests {
49094931 } ) ;
49104932 }
49114933
4934+ #[ test]
4935+ fn index_alias_method_with_constant_receiver ( ) {
4936+ let context = index_source ( {
4937+ "
4938+ class Foo
4939+ def bar; end
4940+ end
4941+
4942+ Foo.alias_method :baz, :bar
4943+ "
4944+ } ) ;
4945+
4946+ assert_no_local_diagnostics ! ( & context) ;
4947+
4948+ assert_definition_at ! ( & context, "5:1-5:28" , MethodAlias , |def| {
4949+ let new_name = context. graph( ) . strings( ) . get( def. new_name_str_id( ) ) . unwrap( ) ;
4950+ let old_name = context. graph( ) . strings( ) . get( def. old_name_str_id( ) ) . unwrap( ) ;
4951+ assert_eq!( new_name. as_str( ) , "baz()" ) ;
4952+ assert_eq!( old_name. as_str( ) , "bar()" ) ;
4953+
4954+ match def. receiver( ) {
4955+ Some ( Receiver :: ConstantReceiver ( name_id) ) => {
4956+ let name = context. graph( ) . names( ) . get( name_id) . unwrap( ) ;
4957+ let actual_name = context. graph( ) . strings( ) . get( name. str ( ) ) . unwrap( ) . as_str( ) ;
4958+ assert_eq!( actual_name, "Foo" ) ;
4959+ }
4960+ other => panic!( "Expected ConstantReceiver, got {other:?}" ) ,
4961+ }
4962+ } ) ;
4963+
4964+ let method_ref = context
4965+ . graph ( )
4966+ . method_references ( )
4967+ . values ( )
4968+ . find ( |m| context. graph ( ) . strings ( ) . get ( m. str ( ) ) . unwrap ( ) . as_str ( ) == "bar()" )
4969+ . expect ( "should have a method reference for bar()" ) ;
4970+
4971+ let receiver = context. graph ( ) . names ( ) . get ( & method_ref. receiver ( ) . unwrap ( ) ) . unwrap ( ) ;
4972+ assert_eq ! ( context. graph( ) . strings( ) . get( receiver. str ( ) ) . unwrap( ) . as_str( ) , "Foo" ) ;
4973+ }
4974+
4975+ #[ test]
4976+ fn index_alias_method_with_constant_path_receiver ( ) {
4977+ let context = index_source ( {
4978+ "
4979+ module Outer
4980+ class Inner
4981+ def bar; end
4982+ end
4983+ end
4984+
4985+ Outer::Inner.alias_method :baz, :bar
4986+ "
4987+ } ) ;
4988+
4989+ assert_no_local_diagnostics ! ( & context) ;
4990+
4991+ assert_definition_at ! ( & context, "7:1-7:37" , MethodAlias , |def| {
4992+ let new_name = context. graph( ) . strings( ) . get( def. new_name_str_id( ) ) . unwrap( ) ;
4993+ let old_name = context. graph( ) . strings( ) . get( def. old_name_str_id( ) ) . unwrap( ) ;
4994+ assert_eq!( new_name. as_str( ) , "baz()" ) ;
4995+ assert_eq!( old_name. as_str( ) , "bar()" ) ;
4996+
4997+ match def. receiver( ) {
4998+ Some ( Receiver :: ConstantReceiver ( name_id) ) => {
4999+ let name = context. graph( ) . names( ) . get( name_id) . unwrap( ) ;
5000+ let actual_name = context. graph( ) . strings( ) . get( name. str ( ) ) . unwrap( ) . as_str( ) ;
5001+ assert_eq!( actual_name, "Inner" ) ;
5002+ }
5003+ other => panic!( "Expected ConstantReceiver, got {other:?}" ) ,
5004+ }
5005+ } ) ;
5006+ }
5007+
5008+ #[ test]
5009+ fn index_alias_method_with_self_receiver_has_no_receiver ( ) {
5010+ let context = index_source ( {
5011+ "
5012+ class Foo
5013+ self.alias_method :baz, :bar
5014+ end
5015+ "
5016+ } ) ;
5017+
5018+ assert_no_local_diagnostics ! ( & context) ;
5019+
5020+ assert_definition_at ! ( & context, "1:1-3:4" , Class , |foo_class_def| {
5021+ assert_definition_at!( & context, "2:3-2:31" , MethodAlias , |def| {
5022+ let new_name = context. graph( ) . strings( ) . get( def. new_name_str_id( ) ) . unwrap( ) ;
5023+ let old_name = context. graph( ) . strings( ) . get( def. old_name_str_id( ) ) . unwrap( ) ;
5024+ assert_eq!( new_name. as_str( ) , "baz()" ) ;
5025+ assert_eq!( old_name. as_str( ) , "bar()" ) ;
5026+
5027+ assert!( def. receiver( ) . is_none( ) ) ;
5028+ assert_eq!( foo_class_def. id( ) , def. lexical_nesting_id( ) . unwrap( ) ) ;
5029+ } ) ;
5030+ } ) ;
5031+ }
5032+
49125033 #[ test]
49135034 fn index_alias_global_variables ( ) {
49145035 let context = index_source ( {
0 commit comments