Skip to content

Instantly share code, notes, and snippets.

@ellcs
Created March 30, 2020 08:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ellcs/37644987d2166d51808996d0c64a24a4 to your computer and use it in GitHub Desktop.
Save ellcs/37644987d2166d51808996d0c64a24a4 to your computer and use it in GitHub Desktop.
require 'contracts'
# https://ruby-doc.org/core-2.6/RubyVM/InstructionSequence.html
module B
def c; end
end
def global_method; end
class A
include B
include Contracts::Core
def self.klass_method; end
def foo; end
Contract Integer => Integer
def ret_int(q)
q
end
def third
klass_method
c
ret_int.a
foo
global_method
asdf
end
end
class ISeqParser
attr_reader :m
attr_reader :iseq
def self.for(m)
new(m, RubyVM::InstructionSequence.of(m))
end
def initialize(m, iseq)
@m = m
@iseq = iseq
@array = iseq.to_a
end
[:magic,
:major_version,
:minor_version,
:format_type,
:misc,
:label,
:path,
:absolute_path,
:first_lineno,
:type,
:locals,
:params,
:catch_type,
:bytecode].each.with_index do |m, index|
define_method(m) do
@array[index]
end
end
def arg_size
misc[:arg_size]
end
def local_size
misc[:local_size]
end
def stack_max
misc[:stack_max]
end
# packed by lines
def packed_bytecode
bytecode.reduce([]) do |accu, elem|
if elem.is_a?(Integer)
accu.push([elem])
else
accu.last << elem
end
accu
end
end
def sat_calls2
errors = []
packed_bytecode.each do |pb|
owner = if pb.include?([:putself])
@m.owner
else
raise "not sapport yet"
end
pb.select do |(k, e)|
if k == :opt_send_without_block
unless object.private_methods.include?(mc) ||
owner.instance_methods.include?(mc) ||
owner.methods.include?(mc)
errors << "#{owner}##{@m.name} doesn't know #{mc}."
end
Contracts::Engine.fetch_from(owner)
end
end
end
end
# returns new owner
def sat_call(owner, method)
end
def method_calls
calls = []
binding.pry
packed_bytecode.each do |instruction_line|
index = instruction_line.flatten.find_index(:opt_send_without_block)
if index
calls << instruction_line.flatten[index+1][:mid]
end
end
calls
end
def sat_calls
owner = @m.owner
errors = []
method_calls.each do |mc|
unless object.private_methods.include?(mc) ||
owner.instance_methods.include?(mc) ||
owner.methods.include?(mc)
errors << "#{owner}##{@m.name} doesn't know #{mc}."
end
end
errors
end
end
i = ISeqParser.for(A.instance_method(:third))
require 'pry';binding.pry
check(method(:third))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment