From 2d6e58da01ef09276291b358e4a0490d10b08b4e Mon Sep 17 00:00:00 2001 From: Vinicius Stock Date: Mon, 2 Mar 2026 14:02:14 -0500 Subject: [PATCH] Avoid creating singleton classes for non-namespace targets --- rust/rubydex/src/resolution.rs | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/rust/rubydex/src/resolution.rs b/rust/rubydex/src/resolution.rs index 2f9b3fcb..e2b9b55b 100644 --- a/rust/rubydex/src/resolution.rs +++ b/rust/rubydex/src/resolution.rs @@ -1011,6 +1011,13 @@ impl<'a> Resolver<'a> { let owner = self.graph.declarations().get(&owner_id).unwrap(); let owner_is_namespace = owner.as_namespace().is_some(); + // Skip creating singletons when the target is a not a namespace or not promotable. For example: + // Foo = 1 + // class << Foo; end + if singleton && !owner_is_namespace { + return Outcome::Unresolved(None); + } + // We don't prefix declarations with `Object::` if owner_id != *OBJECT_ID { fully_qualified_name.insert_str(0, "::"); @@ -5151,4 +5158,41 @@ mod tests { assert_declaration_kind_eq!(context, "Foo::Bar", "Module"); assert_declaration_kind_eq!(context, "Foo::Bar::Baz", "Constant"); } + + #[test] + fn singleton_class_block_for_promotable_constant() { + let mut context = GraphTest::new(); + context.index_uri("file:///a.rb", { + r" + Foo = dynamic + + class << Foo + def bar; end + end + " + }); + + context.resolve(); + assert_declaration_kind_eq!(context, "Foo", "Module"); + assert_declaration_exists!(context, "Foo::#bar()"); + } + + #[test] + fn singleton_class_block_for_non_promotable_constant() { + let mut context = GraphTest::new(); + context.index_uri("file:///a.rb", { + r" + Foo = 1 + + class << Foo + def bar; end + end + " + }); + + context.resolve(); + assert_declaration_kind_eq!(context, "Foo", "Constant"); + assert_declaration_does_not_exist!(context, "Foo::"); + assert_declaration_does_not_exist!(context, "Foo::#bar()"); + } }