In Files

  • typeprof-0.21.2/lib/typeprof.rb
  • typeprof-0.21.2/lib/typeprof/analyzer.rb
  • typeprof-0.21.2/lib/typeprof/arguments.rb
  • typeprof-0.21.2/lib/typeprof/block.rb
  • typeprof-0.21.2/lib/typeprof/builtin.rb
  • typeprof-0.21.2/lib/typeprof/cli.rb
  • typeprof-0.21.2/lib/typeprof/code-range.rb
  • typeprof-0.21.2/lib/typeprof/config.rb
  • typeprof-0.21.2/lib/typeprof/container-type.rb
  • typeprof-0.21.2/lib/typeprof/export.rb
  • typeprof-0.21.2/lib/typeprof/import.rb
  • typeprof-0.21.2/lib/typeprof/insns-def.rb
  • typeprof-0.21.2/lib/typeprof/iseq.rb
  • typeprof-0.21.2/lib/typeprof/lsp.rb
  • typeprof-0.21.2/lib/typeprof/method.rb
  • typeprof-0.21.2/lib/typeprof/type.rb
  • typeprof-0.21.2/lib/typeprof/utils.rb
  • typeprof-0.21.2/lib/typeprof/version.rb

Class/Module Index [+]

Quicksearch

TypeProf

Public Class Methods

analyze(config, cancel_token = nil) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/config.rb, line 79
def self.analyze(config, cancel_token = nil)
  # Deploy the config to the TypeProf::Config (Note: This is thread local)
  Config.set_current(config)

  if Config.current.options[:stackprof]
    require "stackprof"
    out = "typeprof-stackprof-#{ Config.current.options[:stackprof] }.dump"
    StackProf.start(mode: Config.current.options[:stackprof], out: out, raw: true)
  end

  scratch = Scratch.new
  Builtin.setup_initial_global_env(scratch)

  Config.current.gem_rbs_features.each do |feature|
    Import.import_library(scratch, feature)
  end

  rbs_files = []
  rbs_codes = []
  Config.current.rbs_files.each do |rbs|
    if rbs.is_a?(Array) # [String name, String content]
      rbs_codes << rbs
    else
      rbs_files << rbs
    end
  end
  Import.import_rbs_files(scratch, rbs_files)
  rbs_codes.each do |name, content|
    Import.import_rbs_code(scratch, name, content)
  end

  def_code_range_table = nil
  caller_code_range_table = nil
  Config.current.rb_files.each do |rb|
    if rb.is_a?(Array) # [String name, String content]
      iseq, def_tbl, caller_tbl = ISeq.compile_str(*rb.reverse)
      def_code_range_table ||= def_tbl
      caller_code_range_table ||= caller_tbl
    else
      iseq = rb
    end
    scratch.add_entrypoint(iseq)
  end

  result = scratch.type_profile(cancel_token)

  if Config.current.options[:lsp]
    return scratch.report_lsp, def_code_range_table, caller_code_range_table
  end

  if Config.current.output.respond_to?(:write)
    scratch.report(result, Config.current.output)
  else
    open(Config.current.output, "w") do |output|
      scratch.report(result, output)
    end
  end

rescue TypeProfError => exc
  exc.report(Config.current.output)

  return nil
ensure
  if Config.current.options[:stackprof] && defined?(StackProf)
    StackProf.stop
    StackProf.results
  end
end
            
any() click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 424
def self.any
  Thread.current[:any] ||= Any.new
end
            
bool() click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 432
def self.bool
  Thread.current[:bool] ||= Union.new(Utils::Set[
    Instance.new(Type::Builtin[:true]),
    Instance.new(Type::Builtin[:false])
  ], nil)
end
            
bot() click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 428
def self.bot
  Thread.current[:bot] ||= Union.new(Utils::Set[], nil)
end
            
builtin_global_variable_type(var) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 806
def self.builtin_global_variable_type(var)
  case var
  when :$_, :$/, :$\, :$,, :$;
    Type.optional(Type::Instance.new(Type::Builtin[:str]))
  when :$0, :$PROGRAM_NAME
    Type::Instance.new(Type::Builtin[:str])
  when :$~
    Type.optional(Type::Instance.new(Type::Builtin[:matchdata]))
  when :$., :$$
    Type::Instance.new(Type::Builtin[:int])
  when :$?
    Type.optional(Type::Instance.new(Type::Builtin[:int]))
  when :$!
    Type.optional(Type::Instance.new(Type::Builtin[:exc]))
  when :$@
    str = Type::Instance.new(Type::Builtin[:str])
    base_ty = Type::Instance.new(Type::Builtin[:ary])
    Type.optional(Type::Array.new(Type::Array::Elements.new([], str), base_ty))
  when :$*, :$:, :$LOAD_PATH, :$", :$LOADED_FEATURES
    str = Type::Instance.new(Type::Builtin[:str])
    base_ty = Type::Instance.new(Type::Builtin[:ary])
    Type::Array.new(Type::Array::Elements.new([], str), base_ty)
  when :$<
    :ARGF
  when :$>
    :STDOUT
  when :$DEBUG
    Type.bool
  when :$FILENAME
    Type::Instance.new(Type::Builtin[:str])
  when :$stdin
    :STDIN
  when :$stdout
    :STDOUT
  when :$stderr
    :STDERR
  when :$VERBOSE
    Type.bool.union(Type.nil)
  else
    nil
  end
end
            
gen_hash(base_ty = Type::Instance.new(Type::Builtin[:hash])) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 747
def self.gen_hash(base_ty = Type::Instance.new(Type::Builtin[:hash]))
  hg = HashGenerator.new
  yield hg
  Type::Hash.new(Type::Hash::Elements.new(hg.map_tys), base_ty)
end
            
guess_literal_type(obj) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 753
def self.guess_literal_type(obj)
  case obj
  when ::Symbol
    Type::Symbol.new(obj, Type::Instance.new(Type::Builtin[:sym]))
  when ::Integer
    Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:int]))
  when ::Rational
    Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:rational]))
  when ::Complex
    Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:complex]))
  when ::Float
    Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:float]))
  when ::Class
    return Type.any if obj < Exception
    case obj
    when ::Object
      Type::Builtin[:obj]
    when ::Array
      Type::Builtin[:ary]
    else
      raise "unknown class: #{ obj.inspect }"
    end
  when ::TrueClass
    Type::Instance.new(Type::Builtin[:true])
  when ::FalseClass
    Type::Instance.new(Type::Builtin[:false])
  when ::Array
    base_ty = Type::Instance.new(Type::Builtin[:ary])
    lead_tys = obj.map {|arg| guess_literal_type(arg) }
    Type::Array.new(Type::Array::Elements.new(lead_tys), base_ty)
  when ::Hash
    Type.gen_hash do |h|
      obj.each do |k, v|
        k_ty = guess_literal_type(k).globalize(nil, {}, Config.current.options[:type_depth_limit])
        v_ty = guess_literal_type(v)
        h[k_ty] = v_ty
      end
    end
  when ::String
    Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:str]))
  when ::Regexp
    Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:regexp]))
  when ::NilClass
    Type.nil
  when ::Range
    Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:range]))
  when ::Encoding
    Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:encoding]))
  else
    raise "unknown object: #{ obj.inspect }"
  end
end
            
nil() click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 439
def self.nil
  Thread.current[:nil] ||= Instance.new(Type::Builtin[:nil])
end
            
optional(ty) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 443
def self.optional(ty)
  ty.union(Type.nil)
end
            
start_lsp_server(config) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/lsp.rb, line 6
def self.start_lsp_server(config)
  if config.lsp_options[:stdio]
    reader = LSP::Reader.new($stdin)
    writer = LSP::Writer.new($stdout)
    # pipe all builtin print output to stderr to avoid conflicting with lsp
    $stdout = $stderr
    TypeProf::LSP::Server.new(config, reader, writer).run
  else
    Socket.tcp_server_sockets("localhost", config.lsp_options[:port]) do |servs|
      serv = servs[0].local_address
      $stdout << JSON.generate({
        host: serv.ip_address,
        port: serv.ip_port,
        pid: $$,
      })
      $stdout.flush

      $stdout = $stderr

      Socket.accept_loop(servs) do |sock|
        sock.set_encoding("UTF-8")
        begin
          reader = LSP::Reader.new(sock)
          writer = LSP::Writer.new(sock)
          TypeProf::LSP::Server.new(config, reader, writer).run
        ensure
          sock.close
        end
        exit
      end
    end
  end
end
            
starting_state(iseq) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/config.rb, line 148
def self.starting_state(iseq)
  cref = CRef.new(:bottom, Type::Builtin[:obj], false) # object
  recv = Type::Instance.new(Type::Builtin[:obj])
  ctx = Context.new(iseq, cref, nil)
  ep = ExecutionPoint.new(ctx, 0, nil)
  locals = [Type.nil] * iseq.locals.size
  env = Env.new(StaticEnv.new(recv, Type.nil, false, false), locals, [], Utils::HashWrapper.new({}))

  return ep, env
end
            

Public Instance Methods

analyze(uri, text, cancel_token: nil, signature_help_loc: nil) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/lsp.rb, line 275
def analyze(uri, text, cancel_token: nil, signature_help_loc: nil)
  config = @server.typeprof_config.dup
  path = URI(uri).path
  config.rb_files = [[path, text]]
  config.rbs_files = ["typeprof.rbs"] # XXX
  config.verbose = 0
  config.max_sec = 1
  config.options[:show_errors] = true
  config.options[:show_indicator] = false
  config.options[:lsp] = true
  config.options[:signature_help_loc] = [path, signature_help_loc] if signature_help_loc

  TypeProf.analyze(config, cancel_token)
rescue SyntaxError
end
            
code_range_from_node(node) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/iseq.rb, line 71
def code_range_from_node(node)
  CodeRange.new(
    CodeLocation.new(node.first_lineno, node.first_column),
    CodeLocation.new(node.last_lineno, node.last_column),
  )
end
            
contain?(other) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/code-range.rb, line 82
def contain?(other)
  @first <= other.first && other.last <= @last
end
            
contain_loc?(loc) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/code-range.rb, line 78
def contain_loc?(loc)
  @first <= loc && loc < @last
end
            
find_node_by_id(node, id) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/iseq.rb, line 78
def find_node_by_id(node, id)
  node = RubyVM::AbstractSyntaxTree.parse(node) if node.is_a?(String)

  return node if id == node.node_id

  node.children.each do |child|
    if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
      ret = find_node_by_id(child, id)
      return ret if ret
    end
  end

  nil
end
            
generate_substitution() click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 161
def generate_substitution
  {}
end
            
include_untyped?(_scratch) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 174
def include_untyped?(_scratch)
  false
end
            
on_text_changed() click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/lsp.rb, line 295
def on_text_changed
  cancel_token = AnalysisToken.new
  @last_analysis_cancel_token&.cancel
  @last_analysis_cancel_token = cancel_token

  uri = @uri
  text = @text
  self.push_analysis_queue do
    if cancel_token.cancelled?
      next
    end
    res, def_table, caller_table = self.analyze(uri, text, cancel_token: cancel_token)
    unless cancel_token.cancelled?
      on_text_changed_analysis(res, def_table, caller_table)
    end
  end
end
            
on_text_changed_analysis(res, definition_table, caller_table) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/lsp.rb, line 313
def on_text_changed_analysis(res, definition_table, caller_table)
  @definition_table = definition_table
  @caller_table = caller_table
  return unless res

  @sigs = []
  res[:sigs].each do |file, lineno, sig_str, rbs_code_range, class_kind, class_name|
    uri0 = "file://" + file
    if @uri == uri0
      command = { title: sig_str }
      if rbs_code_range
        command[:command] = "typeprof.jumpToRBS"
        command[:arguments] = [uri0, { line: lineno - 1, character: 0 }, @server.root_uri + "/" + rbs_code_range[0], rbs_code_range[1].to_lsp]
      else
        command[:command] = "typeprof.createPrototypeRBS"
        command[:arguments] = [class_kind, class_name, sig_str]
      end
      @sigs << {
        range: {
          start: { line: lineno - 1, character: 0 },
          end: { line: lineno - 1, character: 1 },
        },
        command: command,
      }
    end
  end
            
overlap?(other) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/code-range.rb, line 86
def overlap?(other)
  if @first <= other.first
    return @last > other.first
  else
    return @first < other.last
  end
end
            
push_analysis_queue(&work) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/lsp.rb, line 291
def push_analysis_queue(&work)
  @analysis_queue.push(work)
end
            
remove_type_vars() click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 170
def remove_type_vars
  substitute(DummySubstitution, Config.current.options[:type_depth_limit])
end
            
signature_help(loc, trigger_kind) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/lsp.rb, line 248
def signature_help(loc, trigger_kind)
  loc = CodeLocation.from_lsp(loc)

  res, = analyze(@uri, @text, signature_help_loc: loc)

  if res
    res[:signature_help].filter_map do |sig_str, sig_help, node_id|
      node = ISeq.find_node_by_id(@text, node_id)
      if node && ISeq.code_range_from_node(node).contain_loc?(loc)
        idx = locate_arg_index_in_signature_help(node, loc, sig_help)

        {
          label: sig_str,
          parameters: sig_help.values.map do |r|
            {
              label: [r.begin, r.end],
            }
          end,
          activeParameter: idx,
        }
      end
    end
  else
    nil
  end
end
            
substitute(_subst, _depth) click to toggle source
 
               # File typeprof-0.21.2/lib/typeprof/type.rb, line 157
def substitute(_subst, _depth)
  raise "cannot substitute abstract type: #{ self.class }"
end
            
There is an updated format of the API docs for this version here.