@@ -274,6 +274,7 @@ impl<'a> Resolver<'a> {
274274 #[ allow( clippy:: too_many_lines) ]
275275 fn handle_remaining_definitions ( & mut self , other_ids : Vec < DefinitionId > ) {
276276 let mut method_visibility_ids = Vec :: new ( ) ;
277+ let mut singleton_method_visibility_ids = Vec :: new ( ) ;
277278
278279 for id in other_ids {
279280 match self . graph . definitions ( ) . get ( & id) . unwrap ( ) {
@@ -607,7 +608,9 @@ impl<'a> Resolver<'a> {
607608 Definition :: MethodVisibility ( _) => {
608609 method_visibility_ids. push ( id) ;
609610 }
610- Definition :: SingletonMethodVisibility ( _) => { }
611+ Definition :: SingletonMethodVisibility ( _) => {
612+ singleton_method_visibility_ids. push ( id) ;
613+ }
611614 Definition :: Class ( _)
612615 | Definition :: SingletonClass ( _)
613616 | Definition :: Module ( _)
@@ -619,6 +622,98 @@ impl<'a> Resolver<'a> {
619622 }
620623
621624 self . resolve_method_visibilities ( method_visibility_ids) ;
625+ self . resolve_singleton_method_visibilities ( singleton_method_visibility_ids) ;
626+ }
627+
628+ /// Resolves `private_class_method` / `public_class_method` calls
629+ fn resolve_singleton_method_visibilities ( & mut self , visibility_ids : Vec < DefinitionId > ) {
630+ let mut pending_work = Vec :: new ( ) ;
631+
632+ for id in visibility_ids {
633+ let Definition :: SingletonMethodVisibility ( singleton_visibility) =
634+ self . graph . definitions ( ) . get ( & id) . unwrap ( )
635+ else {
636+ unreachable ! ( )
637+ } ;
638+
639+ let str_id = * singleton_visibility. target ( ) ;
640+ let uri_id = * singleton_visibility. uri_id ( ) ;
641+ let offset = singleton_visibility. offset ( ) . clone ( ) ;
642+ let lexical_nesting_id = * singleton_visibility. lexical_nesting_id ( ) ;
643+ let receiver = * singleton_visibility. receiver ( ) ;
644+
645+ let attached_namespace_id = if let Some ( receiver_name_id) = receiver {
646+ let NameRef :: Resolved ( resolved) = self . graph . names ( ) . get ( & receiver_name_id) . unwrap ( ) else {
647+ pending_work. push ( Unit :: Definition ( id) ) ;
648+ continue ;
649+ } ;
650+ let Some ( namespace_id) = self . resolve_to_namespace ( * resolved. declaration_id ( ) ) else {
651+ continue ;
652+ } ;
653+ namespace_id
654+ } else {
655+ let Some ( decl_id) = self . resolve_lexical_owner ( lexical_nesting_id, id) else {
656+ continue ;
657+ } ;
658+ decl_id
659+ } ;
660+
661+ let Some ( singleton_id) = self . get_or_create_singleton_class ( attached_namespace_id, true ) else {
662+ continue ;
663+ } ;
664+
665+ let Some ( Declaration :: Namespace ( namespace) ) = self . graph . declarations ( ) . get ( & singleton_id) else {
666+ continue ;
667+ } ;
668+
669+ let mut visibility_applied = false ;
670+ let mut has_partial = false ;
671+
672+ let ancestor_ids: Vec < Ancestor > = namespace. ancestors ( ) . iter ( ) . copied ( ) . collect ( ) ;
673+
674+ for ancestor in ancestor_ids {
675+ match ancestor {
676+ Ancestor :: Complete ( ancestor_id) => {
677+ let has_member = self
678+ . graph
679+ . declarations ( )
680+ . get ( & ancestor_id)
681+ . and_then ( |decl| decl. as_namespace ( ) )
682+ . and_then ( |ns| ns. member ( & str_id) )
683+ . is_some ( ) ;
684+
685+ if has_member {
686+ self . create_declaration ( str_id, id, singleton_id, |name| {
687+ Declaration :: Method ( Box :: new ( MethodDeclaration :: new ( name, singleton_id) ) )
688+ } ) ;
689+ visibility_applied = true ;
690+ break ;
691+ }
692+ }
693+ Ancestor :: Partial ( _) => has_partial = true ,
694+ }
695+ }
696+
697+ if visibility_applied {
698+ continue ;
699+ }
700+
701+ if has_partial {
702+ pending_work. push ( Unit :: Definition ( id) ) ;
703+ } else {
704+ let method_name = self . graph . strings ( ) . get ( & str_id) . unwrap ( ) . as_str ( ) . to_string ( ) ;
705+ let owner_name = self . graph . declarations ( ) . get ( & singleton_id) . unwrap ( ) . name ( ) . to_string ( ) ;
706+ let diagnostic = Diagnostic :: new (
707+ Rule :: UndefinedSingletonMethodVisibilityTarget ,
708+ uri_id,
709+ offset,
710+ format ! ( "undefined singleton method `{method_name}` for visibility change in `{owner_name}`" ) ,
711+ ) ;
712+ self . graph . add_document_diagnostic ( uri_id, diagnostic) ;
713+ }
714+ }
715+
716+ self . graph . extend_work ( pending_work) ;
622717 }
623718
624719 /// Resolves retroactive method visibility changes (`private :foo`, `protected :foo`, `public :foo`).
0 commit comments