Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
26 changes: 24 additions & 2 deletions lib/tapioca/dsl/compilers/action_controller_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,30 @@ def create_unknown_proxy_method(helper_methods, method_name)

#: (Module[top] mod) -> Array[String]
def gather_includes(mod)
mod.ancestors
.reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || name_of(ancestor).nil? }
ancestors = mod.ancestors

# Exclude modules that were prepended into another ancestor in the chain
# rather than explicitly included by the user. Otherwise, modules like
# `DEBUGGER__::TrapInterceptor` (prepended into `::Kernel` by the `debug`
# gem when loaded in-process by, e.g., the Ruby LSP Tapioca add-on) leak
# into generated RBIs.
prepended_into_ancestors = ancestors.each_with_object(Set.new) do |ancestor, set|
next unless ancestor.is_a?(Module)

ancestor.ancestors.each do |sub|
break if sub == ancestor

set << sub
end
end

ancestors
.reject do |ancestor|
ancestor.is_a?(Class) ||
ancestor == mod ||
name_of(ancestor).nil? ||
prepended_into_ancestors.include?(ancestor)
end
.map { |ancestor| T.must(qualified_name_of(ancestor)) }
.reverse
end
Expand Down
30 changes: 30 additions & 0 deletions spec/tapioca/dsl/compilers/action_controller_helpers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,36 @@ class HelperProxy < ::ActionView::Base
RBI
assert_equal expected, rbi_for(:UserController)
end

it "does not include modules prepended into an ancestor (e.g. debug.gem's TrapInterceptor)" do
# `debug/session` prepends `DEBUGGER__::TrapInterceptor` (and related
# modules) into `::Kernel`. The Ruby LSP Tapioca add-on loads
# `debug/session` in-process, so when it triggers DSL regeneration,
# modules prepended into `::Kernel` leak into any helper whose ancestor
# chain traverses `::Kernel`.
#
# These modules were not explicitly included by the user and should not
# appear in generated RBIs.
require "debug/session"

add_ruby_file("kernel_helper.rb", <<~RUBY)
module KernelHelper
include Kernel
end
RUBY

add_ruby_file("controller.rb", <<~RUBY)
class UserController < ActionController::Base
helper KernelHelper
helper_method :foo
def foo
"bar"
end
end
RUBY

refute_includes(rbi_for(:UserController), "DEBUGGER__")
end
end
end
end
Expand Down
Loading