From 9f5fdd31da5a7f43c85b463dde0fe83774f7f4c4 Mon Sep 17 00:00:00 2001 From: James Coleman Date: Thu, 7 Apr 2022 14:51:38 -0400 Subject: Weird method location shouldn't match unknown location Methods that don't have a source location (e.g., C methods, or methods created via metaprogramming or even `alias_method` to C methods) are not reasonable possible matching methods for a "weird method" we need to locate. In this case `renamed_method_source_location` can also return `nil` if the actual code in question is a bare script (i.e., no methods). If that script is loaded via `eval` then we'll end up in the weird method path in the first place, but no method matching can be found, and if a no-source-location method exists, we'll return that. Down the line that's particularly painful because the source loading thinks it's a C method, but it can actually be from metaprogramming (and `alias_method`!), and then `Pry::Method#pry_doc_info` raises an error, and `wherami` breaks even though we already have valid `__FILE__` and `__LINE__` values. --- spec/fixtures/test_task.rb | 3 +++ spec/method_spec.rb | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 spec/fixtures/test_task.rb (limited to 'spec') diff --git a/spec/fixtures/test_task.rb b/spec/fixtures/test_task.rb new file mode 100644 index 00000000..dfa86941 --- /dev/null +++ b/spec/fixtures/test_task.rb @@ -0,0 +1,3 @@ +task :test_task do + binding +end diff --git a/spec/method_spec.rb b/spec/method_spec.rb index 95ac075c..8f06c484 100644 --- a/spec/method_spec.rb +++ b/spec/method_spec.rb @@ -208,6 +208,44 @@ describe Pry::Method do m = Pry::Method.from_binding(o.borscht) expect(m.source).to eq Pry::Method(o.method(:paella)).source end + + it 'should not find a wrong method by matching on nil source location' do + included_module = Module.new do + def self.included(base) + base.send :alias_method, "respond_to_without_variables?", "respond_to?" + base.send :alias_method, "respond_to?", "respond_to_with_variables?" + end + + def respond_to_with_variables?(sym, include_priv=false) + respond_to_without_variables?(sym, include_priv) + end + end + + o = Object.new + class << o + attr_reader :tasks + def task(name, &block) + @tasks ||= {} + @tasks[name] = block + end + + def load + path = File.expand_path("../fixtures/test_task.rb", __FILE__) + instance_eval File.read(path), path + end + end + + o.load + + o2 = Object.new + o2.singleton_class.send(:include, included_module) + + # Verify preconditions. + expect(o2.method(:respond_to_without_variables?).source_location).to be_nil + + b = o2.instance_eval(&o.tasks[:test_task]) + expect(Pry::Method.from_binding(b).name).to eq "load" + end end describe 'super' do -- cgit v1.2.1