class Solargraph::Pin::Base
The base class for map pins.
Attributes
@return [YARD::CodeObjects::Base]
@type [::Numeric, nil] A priority for determining if pins should be combined or not
A nil priority is considered the be the lowest. All code, yard & rbs pins have nil priority Between 2 pins, the one with the higher priority gets chosen. If the priorities are equal, they are combined.
@return [Solargraph::Location, nil]
@return [String]
@return [String]
@return [Boolean]
@return [Boolean]
@return [ComplexType]
@return [::Symbol]
@return [Solargraph::Location, nil]
Public Class Methods
Source
# File lib/solargraph/pin/base.rb, line 49 def initialize location: nil, type_location: nil, closure: nil, source: nil, name: '', comments: '', docstring: nil, directives: nil, combine_priority: nil @location = location @type_location = type_location @closure = closure @name = name @comments = comments @source = source @identity = nil @docstring = docstring @directives = directives @combine_priority = combine_priority assert_source_provided assert_location_provided end
@param location [Solargraph::Location, nil] @param type_location [Solargraph::Location, nil] @param closure [Solargraph::Pin::Closure, nil] @param name [String] @param comments [String] @param source [Symbol, nil] @param docstring [YARD::Docstring, nil] @param directives [::Array<YARD::Tags::Directive>, nil] @param combine_priority [::Numeric, nil] See attr_reader for combine_priority
Public Instance Methods
Source
# File lib/solargraph/pin/base.rb, line 468 def == other return false unless nearly? other # @sg-ignore Should add more explicit type check on other comments == other.comments && location == other.location end
Source
# File lib/solargraph/pin/base.rb, line 637 def all_location_text if location.nil? && type_location.nil? '' elsif !location.nil? && type_location.nil? " at #{location.inspect})" elsif !type_location.nil? && location.nil? " at #{type_location.inspect})" else " at (#{location.inspect} and #{type_location.inspect})" end end
@return [String]
Source
# File lib/solargraph/pin/base.rb, line 407 def all_rooted? !return_type || return_type.all_rooted? end
Source
# File lib/solargraph/pin/base.rb, line 66 def assert_location_provided return unless best_location.nil? && %i[yardoc source rbs].include?(source) Solargraph.assert_or_log(:best_location, "Neither location nor type_location provided - #{path} #{source} #{self.class}") end
@return [void]
Source
# File lib/solargraph/pin/base.rb, line 311 def assert_same(other, attr) return false if other.nil? val1 = send(attr) val2 = other.send(attr) return val1 if val1 == val2 Solargraph.assert_or_log("combine_with_#{attr}".to_sym, "Inconsistent #{attr.inspect} values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}") val1 end
@param other [self] @param attr [::Symbol]
@sg-ignore @return [undefined]
Source
# File lib/solargraph/pin/base.rb, line 270 def assert_same_array_content(other, attr, &block) arr1 = send(attr) raise "Expected #{attr} on #{self} to be an Enumerable, got #{arr1.class}" unless arr1.is_a?(::Enumerable) # @type arr1 [::Enumerable] arr2 = other.send(attr) raise "Expected #{attr} on #{other} to be an Enumerable, got #{arr2.class}" unless arr2.is_a?(::Enumerable) # @type arr2 [::Enumerable] # @type [undefined] values1 = arr1.map(&block) # @type [undefined] values2 = arr2.map(&block) # @sg-ignore return arr1 if values1 == values2 Solargraph.assert_or_log("combine_with_#{attr}".to_sym, "Inconsistent #{attr.inspect} values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self values = #{values1}\nother values =#{attr} = #{values2}") arr1 end
@param other [self] @param attr [::Symbol] @return [void] @todo strong typechecking should complain when there are no block-related tags
Source
# File lib/solargraph/pin/base.rb, line 293 def assert_same_count(other, attr) # @type [::Enumerable] arr1 = self.send(attr) raise "Expected #{attr} on #{self} to be an Enumerable, got #{arr1.class}" unless arr1.is_a?(::Enumerable) # @type [::Enumerable] arr2 = other.send(attr) raise "Expected #{attr} on #{other} to be an Enumerable, got #{arr2.class}" unless arr2.is_a?(::Enumerable) return arr1 if arr1.count == arr2.count Solargraph.assert_or_log("combine_with_#{attr}".to_sym, "Inconsistent #{attr.inspect} count value between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{arr1.inspect}\nother.#{attr} = #{arr2.inspect}") arr1 end
@param other [self] @param attr [::Symbol]
@return [::Enumerable]
Source
# File lib/solargraph/pin/base.rb, line 259 def assert_same_macros(other) return unless self.source == :yardoc && other.source == :yardoc assert_same_count(other, :macros) # @param [YARD::Tags::MacroDirective] assert_same_array_content(other, :macros) { |macro| macro.tag.name } end
@param other [self] @return [void]
Source
# File lib/solargraph/pin/base.rb, line 369 def assert_source_provided Solargraph.assert_or_log(:source, "source not provided - #{@path} #{@source} #{self.class}") if source.nil? end
@return [void]
Source
# File lib/solargraph/pin/base.rb, line 444 def best_location location || type_location end
@return [Location, nil]
Source
# File lib/solargraph/pin/base.rb, line 217 def choose(other, attr) results = [self, other].map(&attr).compact # true and false are different classes and can't be sorted return true if results.any? { |r| r == true || r == false } results.min rescue STDERR.puts("Problem handling #{attr} for \n#{self.inspect}\n and \n#{other.inspect}\n\n#{self.send(attr).inspect} vs #{other.send(attr).inspect}") raise end
when choices are arbitrary, make sure the choice is consistent
@param other [Pin::Base] @param attr [::Symbol]
@return [Object, nil]
Source
# File lib/solargraph/pin/base.rb, line 132 def choose_longer(other, attr) # @type [undefined] val1 = send(attr) # @type [undefined] val2 = other.send(attr) return val1 if val1 == val2 return val2 if val1.nil? val1.length > val2.length ? val1 : val2 end
@param other [self] @param attr [::Symbol] @sg-ignore @return [undefined]
Source
# File lib/solargraph/pin/base.rb, line 231 def choose_node(other, attr) if other.object_id < attr.object_id other.send(attr) else send(attr) end end
@param other [self] @param attr [::Symbol] @sg-ignore @return [undefined]
Source
# File lib/solargraph/pin/base.rb, line 344 def choose_pin_attr(other, attr) # @type [Pin::Base, nil] val1 = send(attr) # @type [Pin::Base, nil] val2 = other.send(attr) if val1.class != val2.class # :nocov: Solargraph.assert_or_log("combine_with_#{attr}_class".to_sym, "Inconsistent #{attr.inspect} class values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}") return val1 # :nocov: end # arbitrary way of choosing a pin [val1, val2].compact.max_by do |closure| [ # maximize number of gates, as types in other combined pins may # depend on those gates closure.gates.length, # use basename so that results don't vary system to system File.basename(closure.best_location.to_s) ] end end
@param other [self] @param attr [::Symbol]
@sg-ignore Missing @return tag for Solargraph::Pin::Base#choose_pin_attr @return [undefined]
Source
# File lib/solargraph/pin/base.rb, line 325 def choose_pin_attr_with_same_name(other, attr) # @type [Pin::Base, nil] val1 = send(attr) # @type [Pin::Base, nil] val2 = other.send(attr) raise "Expected pin for #{attr} on\n#{self.inspect},\ngot #{val1.inspect}" unless val1.nil? || val1.is_a?(Pin::Base) raise "Expected pin for #{attr} on\n#{other.inspect},\ngot #{val2.inspect}" unless val2.nil? || val2.is_a?(Pin::Base) if val1&.name != val2&.name Solargraph.assert_or_log("combine_with_#{attr}_name".to_sym, "Inconsistent #{attr.inspect} name values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}") end choose_pin_attr(other, attr) end
@param other [self] @param attr [::Symbol] @sg-ignore @return [undefined]
Source
# File lib/solargraph/pin/base.rb, line 112 def choose_priority(other) if combine_priority.nil? && !other.combine_priority.nil? return other elsif other.combine_priority.nil? && !combine_priority.nil? return self elsif !combine_priority.nil? && !other.combine_priority.nil? if combine_priority > other.combine_priority return self elsif combine_priority < other.combine_priority return other end end nil end
@param other [self] @return [self, nil] Returns either the pin chosen based on priority or nil
A nil return means that the combination process must proceed
Source
# File lib/solargraph/pin/base.rb, line 73 def closure Solargraph.assert_or_log(:closure, "Closure not set on #{self.class} #{name.inspect} from #{source.inspect}") unless @closure # @type [Pin::Closure, nil] @closure end
@return [Pin::Closure, nil]
Source
# File lib/solargraph/pin/base.rb, line 144 def combine_directives(other) return self.directives if other.directives.empty? return other.directives if directives.empty? [directives + other.directives].uniq end
@param other [self] @return [::Array<YARD::Tags::Directive>, nil]
Source
# File lib/solargraph/pin/base.rb, line 152 def combine_name(other) if needs_consistent_name? || other.needs_consistent_name? assert_same(other, :name) else choose(other, :name) end end
@param other [self] @return [String]
Source
# File lib/solargraph/pin/base.rb, line 187 def combine_return_type(other) if return_type.undefined? other.return_type elsif other.return_type.undefined? return_type elsif dodgy_return_type_source? && !other.dodgy_return_type_source? other.return_type elsif other.dodgy_return_type_source? && !dodgy_return_type_source? return_type else all_items = return_type.items + other.return_type.items if all_items.any? { |item| item.selfy? } && all_items.any? { |item| item.rooted_tag == context.reduce_class_type.rooted_tag } # assume this was a declaration that should have said 'self' all_items.delete_if { |item| item.rooted_tag == context.reduce_class_type.rooted_tag } end ComplexType.new(all_items) end end
@param other [self] @return [ComplexType]
Source
# File lib/solargraph/pin/base.rb, line 83 def combine_with(other, attrs={}) raise "tried to combine #{other.class} with #{self.class}" unless other.class == self.class priority_choice = choose_priority(other) return priority_choice unless priority_choice.nil? type_location = choose(other, :type_location) location = choose(other, :location) combined_name = combine_name(other) new_attrs = { location: location, type_location: type_location, name: combined_name, closure: choose_pin_attr_with_same_name(other, :closure), comments: choose_longer(other, :comments), source: :combined, docstring: choose(other, :docstring), directives: combine_directives(other), combine_priority: combine_priority }.merge(attrs) assert_same_macros(other) logger.debug { "Base#combine_with(path=#{path}) - other.comments=#{other.comments.inspect}, self.comments = #{self.comments}" } out = self.class.new(**new_attrs) out.reset_generated! out end
@param other [self] @param attrs [Hash{::Symbol => Object}]
@return [self]
Source
# File lib/solargraph/pin/base.rb, line 374 def comments @comments ||= '' end
@return [String]
Source
# File lib/solargraph/pin/base.rb, line 425 def completion_item_kind LanguageServer::CompletionItemKinds::KEYWORD end
@return [Integer]
Source
# File lib/solargraph/pin/base.rb, line 512 def deprecated? @deprecated ||= docstring.has_tag?('deprecated') end
@return [Boolean]
Source
# File lib/solargraph/pin/base.rb, line 627 def desc "[#{inner_desc}]" end
@return [String]
Source
# File lib/solargraph/pin/base.rb, line 488 def directives parse_comments unless @directives @directives end
@return [::Array<YARD::Tags::Directive>]
Source
# File lib/solargraph/pin/base.rb, line 482 def docstring parse_comments unless @docstring @docstring ||= Solargraph::Source.parse_docstring('').to_docstring end
@return [YARD::Docstring]
Source
# File lib/solargraph/pin/base.rb, line 206 def dodgy_return_type_source? # uses a lot of 'Object' instead of 'self' location&.filename&.include?('core_ext/object/') end
Source
# File lib/solargraph/pin/base.rb, line 413 def erase_generics(generics_to_erase) return self if generics_to_erase.empty? transform_types { |t| t.erase_generics(generics_to_erase) } end
@param generics_to_erase [::Array<String>] @return [self]
Source
# File lib/solargraph/pin/base.rb, line 419 def filename return nil if location.nil? location.filename end
@return [String, nil]
Source
# File lib/solargraph/pin/base.rb, line 594 def gates @gates ||= closure&.gates || [''] end
The namespaces available for resolving the current namespace. Each gate should be a fully qualified namespace or the root namespace (i.e., an empty string.)
Example: Given the name ‘Bar’ and the gates [‘Foo’, ”], the fully qualified namespace should be ‘Foo::Bar’ or ‘Bar’.
@return [Array<String>]
Source
# File lib/solargraph/pin/base.rb, line 582 def identity @identity ||= "#{closure&.path}|#{name}|#{location}" end
@deprecated @return [String]
Source
# File lib/solargraph/pin/base.rb, line 539 def infer api_map Solargraph::Logging.logger.warn "WARNING: Pin #infer methods are deprecated. Use #typify or #probe instead." type = typify(api_map) return type unless type.undefined? probe api_map end
Source
# File lib/solargraph/pin/base.rb, line 620 def inner_desc closure_info = closure&.desc binder_info = binder&.desc "name=#{name.inspect} return_type=#{type_desc}, context=#{context.rooted_tags}, closure=#{closure_info}, binder=#{binder_info}" end
@return [String]
Source
# File lib/solargraph/pin/base.rb, line 632 def inspect "#<#{self.class} `#{self.inner_desc}`#{all_location_text} via #{source.inspect}>" end
@return [String]
Source
# File lib/solargraph/pin/base.rb, line 494 def macros @macros ||= collect_macros end
@return [::Array<YARD::Tags::MacroDirective>]
Source
# File lib/solargraph/pin/base.rb, line 506 def maybe_directives? return !@directives.empty? if defined?(@directives) && @directives @maybe_directives ||= comments.include?('@!') end
Perform a quick check to see if this pin possibly includes YARD directives. This method does not require parsing the comments.
After the comments have been parsed, this method will return false if no directives were found, regardless of whether it previously appeared possible.
@return [Boolean]
Source
# File lib/solargraph/pin/base.rb, line 454 def nearly? other self.class == other.class && name == other.name && (closure == other.closure || (closure && closure.nearly?(other.closure))) && (comments == other.comments || (((maybe_directives? == false && other.maybe_directives? == false) || compare_directives(directives, other.directives)) && compare_docstring_tags(docstring, other.docstring)) ) end
True if the specified pin is a near match to this one. A near match indicates that the pins contain mostly the same data. Any differences between them should not have an impact on the API surface.
@param other [Solargraph::Pin::Base, Object] @return [Boolean]
Source
# File lib/solargraph/pin/base.rb, line 176 def needs_consistent_name? true end
Source
# File lib/solargraph/pin/base.rb, line 243 def prefer_rbs_location(other, attr) if rbs_location? && !other.rbs_location? self.send(attr) elsif !rbs_location? && other.rbs_location? other.send(attr) else choose(other, attr) end end
@param other [self] @param attr [::Symbol] @sg-ignore @return [undefined]
Source
# File lib/solargraph/pin/base.rb, line 36 def presence_certain? true end
Source
# File lib/solargraph/pin/base.rb, line 532 def probe api_map typify api_map end
Infer the pin’s return type via static code analysis.
@param api_map [ApiMap] @return [ComplexType]
Source
# File lib/solargraph/pin/base.rb, line 573 def proxy return_type result = dup result.return_type = return_type result.proxied = true result end
Return a proxy for this pin with the specified return type. Other than the return type and the proxied? setting, the proxy should be a clone of the original.
@param return_type [ComplexType] @return [self]
Source
# File lib/solargraph/pin/base.rb, line 253 def rbs_location? type_location&.rbs? end
Source
# File lib/solargraph/pin/base.rb, line 556 def realize api_map return self if return_type.defined? type = typify(api_map) return proxy(type) if type.defined? type = probe(api_map) return self if type.undefined? result = proxy(type) result.probed = true result end
@param api_map [ApiMap] @return [self]
Source
# File lib/solargraph/pin/base.rb, line 161 def reset_generated! # @return_type doesn't go here as subclasses tend to assign it # themselves in constructors, and they will deal with setting # it in any methods that call this # # @docstring also doesn't go here, as there is code which # directly manipulates docstring without editing comments # (e.g., Api::Map::Store#index processes overrides that way # # Same with @directives, @macros, @maybe_directives, which # regenerate docstring @deprecated = nil reset_conversions end
@return [void]
Source
# File lib/solargraph/pin/base.rb, line 403 def resolve_generics definitions, context_type transform_types { |t| t.resolve_generics(definitions, context_type) if t } end
Determine the concrete type for each of the generic type parameters used in this method based on the parameters passed into the its class and return a new method pin.
@param definitions [Pin::Namespace] The module/class which uses generic types @param context_type [ComplexType] The receiver type @return [self]
Source
# File lib/solargraph/pin/base.rb, line 383 def resolve_generics_from_context(generics_to_resolve, return_type_context = nil, resolved_generic_values: {}) proxy return_type.resolve_generics_from_context(generics_to_resolve, return_type_context, resolved_generic_values: resolved_generic_values) end
@param generics_to_resolve [Enumerable<String>] @param return_type_context [ComplexType, nil] @param context [ComplexType] @param resolved_generic_values [Hash{String => ComplexType}] @return [self]
Source
# File lib/solargraph/pin/base.rb, line 477 def return_type @return_type ||= ComplexType::UNDEFINED end
The pin’s return type.
@return [ComplexType]
Source
# File lib/solargraph/pin/base.rb, line 430 def symbol_kind nil end
@return [Integer, nil]
Source
# File lib/solargraph/pin/base.rb, line 599 def to_rbs return_type.to_rbs end
@return [String, nil]
Source
# File lib/solargraph/pin/base.rb, line 392 def transform_types(&transform) proxy return_type.transform(&transform) end
@yieldparam [ComplexType] @yieldreturn [ComplexType] @return [self]
Source
# File lib/solargraph/pin/base.rb, line 604 def type_desc rbs = to_rbs # RBS doesn't have a way to represent a Class<x> type rbs = return_type.rooted_tags if return_type.name == 'Class' if path if rbs path + ' ' + rbs else path end else rbs end end
@return [String, nil]
Source
# File lib/solargraph/pin/base.rb, line 524 def typify api_map return_type.qualify(api_map, *(closure&.gates || [''])) end
Source
# File lib/solargraph/pin/base.rb, line 439 def variable? false end
@return [Boolean]
Protected Instance Methods
Source
# File lib/solargraph/pin/base.rb, line 181 def equality_fields [name, location, type_location, closure, source] end
@sg-ignore def should infer as symbol - “Not enough arguments to Module#protected”
Private Instance Methods
Source
# File lib/solargraph/pin/base.rb, line 722 def collect_macros return [] unless maybe_directives? parse = Solargraph::Source.parse_docstring(comments) parse.directives.select{ |d| d.tag.tag_name == 'macro' } end
@return [::Array<YARD::Tags::Handlers::Directive>]
Source
# File lib/solargraph/pin/base.rb, line 702 def compare_directives dir1, dir2 return false if dir1.length != dir2.length dir1.each_index do |i| return false unless compare_tags(dir1[i].tag, dir2[i].tag) end true end
@param dir1 [::Array<YARD::Tags::Directive>] @param dir2 [::Array<YARD::Tags::Directive>] @return [Boolean]
Source
# File lib/solargraph/pin/base.rb, line 671 def parse_comments # HACK: Avoid a NoMethodError on nil with empty overload tags if comments.nil? || comments.empty? || comments.strip.end_with?('@overload') @docstring = nil @directives = [] else # HACK: Pass a dummy code object to the parser for plugins that # expect it not to be nil parse = Solargraph::Source.parse_docstring(comments) @docstring = parse.to_docstring @directives = parse.directives end end
@return [void]