Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for class_methods do blocks within concerns #530

Merged
merged 10 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ platforms :mingw, :x64_mingw, :mswin, :jruby do
gem "tzinfo"
gem "tzinfo-data"
end

gem "ruby-lsp", github: "Shopify/ruby-lsp", branch: "11-14-allow_indexing_enhancements_to_create_namespaces"
17 changes: 12 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
GIT
remote: https://github.com/Shopify/ruby-lsp.git
revision: bb3a5b25da4ba2931278fdeb1f0fbdf40b8545c3
branch: 11-14-allow_indexing_enhancements_to_create_namespaces
specs:
ruby-lsp (0.21.4)
language_server-protocol (~> 3.17.0)
prism (>= 1.2, < 2.0)
rbs (>= 3, < 4)
sorbet-runtime (>= 0.5.10782)

PATH
remote: .
specs:
Expand Down Expand Up @@ -214,11 +225,6 @@ GEM
rubocop (~> 1.51)
rubocop-sorbet (0.8.7)
rubocop (>= 1)
ruby-lsp (0.21.2)
language_server-protocol (~> 3.17.0)
prism (>= 1.2, < 2.0)
rbs (>= 3, < 4)
sorbet-runtime (>= 0.5.10782)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
securerandom (0.3.1)
Expand Down Expand Up @@ -283,6 +289,7 @@ DEPENDENCIES
rubocop-rake (~> 0.6.0)
rubocop-shopify (~> 2.15)
rubocop-sorbet (~> 0.8)
ruby-lsp!
ruby-lsp-rails!
sorbet-static-and-runtime
sqlite3
Expand Down
1 change: 0 additions & 1 deletion lib/ruby_lsp/ruby_lsp_rails/addon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ def activate(global_state, outgoing_queue)
@outgoing_queue << Notification.window_log_message("Activating Ruby LSP Rails add-on v#{VERSION}")

register_additional_file_watchers(global_state: global_state, outgoing_queue: outgoing_queue)
@global_state.index.register_enhancement(IndexingEnhancement.new(@global_state.index))

# Start booting the real client in a background thread. Until this completes, the client will be a NullClient
@client_mutex.unlock
Expand Down
99 changes: 48 additions & 51 deletions lib/ruby_lsp/ruby_lsp_rails/indexing_enhancement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,41 @@ module Rails
class IndexingEnhancement < RubyIndexer::Enhancement
extend T::Sig

sig { params(listener: RubyIndexer::DeclarationListener).void }
def initialize(listener)
super
# We need this to prevent Sorbet from complaining that @listener is undeclared
@listener = listener
end
andyw8 marked this conversation as resolved.
Show resolved Hide resolved

sig do
override.params(
owner: T.nilable(RubyIndexer::Entry::Namespace),
node: Prism::CallNode,
file_path: String,
code_units_cache: T.any(
T.proc.params(arg0: Integer).returns(Integer),
Prism::CodeUnitsCache,
),
call_node: Prism::CallNode,
).void
end
def on_call_node_enter(owner, node, file_path, code_units_cache)
def on_call_node_enter(call_node)
owner = @listener.current_owner
return unless owner

name = node.name

case name
case call_node.name
when :extend
handle_concern_extend(owner, node)
handle_concern_extend(owner, call_node)
when :has_one, :has_many, :belongs_to, :has_and_belongs_to_many
handle_association(owner, node, file_path, code_units_cache)
handle_association(owner, call_node)
# for `class_methods do` blocks within concerns
when :class_methods
handle_class_methods(owner, call_node)
end
end

sig do
override.params(
call_node: Prism::CallNode,
).void
end
def on_call_node_leave(call_node)
if call_node.name == :class_methods && call_node.block
@listener.pop_namespace_stack
end
end

Expand All @@ -35,16 +49,11 @@ def on_call_node_enter(owner, node, file_path, code_units_cache)
sig do
params(
owner: RubyIndexer::Entry::Namespace,
node: Prism::CallNode,
file_path: String,
code_units_cache: T.any(
T.proc.params(arg0: Integer).returns(Integer),
Prism::CodeUnitsCache,
),
call_node: Prism::CallNode,
).void
end
def handle_association(owner, node, file_path, code_units_cache)
arguments = node.arguments&.arguments
def handle_association(owner, call_node)
arguments = call_node.arguments&.arguments
return unless arguments

name_arg = arguments.first
Expand All @@ -58,41 +67,22 @@ def handle_association(owner, node, file_path, code_units_cache)

return unless name

loc = RubyIndexer::Location.from_prism_location(name_arg.location, code_units_cache)
loc = name_arg.location

# Reader
@index.add(RubyIndexer::Entry::Method.new(
name,
file_path,
loc,
loc,
nil,
[RubyIndexer::Entry::Signature.new([])],
RubyIndexer::Entry::Visibility::PUBLIC,
owner,
))
reader_signatures = [RubyIndexer::Entry::Signature.new([])]
@listener.add_method(name, loc, reader_signatures)

# Writer
@index.add(RubyIndexer::Entry::Method.new(
"#{name}=",
file_path,
loc,
loc,
nil,
[RubyIndexer::Entry::Signature.new([RubyIndexer::Entry::RequiredParameter.new(name: name.to_sym)])],
RubyIndexer::Entry::Visibility::PUBLIC,
owner,
))
writer_signatures = [
RubyIndexer::Entry::Signature.new([RubyIndexer::Entry::RequiredParameter.new(name: name.to_sym)]),
]
@listener.add_method("#{name}=", loc, writer_signatures)
end

sig do
params(
owner: RubyIndexer::Entry::Namespace,
node: Prism::CallNode,
).void
end
def handle_concern_extend(owner, node)
arguments = node.arguments&.arguments
sig { params(owner: RubyIndexer::Entry::Namespace, call_node: Prism::CallNode).void }
def handle_concern_extend(owner, call_node)
arguments = call_node.arguments&.arguments
return unless arguments

arguments.each do |node|
Expand All @@ -101,7 +91,7 @@ def handle_concern_extend(owner, node)
module_name = node.full_name
next unless module_name == "ActiveSupport::Concern"

@index.register_included_hook(owner.name) do |index, base|
@listener.register_included_hook do |index, base|
class_methods_name = "#{owner.name}::ClassMethods"

if index.indexed?(class_methods_name)
Expand All @@ -114,6 +104,13 @@ def handle_concern_extend(owner, node)
# Do nothing
end
end

sig { params(owner: RubyIndexer::Entry::Namespace, call_node: Prism::CallNode).void }
def handle_class_methods(owner, call_node)
graphite-app[bot] marked this conversation as resolved.
Show resolved Hide resolved
return unless call_node.block

graphite-app[bot] marked this conversation as resolved.
Show resolved Hide resolved
@listener.add_module("ClassMethods", call_node.location, call_node.location)
graphite-app[bot] marked this conversation as resolved.
Show resolved Hide resolved
end
end
end
end
Loading
Loading