@@ -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 . create_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 create_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,23 @@ 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+ let receiver_node = node. receiver ( ) ;
1663+ let receiver = receiver_node. as_ref ( ) . and_then ( |node| match node {
1664+ ruby_prism:: Node :: ConstantPathNode { .. } | ruby_prism:: Node :: ConstantReadNode { .. } => self
1665+ . index_constant_reference ( node, true )
1666+ . map ( Receiver :: ConstantReceiver ) ,
1667+ _ => None ,
1668+ } ) ;
1669+
1670+ // alias_method references instance methods, so we use the class NameId directly
1671+ let method_ref_receiver = match & receiver {
1672+ Some ( Receiver :: ConstantReceiver ( name_id) ) => Some ( * name_id) ,
1673+ Some ( Receiver :: SelfReceiver ( _) ) | None => {
1674+ self . method_receiver ( receiver_node. as_ref ( ) , node. location ( ) )
1675+ }
1676+ } ;
1677+
1678+ let reference = MethodRef :: new ( old_name_str_id, self . uri_id , old_offset. clone ( ) , method_ref_receiver) ;
16581679 self . local_graph . add_method_reference ( reference) ;
16591680
16601681 let offset = Offset :: from_prism_location ( & node. location ( ) ) ;
@@ -1668,6 +1689,7 @@ impl Visit<'_> for RubyIndexer<'_> {
16681689 comments,
16691690 flags,
16701691 self . current_nesting_definition_id ( ) ,
1692+ receiver,
16711693 ) ) ) ;
16721694
16731695 let definition_id = self . local_graph . add_definition ( definition) ;
@@ -1978,6 +2000,7 @@ impl Visit<'_> for RubyIndexer<'_> {
19782000 comments,
19792001 flags,
19802002 self . current_nesting_definition_id ( ) ,
2003+ None ,
19812004 ) ) ) ;
19822005
19832006 let definition_id = self . local_graph . add_definition ( definition) ;
@@ -4909,6 +4932,105 @@ mod tests {
49094932 } ) ;
49104933 }
49114934
4935+ #[ test]
4936+ fn index_alias_method_with_constant_receiver ( ) {
4937+ let context = index_source ( {
4938+ "
4939+ class Foo
4940+ def bar; end
4941+ end
4942+
4943+ Foo.alias_method :baz, :bar
4944+ "
4945+ } ) ;
4946+
4947+ assert_no_local_diagnostics ! ( & context) ;
4948+
4949+ assert_definition_at ! ( & context, "5:1-5:28" , MethodAlias , |def| {
4950+ let new_name = context. graph( ) . strings( ) . get( def. new_name_str_id( ) ) . unwrap( ) ;
4951+ let old_name = context. graph( ) . strings( ) . get( def. old_name_str_id( ) ) . unwrap( ) ;
4952+ assert_eq!( new_name. as_str( ) , "baz()" ) ;
4953+ assert_eq!( old_name. as_str( ) , "bar()" ) ;
4954+
4955+ match def. receiver( ) {
4956+ Some ( Receiver :: ConstantReceiver ( name_id) ) => {
4957+ let name = context. graph( ) . names( ) . get( name_id) . unwrap( ) ;
4958+ let actual_name = context. graph( ) . strings( ) . get( name. str ( ) ) . unwrap( ) . as_str( ) ;
4959+ assert_eq!( actual_name, "Foo" ) ;
4960+ }
4961+ other => panic!( "Expected ConstantReceiver, got {other:?}" ) ,
4962+ }
4963+ } ) ;
4964+
4965+ let method_ref = context
4966+ . graph ( )
4967+ . method_references ( )
4968+ . values ( )
4969+ . find ( |m| context. graph ( ) . strings ( ) . get ( m. str ( ) ) . unwrap ( ) . as_str ( ) == "bar()" )
4970+ . expect ( "should have a method reference for bar()" ) ;
4971+
4972+ let receiver = context. graph ( ) . names ( ) . get ( & method_ref. receiver ( ) . unwrap ( ) ) . unwrap ( ) ;
4973+ assert_eq ! ( context. graph( ) . strings( ) . get( receiver. str ( ) ) . unwrap( ) . as_str( ) , "Foo" ) ;
4974+ }
4975+
4976+ #[ test]
4977+ fn index_alias_method_with_constant_path_receiver ( ) {
4978+ let context = index_source ( {
4979+ "
4980+ module Outer
4981+ class Inner
4982+ def bar; end
4983+ end
4984+ end
4985+
4986+ Outer::Inner.alias_method :baz, :bar
4987+ "
4988+ } ) ;
4989+
4990+ assert_no_local_diagnostics ! ( & context) ;
4991+
4992+ assert_definition_at ! ( & context, "7:1-7:37" , MethodAlias , |def| {
4993+ let new_name = context. graph( ) . strings( ) . get( def. new_name_str_id( ) ) . unwrap( ) ;
4994+ let old_name = context. graph( ) . strings( ) . get( def. old_name_str_id( ) ) . unwrap( ) ;
4995+ assert_eq!( new_name. as_str( ) , "baz()" ) ;
4996+ assert_eq!( old_name. as_str( ) , "bar()" ) ;
4997+
4998+ match def. receiver( ) {
4999+ Some ( Receiver :: ConstantReceiver ( name_id) ) => {
5000+ let name = context. graph( ) . names( ) . get( name_id) . unwrap( ) ;
5001+ let actual_name = context. graph( ) . strings( ) . get( name. str ( ) ) . unwrap( ) . as_str( ) ;
5002+ assert_eq!( actual_name, "Inner" ) ;
5003+ }
5004+ other => panic!( "Expected ConstantReceiver, got {other:?}" ) ,
5005+ }
5006+ } ) ;
5007+ }
5008+
5009+ #[ test]
5010+ fn index_alias_method_with_self_receiver_has_no_receiver ( ) {
5011+ let context = index_source ( {
5012+ "
5013+ class Foo
5014+ self.alias_method :baz, :bar
5015+ end
5016+ "
5017+ } ) ;
5018+
5019+ assert_no_local_diagnostics ! ( & context) ;
5020+
5021+ assert_definition_at ! ( & context, "1:1-3:4" , Class , |foo_class_def| {
5022+ assert_definition_at!( & context, "2:3-2:31" , MethodAlias , |def| {
5023+ let new_name = context. graph( ) . strings( ) . get( def. new_name_str_id( ) ) . unwrap( ) ;
5024+ let old_name = context. graph( ) . strings( ) . get( def. old_name_str_id( ) ) . unwrap( ) ;
5025+ assert_eq!( new_name. as_str( ) , "baz()" ) ;
5026+ assert_eq!( old_name. as_str( ) , "bar()" ) ;
5027+
5028+ assert!( def. receiver( ) . is_none( ) ) ;
5029+ assert_eq!( foo_class_def. id( ) , def. lexical_nesting_id( ) . unwrap( ) ) ;
5030+ } ) ;
5031+ } ) ;
5032+ }
5033+
49125034 #[ test]
49135035 fn index_alias_global_variables ( ) {
49145036 let context = index_source ( {
0 commit comments