From a2dbacb8125622214c4846288c88c402af36b619 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Wed, 7 Dec 2022 22:53:51 -0800 Subject: [PATCH] Process non-self singleton classes (#581) --- .../rubyvm/node_processors/sclass_node.rb | 17 +++++++-- spec/api_map_spec.rb | 38 +++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb b/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb index f4445a6e8..8f3fdf0aa 100644 --- a/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +++ b/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb @@ -6,11 +6,22 @@ module Rubyvm module NodeProcessors class SclassNode < Parser::NodeProcessor::Base def process - # @todo Temporarily skipping remote metaclasses - return unless node.children[0].is_a?(RubyVM::AbstractSyntaxTree::Node) && node.children[0].type == :SELF + sclass = node.children[0] + if sclass.is_a?(RubyVM::AbstractSyntaxTree::Node) && sclass.type == :SELF + closure = region.closure + elsif sclass.is_a?(RubyVM::AbstractSyntaxTree::Node) && %i[CDECL CONST].include?(sclass.type) + names = [region.closure.namespace, region.closure.name] + if names.last != sclass.children[0].to_s + names << sclass.children[0].to_s + end + name = names.reject(&:empty?).join('::') + closure = Solargraph::Pin::Namespace.new(name: name, location: region.closure.location) + else + return + end pins.push Solargraph::Pin::Singleton.new( location: get_node_location(node), - closure: region.closure + closure: closure ) process_children region.update(visibility: :public, scope: :class, closure: pins.last) end diff --git a/spec/api_map_spec.rb b/spec/api_map_spec.rb index c34bcd233..a0150718e 100755 --- a/spec/api_map_spec.rb +++ b/spec/api_map_spec.rb @@ -684,6 +684,44 @@ class << self expect(pins.map(&:name)).to include('foo') end + it 'finds class methods in class << Example' do + source = Solargraph::Source.load_string(%( + class << Example = Class.new + def foo; end + end + class Example + class << Example + def bar; end + end + end + )) + @api_map.map source + pins = @api_map.get_methods('Example', scope: :class).select do |pin| + pin.namespace == 'Example' + end + expect(pins.map(&:name).sort).to eq(['bar', 'foo']) + end + + it 'finds class methods in nested class << Example' do + source = Solargraph::Source.load_string(%( + module Container + class << Example = Class.new + def foo; end + end + class Example + class << Example + def bar; end + end + end + end + )) + @api_map.map source + pins = @api_map.get_methods('Container::Example', scope: :class).select do |pin| + pin.namespace == 'Container::Example' + end + expect(pins.map(&:name).sort).to eq(['bar', 'foo']) + end + it 'resolves aliases for YARD methods' do dir = File.absolute_path(File.join('spec', 'fixtures', 'yard_map')) yard_pins = Dir.chdir dir do