class Solargraph::Pin::Method
The base class for method and attribute pins.
Attributes
@return [Parser::AST::Node]
@return [Array<Pin::Parameter>]
@return [::Symbol] :public, :private, or :protected
Public Class Methods
@param visibility [::Symbol] :public, :protected, or :private @param explicit [Boolean] @param parameters [Array<Pin::Parameter>] @param node [Parser::AST::Node, RubyVM::AbstractSyntaxTree::Node] @param attribute [Boolean]
# File lib/solargraph/pin/method.rb, line 23 def initialize visibility: :public, explicit: true, parameters: [], node: nil, attribute: false, signatures: nil, anon_splat: false, **splat super(**splat) @visibility = visibility @explicit = explicit @parameters = parameters @node = node @attribute = attribute @signatures = signatures @anon_splat = anon_splat end
Public Instance Methods
# File lib/solargraph/pin/method.rb, line 183 def anon_splat? @anon_splat end
# File lib/solargraph/pin/method.rb, line 140 def attribute? @attribute end
# File lib/solargraph/pin/method.rb, line 39 def completion_item_kind attribute? ? Solargraph::LanguageServer::CompletionItemKinds::PROPERTY : Solargraph::LanguageServer::CompletionItemKinds::METHOD end
@return [String]
# File lib/solargraph/pin/method.rb, line 64 def detail # This property is not cached in an instance variable because it can # change when pins get proxied. detail = String.new detail += if signatures.length > 1 "(*) " else "(#{signatures.first.parameters.map(&:full).join(', ')}) " unless signatures.first.parameters.empty? end.to_s detail += "=#{probed? ? '~' : (proxied? ? '^' : '>')} #{return_type.to_s}" unless return_type.undefined? detail.strip! return nil if detail.empty? detail end
# File lib/solargraph/pin/method.rb, line 101 def documentation if @documentation.nil? @documentation ||= super || '' param_tags = docstring.tags(:param) unless param_tags.nil? or param_tags.empty? @documentation += "\n\n" unless @documentation.empty? @documentation += "Params:\n" lines = [] param_tags.each do |p| l = "* #{p.name}" l += " [#{escape_brackets(p.types.join(', '))}]" unless p.types.nil? or p.types.empty? l += " #{p.text}" lines.push l end @documentation += lines.join("\n") end return_tags = docstring.tags(:return) unless return_tags.empty? @documentation += "\n\n" unless @documentation.empty? @documentation += "Returns:\n" lines = [] return_tags.each do |r| l = "*" l += " [#{escape_brackets(r.types.join(', '))}]" unless r.types.nil? or r.types.empty? l += " #{r.text}" lines.push l end @documentation += lines.join("\n") end @documentation += "\n\n" unless @documentation.empty? @documentation += "Visibility: #{visibility}" end @documentation.to_s end
# File lib/solargraph/pin/method.rb, line 136 def explicit? @explicit end
# File lib/solargraph/pin/method.rb, line 144 def nearly? other return false unless super parameters == other.parameters and scope == other.scope and visibility == other.visibility end
@return [Array<Pin::Method>]
# File lib/solargraph/pin/method.rb, line 162 def overloads @overloads ||= docstring.tags(:overload).map do |tag| Pin::Signature.new( tag.parameters.map do |src| name, decl = parse_overload_param(src.first) Pin::Parameter.new( location: location, closure: self, comments: tag.docstring.all.to_s, name: name, decl: decl, presence: location ? location.range : nil, return_type: param_type_from_name(tag, src.first) ) end, ComplexType.try_parse(*tag.docstring.tags(:return).flat_map(&:types)) ) end @overloads end
@return [Array<String>]
# File lib/solargraph/pin/method.rb, line 35 def parameter_names @parameter_names ||= parameters.map(&:name) end
# File lib/solargraph/pin/method.rb, line 89 def path @path ||= "#{namespace}#{(scope == :instance ? '#' : '.')}#{name}" end
# File lib/solargraph/pin/method.rb, line 151 def probe api_map attribute? ? infer_from_iv(api_map) : infer_from_return_nodes(api_map) end
# File lib/solargraph/pin/method.rb, line 47 def return_type @return_type ||= ComplexType.try_parse(*signatures.map(&:return_type).map(&:to_s)) end
@return [Array<Hash>]
# File lib/solargraph/pin/method.rb, line 80 def signature_help @signature_help ||= signatures.map do |sig| { label: name + '(' + sig.parameters.map(&:full).join(', ') + ')', documentation: documentation } end end
@return [Array<Signature>]
# File lib/solargraph/pin/method.rb, line 52 def signatures @signatures ||= begin top_type = generate_complex_type result = [] result.push Signature.new(parameters, top_type) if top_type.defined? result.concat(overloads.map { |meth| Signature.new(meth.parameters, meth.return_type) }) result.push Signature.new(parameters, top_type) if result.empty? result end end
# File lib/solargraph/pin/method.rb, line 43 def symbol_kind attribute? ? Solargraph::LanguageServer::SymbolKinds::PROPERTY : LanguageServer::SymbolKinds::METHOD end
# File lib/solargraph/pin/method.rb, line 155 def try_merge! pin return false unless super @node = pin.node true end
# File lib/solargraph/pin/method.rb, line 93 def typify api_map decl = super return decl unless decl.undefined? type = see_reference(api_map) || typify_from_super(api_map) return type.qualify(api_map, namespace) unless type.nil? name.end_with?('?') ? ComplexType::BOOLEAN : ComplexType::UNDEFINED end
Private Instance Methods
# File lib/solargraph/pin/method.rb, line 207 def clean_param name name.gsub(/[*&:]/, '') end
@return [ComplexType]
# File lib/solargraph/pin/method.rb, line 219 def generate_complex_type tags = docstring.tags(:return).map(&:types).flatten.reject(&:nil?) return ComplexType::UNDEFINED if tags.empty? ComplexType.try_parse *tags end
# File lib/solargraph/pin/method.rb, line 306 def infer_from_iv api_map types = [] varname = "@#{name.gsub(/=$/, '')}" pins = api_map.get_instance_variable_pins(binder.namespace, binder.scope).select { |iv| iv.name == varname } pins.each do |pin| type = pin.typify(api_map) type = pin.probe(api_map) if type.undefined? types.push type if type.defined? end return ComplexType::UNDEFINED if types.empty? ComplexType.try_parse(*types.map(&:tag).uniq) end
@param api_map [ApiMap] @return [ComplexType]
# File lib/solargraph/pin/method.rb, line 281 def infer_from_return_nodes api_map return ComplexType::UNDEFINED if node.nil? result = [] has_nil = false return ComplexType::NIL if method_body_node.nil? returns_from(method_body_node).each do |n| if n.nil? || [:NIL, :nil].include?(n.type) has_nil = true next end rng = Range.from_node(n) next unless rng clip = api_map.clip_at( location.filename, rng.ending ) chain = Solargraph::Parser.chain(n, location.filename) type = chain.infer(api_map, self, clip.locals) result.push type unless type.undefined? end result.push ComplexType::NIL if has_nil return ComplexType::UNDEFINED if result.empty? ComplexType.try_parse(*result.map(&:tag).uniq) end
@return [Parser::AST::Node, nil]
# File lib/solargraph/pin/method.rb, line 270 def method_body_node return nil if node.nil? return node.children[1].children.last if node.type == :DEFN return node.children[2].children.last if node.type == :DEFS return node.children[2] if node.type == :def || node.type == :DEFS return node.children[3] if node.type == :defs nil end
@param tag [YARD::Tags::OverloadTag]
# File lib/solargraph/pin/method.rb, line 212 def param_type_from_name(tag, name) param = tag.tags(:param).select { |t| t.name == name }.first return ComplexType::UNDEFINED unless param ComplexType.try_parse(*param.types) end
When YARD parses an overload tag, it includes rest modifiers in the parameters names.
@param arg [String] @return [Array(String, Symbol)]
# File lib/solargraph/pin/method.rb, line 323 def parse_overload_param(name) if name.start_with?('**') [name[2..-1], :kwrestarg] elsif name.start_with?('*') [name[1..-1], :restarg] else [name, :arg] end end
@param ref [String] @param api_map [ApiMap] @return [ComplexType]
# File lib/solargraph/pin/method.rb, line 252 def resolve_reference ref, api_map parts = ref.split(/[\.#]/) if parts.first.empty? || parts.one? path = "#{namespace}#{ref}" else fqns = api_map.qualify(parts.first, namespace) return ComplexType::UNDEFINED if fqns.nil? path = fqns + ref[parts.first.length] + parts.last end pins = api_map.get_path_pins(path) pins.each do |pin| type = pin.typify(api_map) return type unless type.undefined? end nil end
@param api_map [ApiMap] @return [ComplexType, nil]
# File lib/solargraph/pin/method.rb, line 227 def see_reference api_map docstring.ref_tags.each do |ref| next unless ref.tag_name == 'return' && ref.owner result = resolve_reference(ref.owner.to_s, api_map) return result unless result.nil? end match = comments.match(/^[ \t]*\(see (.*)\)/m) return nil if match.nil? resolve_reference match[1], api_map end
# File lib/solargraph/pin/method.rb, line 189 def select_decl name, asgn if name.start_with?('**') :kwrestarg elsif name.start_with?('*') :restarg elsif name.start_with?('&') :blockarg elsif name.end_with?(':') && asgn :kwoptarg elsif name.end_with?(':') :kwarg elsif asgn :optarg else :arg end end
@param api_map [ApiMap] @return [ComplexType, nil]
# File lib/solargraph/pin/method.rb, line 240 def typify_from_super api_map stack = api_map.get_method_stack(namespace, name, scope: scope).reject { |pin| pin.path == path } return nil if stack.empty? stack.each do |pin| return pin.return_type unless pin.return_type.undefined? end nil end