class Solargraph::Source::Chain::Call

def block_call_type(api_map, name_pin, locals)

Returns:
  • (ComplexType, nil) -

Parameters:
  • locals (::Array) --
  • block_parameter_types (::Array) --
  • name_pin (Pin::Base) --
  • api_map (ApiMap) --
def block_call_type(api_map, name_pin, locals)
  return nil unless with_block?
  block_context_pin = name_pin
  block_pin = find_block_pin(api_map)
  block_context_pin = block_pin.closure if block_pin
  block.infer(api_map, block_context_pin, locals)
end

def block_symbol_call_type(api_map, context, block_parameter_types, locals)

Returns:
  • (ComplexType, nil) -

Parameters:
  • locals (::Array) --
  • block_parameter_types (::Array) --
  • context (ComplexType) --
  • api_map (ApiMap) --
def block_symbol_call_type(api_map, context, block_parameter_types, locals)
  # Ruby's shorthand for sending the passed in method name

  # to the first yield parameter with no arguments

  block_symbol_name = block.links.first.word
  block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
  callee = api_map.get_path_pins(block_symbol_call_path).first
  return_type = callee&.return_type
  # @todo: Figure out why we get unresolved generics at

  #   this point and need to assume method return types

  #   based on the generic type

  return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
  return_type || ComplexType::UNDEFINED
end

def extra_return_type docstring, context

Returns:
  • (ComplexType, nil) -

Parameters:
  • context (ComplexType) --
  • docstring (YARD::Docstring) --
def extra_return_type docstring, context
  if docstring.has_tag?('return_single_parameter') #&& context.subtypes.one?

    return context.subtypes.first || ComplexType::UNDEFINED
  elsif docstring.has_tag?('return_value_parameter') && context.value_types.one?
    return context.value_types.first
  end
  nil
end

def find_block_pin(api_map)

Returns:
  • (Pin::Block, nil) -

Parameters:
  • api_map (ApiMap) --
def find_block_pin(api_map)
  node_location = Solargraph::Location.from_node(block.node)
  return if  node_location.nil?
  block_pins = api_map.get_block_pins
  block_pins.find { |pin| pin.location.contain?(node_location) }
end

def find_method_pin(name_pin)

Returns:
  • (Pin::Method, nil) -

Parameters:
  • name_pin (Pin::Base) --
def find_method_pin(name_pin)
  method_pin = name_pin
  until method_pin.is_a?(Pin::Method)
    method_pin = method_pin.closure
    return if method_pin.nil?
  end
  method_pin
end

def fix_block_pass

Returns:
  • (void) -
def fix_block_pass
  argument = @arguments.last&.links&.first
  @block = @arguments.pop if argument.is_a?(BlockSymbol) || argument.is_a?(BlockVariable)
end

def inferred_pins pins, api_map, name_pin, locals

Returns:
  • (::Array) -

Parameters:
  • locals (::Array) --
  • name_pin (Pin::Base) --
  • api_map (ApiMap) --
  • pins (::Enumerable) --
def inferred_pins pins, api_map, name_pin, locals
  result = pins.map do |p|
    next p unless p.is_a?(Pin::Method)
    overloads = p.signatures
    # next p if overloads.empty?

    type = ComplexType::UNDEFINED
    # start with overloads that require blocks; if we are

    # passing a block, we want to find a signature that will

    # use it.  If we didn't pass a block, the logic below will

    # reject it regardless

    sorted_overloads = overloads.sort { |ol| ol.block? ? -1 : 1 }
    new_signature_pin = nil
    sorted_overloads.each do |ol|
      next unless ol.arity_matches?(arguments, with_block?)
      match = true
      atypes = []
      arguments.each_with_index do |arg, idx|
        param = ol.parameters[idx]
        if param.nil?
          match = ol.parameters.any?(&:restarg?)
          break
        end
        atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(name_pin.context), locals)
        # make sure we get types from up the method

        # inheritance chain if we don't have them on this pin

        ptype = param.typify api_map
        # @todo Weak type comparison

        # unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)

        unless ptype.undefined? || atype.name == ptype.name || ptype.any? { |current_ptype| api_map.super_and_sub?(current_ptype.name, atype.name) } || ptype.generic? || param.restarg?
          match = false
          break
        end
      end
      if match
        if ol.block && with_block?
          block_atypes = ol.block.parameters.map(&:return_type)
          if block.links.map(&:class) == [BlockSymbol]
            # like the bar in foo(&:bar)

            blocktype = block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
          else
            blocktype = block_call_type(api_map, name_pin, locals)
          end
        end
        new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
        new_return_type = new_signature_pin.return_type
        type = with_params(new_return_type.self_to_type(name_pin.context), name_pin.context).qualify(api_map, name_pin.context.namespace) if new_return_type.defined?
        type ||= ComplexType::UNDEFINED
      end
      break if type.defined?
    end
    p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
    next p.proxy(type) if type.defined?
    if !p.macros.empty?
      result = process_macro(p, api_map, name_pin.context, locals)
      next result unless result.return_type.undefined?
    elsif !p.directives.empty?
      result = process_directive(p, api_map, name_pin.context, locals)
      next result unless result.return_type.undefined?
    end
    p
  end
  result.map do |pin|
    if pin.path == 'Class#new' && name_pin.context.tag != 'Class'
      reduced_context = name_pin.context.reduce_class_type
      pin.proxy(reduced_context)
    else
      next pin if pin.return_type.undefined?
      selfy = pin.return_type.self_to_type(name_pin.context)
      selfy == pin.return_type ? pin : pin.proxy(selfy)
    end
  end
end

def initialize word, arguments = [], block = nil

Parameters:
  • block (Chain, nil) --
  • arguments (::Array) --
  • word (String) --
def initialize word, arguments = [], block = nil
  @word = word
  @arguments = arguments
  @block = block
  fix_block_pass
end

def inner_process_macro pin, macro, api_map, context, locals

Returns:
  • (Pin::ProxyType) -

Parameters:
  • locals (Enumerable) --
  • context (ComplexType) --
  • api_map (ApiMap) --
  • macro (YARD::Tags::MacroDirective) --
  • pin (Pin::Base) --
def inner_process_macro pin, macro, api_map, context, locals
  vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
  txt = macro.tag.text.clone
  if txt.empty? && macro.tag.name
    named = api_map.named_macro(macro.tag.name)
    txt = named.tag.text.clone if named
  end
  i = 1
  vals.each do |v|
    txt.gsub!(/\$#{i}/, v.context.namespace)
    i += 1
  end
  docstring = Solargraph::Source.parse_docstring(txt).to_docstring
  tag = docstring.tag(:return)
  unless tag.nil? || tag.types.nil?
    return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types))
  end
  Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
end

def process_directive pin, api_map, context, locals

Returns:
  • (Pin::ProxyType) -

Parameters:
  • locals (Enumerable) --
  • context (ComplexType) --
  • api_map (ApiMap) --
  • pin (Pin::Method) --
def process_directive pin, api_map, context, locals
  pin.directives.each do |dir|
    macro = api_map.named_macro(dir.tag.name)
    next if macro.nil?
    result = inner_process_macro(pin, macro, api_map, context, locals)
    return result unless result.return_type.undefined?
  end
  Pin::ProxyType.anonymous ComplexType::UNDEFINED
end

def process_macro pin, api_map, context, locals

Returns:
  • (Pin::Base) -

Parameters:
  • locals (Enumerable) --
  • context (ComplexType) --
  • api_map (ApiMap) --
  • pin (Pin::Base) --
def process_macro pin, api_map, context, locals
  pin.macros.each do |macro|
    # @todo 'Wrong argument type for

    #   Solargraph::Source::Chain::Call#inner_process_macro:

    #   macro expected YARD::Tags::MacroDirective, received

    #   generic<Elem>' is because we lose 'rooted' information

    #   in the 'Chain::Array' class internally, leaving

    #   ::Array#each shadowed when it shouldn't be.

    result = inner_process_macro(pin, macro, api_map, context, locals)
    return result unless result.return_type.undefined?
  end
  Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
end

def resolve api_map, name_pin, locals

Parameters:
  • locals (::Array) --
  • name_pin (Pin::Closure) -- name_pin.binder should give us the object on which 'word' will be invoked
  • api_map (ApiMap) --
def resolve api_map, name_pin, locals
  return super_pins(api_map, name_pin) if word == 'super'
  return yield_pins(api_map, name_pin) if word == 'yield'
  found = if head?
    locals.select { |p| p.name == word }
  else
    []
  end
  return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
  pins = name_pin.binder.each_unique_type.flat_map do |context|
    ns = context.namespace == '' ? '' : context.namespace_type.tag
    api_map.get_method_stack(ns, word, scope: context.scope)
  end
  return [] if pins.empty?
  inferred_pins(pins, api_map, name_pin, locals)
end

def super_pins api_map, name_pin

Returns:
  • (::Array) -

Parameters:
  • name_pin (Pin::Base) --
  • api_map (ApiMap) --
def super_pins api_map, name_pin
  method_pin = find_method_pin(name_pin)
  return [] if method_pin.nil?
  pins = api_map.get_method_stack(method_pin.namespace, method_pin.name, scope: method_pin.context.scope)
  pins.reject{|p| p.path == name_pin.path}
end

def with_block?

def with_block?
  !!@block
end

def with_params type, context

Returns:
  • (ComplexType) -

Parameters:
  • context (ComplexType) --
  • type (ComplexType) --
def with_params type, context
  return type unless type.to_s.include?('$')
  ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:rooted_tag).join(', ')).gsub('<>', ''))
end

def yield_pins api_map, name_pin

Returns:
  • (::Array) -

Parameters:
  • name_pin (Pin::Base) --
  • api_map (ApiMap) --
def yield_pins api_map, name_pin
  method_pin = find_method_pin(name_pin)
  return [] unless method_pin
  method_pin.signatures.map(&:block).compact.map do |signature_pin|
    return_type = signature_pin.return_type.qualify(api_map, name_pin.namespace)
    signature_pin.proxy(return_type)
  end
end