From 783c52a4a956266ff62f333bf1d9eba3f610285d Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 1 Jul 2022 00:01:49 +0900 Subject: [PATCH] support BasicObject fix #624 --- lib/debug/frame_info.rb | 6 +++++- lib/debug/server_dap.rb | 18 ++++++++++-------- lib/debug/session.rb | 9 +++++++++ lib/debug/thread_client.rb | 38 +++++++++++++++++++++++++++----------- lib/debug/tracer.rb | 2 +- 5 files changed, 52 insertions(+), 21 deletions(-) diff --git a/lib/debug/frame_info.rb b/lib/debug/frame_info.rb index b77333031..632a83bd1 100644 --- a/lib/debug/frame_info.rb +++ b/lib/debug/frame_info.rb @@ -102,7 +102,11 @@ def other_identifier end def callee - self._callee ||= self.binding&.eval('__callee__') + self._callee ||= begin + self.binding&.eval('__callee__') + rescue NameError # BasicObject + nil + end end def return_str diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 1651a65f2..a83bed5c7 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -718,10 +718,10 @@ def process_dap args ] end - vars += obj.instance_variables.map{|iv| - variable(iv, obj.instance_variable_get(iv)) + vars += M_INSTANCE_VARIABLES.bind_call(obj).map{|iv| + variable(iv, M_INSTANCE_VARIABLE_GET.bind_call(obj, iv)) } - vars.unshift variable('#class', obj.class) + vars.unshift variable('#class', M_CLASS.bind_call(obj)) end end event! :dap_result, :variable, req, variables: (vars || []), tid: self.id @@ -748,7 +748,7 @@ def process_dap args case expr when /\A\@\S/ begin - result = b.receiver.instance_variable_get(expr) + result = M_INSTANCE_VARIABLE_GET.bind_call(b.receiver, expr) rescue NameError message = "Error: Not defined instance variable: #{expr.inspect}" end @@ -759,6 +759,8 @@ def process_dap args break false end } and (message = "Error: Not defined global variable: #{expr.inspect}") + when /\Aself$/ + result = b.receiver when /(\A((::[A-Z]|[A-Z])\w*)+)/ unless result = search_const(b, $1) message = "Error: Not defined constants: #{expr.inspect}" @@ -768,8 +770,8 @@ def process_dap args result = b.local_variable_get(expr) rescue NameError # try to check method - if b.receiver.respond_to? expr, include_all: true - result = b.receiver.method(expr) + if M_RESPOND_TO_P.bind_call(b.receiver, expr, include_all: true) + result = M_METHOD.bind_call(b.receiver, expr) else message = "Error: Can not evaluate: #{expr.inspect}" end @@ -849,11 +851,11 @@ def variable_ name, obj, indexedVariables: 0, namedVariables: 0 vid = 0 end - ivnum = obj.instance_variables.size + ivnum = M_INSTANCE_VARIABLES.bind_call(obj).size { name: name, value: DEBUGGER__.safe_inspect(obj), - type: obj.class.name || obj.class.to_s, + type: (klass = M_CLASS.bind_call(obj)).name || klass.to_s, variablesReference: vid, indexedVariables: indexedVariables, namedVariables: namedVariables + ivnum, diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 668afa37a..39512cfa9 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2310,3 +2310,12 @@ class Binding alias break debugger alias b debugger end + +# for Ruby 2.6 compatibility +unless method(:p).unbind.respond_to? :bind_call + class UnboundMethod + def bind_call(obj, *args) + self.bind(obj).call(*args) + end + end +end diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 6ac947711..342caba60 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -6,6 +6,15 @@ require_relative 'color' module DEBUGGER__ + M_INSTANCE_VARIABLES = method(:instance_variables).unbind + M_INSTANCE_VARIABLE_GET = method(:instance_variable_get).unbind + M_CLASS = method(:class).unbind + M_SINGLETON_CLASS = method(:singleton_class).unbind + M_KIND_OF_P = method(:kind_of?).unbind + M_RESPOND_TO_P = method(:respond_to?).unbind + M_METHOD = method(:method).unbind + M_OBJECT_ID = method(:object_id).unbind + module SkipPathHelper def skip_path?(path) CONFIG.skip? || !path || @@ -532,8 +541,8 @@ def show_locals pat def show_ivars pat if s = current_frame&.self - s.instance_variables.sort.each{|iv| - value = s.instance_variable_get(iv) + M_INSTANCE_VARIABLES.bind_call(s).sort.each{|iv| + value = M_INSTANCE_VARIABLE_GET.bind_call(s, iv) puts_variable_info iv, value, pat } end @@ -542,10 +551,10 @@ def show_ivars pat def show_consts pat, only_self: false if s = current_frame&.self cs = {} - if s.kind_of? Module + if M_KIND_OF_P.bind_call(s, Module) cs[s] = :self else - s = s.class + s = M_CLASS.bind_call(s) cs[s] = :self unless only_self end @@ -583,7 +592,7 @@ def puts_variable_info label, obj, pat return if pat && pat !~ label begin - inspected = obj.inspect + inspected = DEBUGGER__.safe_inspect(obj) rescue Exception => e inspected = e.inspect end @@ -687,18 +696,25 @@ def show_outline expr o = Output.new(@output) locals = current_frame&.local_variables - klass = (obj.class == Class || obj.class == Module ? obj : obj.class) - o.dump("constants", obj.constants) if obj.respond_to?(:constants) + klass = M_CLASS.bind_call(obj) + klass = obj if Class == klass || Module == klass + + o.dump("constants", obj.constants) if M_RESPOND_TO_P.bind_call(obj, :constants) outline_method(o, klass, obj) - o.dump("instance variables", obj.instance_variables) + o.dump("instance variables", M_INSTANCE_VARIABLES.bind_call(obj)) o.dump("class variables", klass.class_variables) o.dump("locals", locals.keys) if locals end end def outline_method(o, klass, obj) - singleton_class = begin obj.singleton_class; rescue TypeError; nil end + begin + singleton_class = M_SINGLETON_CLASS.bind_call(obj) + rescue TypeError + singleton_class = nil + end + maps = class_method_map((singleton_class || klass).ancestors) maps.each do |mod, methods| name = mod == singleton_class ? "#{klass}.methods" : "#{mod}#methods" @@ -1000,7 +1016,7 @@ def wait_next_action_ begin obj = frame_eval args.shift, re_raise: true opt = args.shift - obj_inspect = obj.inspect + obj_inspect = DEBUGGER__.safe_inspect(obj) width = 50 @@ -1008,7 +1024,7 @@ def wait_next_action_ obj_inspect = truncate(obj_inspect, width: width) end - event! :result, :trace_pass, obj.object_id, obj_inspect, opt + event! :result, :trace_pass, M_OBJECT_ID.bind_call(obj), obj_inspect, opt rescue => e puts e.message event! :result, nil diff --git a/lib/debug/tracer.rb b/lib/debug/tracer.rb index 9c305ca12..ac0667c3a 100644 --- a/lib/debug/tracer.rb +++ b/lib/debug/tracer.rb @@ -186,7 +186,7 @@ def setup @tracer = TracePoint.new(:a_call){|tp| next if skip?(tp) - if tp.self.object_id == @obj_id + if M_OBJECT_ID.bind_call(tp.self) == @obj_id klass = tp.defined_class method = tp.method_id method_info =