Class: Solargraph::ApiMap

Inherits:
Object
  • Object
show all
Extended by:
Logging
Includes:
Logging
Defined in:
lib/solargraph/api_map.rb,
lib/solargraph/api_map/cache.rb,
lib/solargraph/api_map/index.rb,
lib/solargraph/api_map/store.rb,
lib/solargraph/api_map/constants.rb,
lib/solargraph/api_map/source_to_yard.rb

Overview

An aggregate provider for information about Workspaces, Sources, gems, and the Ruby core.

Defined Under Namespace

Modules: SourceToYard Classes: Cache, Constants, Index, Store

Constant Summary collapse

@@core_map =
RbsMap::CoreMap.new

Constants included from Logging

Logging::DEFAULT_LOG_LEVEL, Logging::LOG_LEVELS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logging

log_level, logger

Constructor Details

#initialize(pins: [], loose_unions: true) ⇒ ApiMap

Returns a new instance of ApiMap.

Parameters:

  • pins (Array<Solargraph::Pin::Base>) (defaults to: [])
  • loose_unions (Boolean) (defaults to: true)

    if true, a potential type can be inferred if ANY of the UniqueTypes in the base chain’s ComplexType match it. If false, every single UniqueTypes in the base must be ALL able to independently provide this type. The former is useful during completion, but the latter is best for typechecking at higher levels.



34
35
36
37
38
39
# File 'lib/solargraph/api_map.rb', line 34

def initialize pins: [], loose_unions: true
  @source_map_hash = {}
  @cache = Cache.new
  @loose_unions = loose_unions
  index pins
end

Instance Attribute Details

#loose_unionsObject (readonly)

Returns the value of attribute loose_unions.



70
71
72
# File 'lib/solargraph/api_map.rb', line 70

def loose_unions
  @loose_unions
end

#missing_docsArray<String> (readonly)

Returns:

  • (Array<String>)


24
25
26
# File 'lib/solargraph/api_map.rb', line 24

def missing_docs
  @missing_docs
end

#unresolved_requiresArray<String> (readonly)

Returns:

  • (Array<String>)


19
20
21
# File 'lib/solargraph/api_map.rb', line 19

def unresolved_requires
  @unresolved_requires
end

Class Method Details

.load(directory, loose_unions: true) ⇒ ApiMap

Create an ApiMap with a workspace in the specified directory.

Parameters:

  • directory (String)
  • loose_unions (Boolean) (defaults to: true)

    See #initialize

Returns:



230
231
232
233
234
235
236
237
238
# File 'lib/solargraph/api_map.rb', line 230

def self.load directory, loose_unions: true
  api_map = new(loose_unions: loose_unions)
  workspace = Solargraph::Workspace.new(directory)
  # api_map.catalog Bench.new(workspace: workspace)
  library = Library.new(workspace)
  library.map!
  api_map.catalog library.bench
  api_map
end

.load_with_cache(directory, out = $stderr, loose_unions: true) ⇒ ApiMap

Create an ApiMap with a workspace in the specified directory and cache any missing gems.

Parameters:

  • directory (String)
  • out (IO, StringIO, nil) (defaults to: $stderr)

    The output stream for messages

  • loose_unions (Boolean) (defaults to: true)

    See #initialize

Returns:



268
269
270
271
272
273
274
275
276
277
# File 'lib/solargraph/api_map.rb', line 268

def self.load_with_cache directory, out = $stderr, loose_unions: true
  api_map = load(directory, loose_unions: loose_unions)
  if api_map.uncached_gemspecs.empty?
    logger.info { "All gems cached for #{directory}" }
    return api_map
  end

  api_map.cache_all_for_doc_map!(out: out)
  load(directory, loose_unions: loose_unions)
end

.reset_core(out: nil) ⇒ void

This method returns an undefined value.

Parameters:

  • out (StringIO, IO, nil) (defaults to: nil)

    output stream for logging



43
44
45
# File 'lib/solargraph/api_map.rb', line 43

def self.reset_core out: nil
  @@core_map = RbsMap::CoreMap.new
end

Instance Method Details

#==(other) ⇒ Object

Parameters:

  • other (Object)


61
62
63
# File 'lib/solargraph/api_map.rb', line 61

def == other
  eql?(other)
end

#bundled?(filename) ⇒ Boolean

True if the specified file was included in a bundle, i.e., it’s either included in a workspace or open in a library.

Parameters:

  • filename (String)

Returns:

  • (Boolean)


695
696
697
# File 'lib/solargraph/api_map.rb', line 695

def bundled? filename
  source_map_hash.keys.include?(filename)
end

#cache_all_for_doc_map!(out: $stderr, rebuild: false) ⇒ void

This method returns an undefined value.

Parameters:

  • out (StringIO, IO, nil) (defaults to: $stderr)
  • rebuild (Boolean) (defaults to: false)

    whether to rebuild the pins even if they are cached



243
244
245
# File 'lib/solargraph/api_map.rb', line 243

def cache_all_for_doc_map! out: $stderr, rebuild: false
  doc_map.cache_all!(out, rebuild: rebuild)
end

#cache_gem(gemspec, rebuild: false, out: nil) ⇒ void

This method returns an undefined value.

Parameters:

  • gemspec (Gem::Specification)
  • rebuild (Boolean) (defaults to: false)
  • out (StringIO, IO, nil) (defaults to: nil)


251
252
253
# File 'lib/solargraph/api_map.rb', line 251

def cache_gem gemspec, rebuild: false, out: nil
  doc_map.cache(gemspec, rebuild: rebuild, out: out)
end

#catalog(bench) ⇒ self

Catalog a bench.

Parameters:

Returns:

  • (self)


108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/solargraph/api_map.rb', line 108

def catalog bench
  @source_map_hash = bench.source_map_hash
  # @type [Array<Pin::Base>]
  iced_pins = bench.icebox.flat_map(&:pins)
  live_pins = bench.live_map&.all_pins || []
  conventions_environ.clear
  source_map_hash.each_value do |map|
    conventions_environ.merge map.conventions_environ
  end
  unresolved_requires = (bench.external_requires + conventions_environ.requires + bench.workspace.config.required).to_a.compact.uniq
  recreate_docmap = @unresolved_requires != unresolved_requires ||
                    # @sg-ignore Unresolved call to rbs_collection_path on Solargraph::Workspace, nil
                    workspace.rbs_collection_path != bench.workspace.rbs_collection_path ||
                    @doc_map.uncached_gemspecs.any?

  if recreate_docmap
    @doc_map = DocMap.new(unresolved_requires, bench.workspace, out: nil) # @todo Implement gem preferences
    @unresolved_requires = @doc_map.unresolved_requires
  end
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  Solargraph.logger.info 'Cataloging ApiMap started'
  @cache.clear if store.update(@@core_map.pins, @doc_map.pins, conventions_environ.pins, iced_pins, live_pins) { process_macros }
  @missing_docs = [] # @todo Implement missing docs
  Solargraph.logger.info "Cataloging ApiMap finished in #{Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time} seconds"
  self
end

#clip(cursor) ⇒ SourceMap::Clip

Parameters:

Returns:

Raises:



662
663
664
665
666
# File 'lib/solargraph/api_map.rb', line 662

def clip cursor
  raise FileNotFoundError, "ApiMap did not catalog #{cursor.filename}" unless source_map_hash.key?(cursor.filename)

  SourceMap::Clip.new(self, cursor)
end

#clip_at(filename, position) ⇒ SourceMap::Clip

Get a clip by filename and position.

Parameters:

  • filename (String)
  • position (Position, Array(Integer, Integer))

Returns:



219
220
221
222
# File 'lib/solargraph/api_map.rb', line 219

def clip_at filename, position
  position = Position.normalize(position)
  clip(cursor_at(filename, position))
end

#conventions_environEnviron

Returns:



201
202
203
# File 'lib/solargraph/api_map.rb', line 201

def conventions_environ
  @conventions_environ ||= Environ.new
end

#core_pinsEnumerable<Pin::Base>

Returns:



184
185
186
# File 'lib/solargraph/api_map.rb', line 184

def core_pins
  @@core_map.pins
end

#cursor_at(filename, position) ⇒ Source::Cursor

Parameters:

  • filename (String)
  • position (Position, Array(Integer, Integer))

Returns:

Raises:



208
209
210
211
212
# File 'lib/solargraph/api_map.rb', line 208

def cursor_at filename, position
  position = Position.normalize(position)
  raise FileNotFoundError, "File not found: #{filename}" unless source_map_hash.key?(filename)
  source_map_hash[filename].cursor_at(position)
end

#dereference(pin) ⇒ String?

Get a fully qualified namespace from a reference pin.

Parameters:

Returns:

  • (String, nil)


362
363
364
# File 'lib/solargraph/api_map.rb', line 362

def dereference pin
  store.constants.dereference(pin)
end

#doc_mapDocMap

Returns:



164
165
166
# File 'lib/solargraph/api_map.rb', line 164

def doc_map
  @doc_map ||= DocMap.new([], Workspace.new('.'))
end

#document(path) ⇒ Enumerable<Pin::Base>

Deprecated.

This method is likely superfluous. Calling #get_path_pins directly should be sufficient.

Parameters:

  • path (String)

    The path to find

Returns:



637
638
639
# File 'lib/solargraph/api_map.rb', line 637

def document path
  get_path_pins(path)
end

#document_symbols(filename) ⇒ Array<Pin::Symbol>

Get an array of document symbols from a file.

Parameters:

  • filename (String)

Returns:



672
673
674
675
# File 'lib/solargraph/api_map.rb', line 672

def document_symbols filename
  return [] unless source_map_hash.key?(filename) # @todo Raise error?
  resolve_method_aliases source_map_hash[filename].document_symbols
end

#eql?(other) ⇒ Boolean

Parameters:

  • other (Object)

Returns:

  • (Boolean)


54
55
56
57
58
# File 'lib/solargraph/api_map.rb', line 54

def eql? other
  self.class == other.class &&
    # @sg-ignore flow sensitive typing needs to handle self.class == other.class
    equality_fields == other.equality_fields
end

#get_block_pinsEnumerable<Solargraph::Pin::Block>

Returns:



442
443
444
# File 'lib/solargraph/api_map.rb', line 442

def get_block_pins
  store.pins_by_class(Pin::Block)
end

#get_class_variable_pins(namespace) ⇒ Enumerable<Solargraph::Pin::ClassVariable>

Get an array of class variable pins for a namespace.

Parameters:

  • namespace (String)

    A fully qualified namespace

Returns:



427
428
429
# File 'lib/solargraph/api_map.rb', line 427

def get_class_variable_pins namespace
  prefer_non_nil_variables(store.get_class_variables(namespace))
end

#get_complex_type_methods(complex_type, context = '', internal = false) ⇒ Array<Solargraph::Pin::Base>

Get an array of method pins for a complex type.

The type’s namespace and the context should be fully qualified. If the context matches the namespace type or is a subclass of the type, protected methods are included in the results. If protected methods are included and internal is true, private methods are also included.

Examples:

api_map = Solargraph::ApiMap.new
type = Solargraph::ComplexType.parse('String')
api_map.get_complex_type_methods(type)

Parameters:

  • complex_type (Solargraph::ComplexType)

    The complex type of the namespace

  • context (String) (defaults to: '')

    The context from which the type is referenced

  • internal (Boolean) (defaults to: false)

    True to include private methods

Returns:



539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
# File 'lib/solargraph/api_map.rb', line 539

def get_complex_type_methods complex_type, context = '', internal = false
  # This method does not qualify the complex type's namespace because
  # it can cause conflicts between similar names, e.g., `Foo` vs.
  # `Other::Foo`. It still takes a context argument to determine whether
  # protected and private methods are visible.
  return [] if complex_type.undefined? || complex_type.void?
  result = Set.new
  complex_type.each do |type|
    if type.duck_type?
      result.add Pin::DuckMethod.new(name: type.to_s[1..], source: :api_map)
      result.merge get_methods('Object')
    else
      unless type.nil? || type.name == 'void'
        visibility = [:public]
        if type.namespace == context || super_and_sub?(type.namespace, context)
          visibility.push :protected
          visibility.push :private if internal
        end
        result.merge get_methods(type.tag, scope: type.scope, visibility: visibility)
      end
    end
  end
  result.to_a
end

#get_constants(namespace, *contexts) ⇒ Array<Solargraph::Pin::Constant, Solargraph::Pin::Namespace>

Get suggestions for constants in the specified namespace. The result may contain both constant and namespace pins.

Parameters:

  • namespace (String)

    The namespace

  • contexts (Array<String>)

    The contexts

Returns:



312
313
314
315
316
317
318
319
320
321
# File 'lib/solargraph/api_map.rb', line 312

def get_constants namespace, *contexts
  namespace ||= ''
  gates = contexts.clone
  gates.push '' if contexts.empty? && namespace.empty?
  gates.push namespace unless namespace.empty?
  store.constants
       .collect(gates)
       .select { |pin| namespace.empty? || contexts.empty? || pin.namespace == namespace }
       .select { |pin| pin.visibility == :public || pin.namespace == namespace }
end

#get_extends(fqns) ⇒ Array<Pin::Reference::Extend>

Parameters:

  • fqns (String)

Returns:



368
369
370
# File 'lib/solargraph/api_map.rb', line 368

def get_extends fqns
  store.get_extends(fqns)
end

#get_global_variable_pinsEnumerable<Solargraph::Pin::GlobalVariable>

Returns:



437
438
439
# File 'lib/solargraph/api_map.rb', line 437

def get_global_variable_pins
  store.pins_by_class(Pin::GlobalVariable)
end

#get_includes(fqns) ⇒ Array<Pin::Reference::Include>

Parameters:

  • fqns (String)

Returns:



374
375
376
# File 'lib/solargraph/api_map.rb', line 374

def get_includes fqns
  store.get_includes(fqns)
end

#get_instance_variable_pins(namespace, scope = :instance) ⇒ Array<Solargraph::Pin::InstanceVariable>

Get an array of instance variable pins defined in specified namespace and scope.

Parameters:

  • namespace (String)

    A fully qualified namespace

  • scope (Symbol) (defaults to: :instance)

    :instance or :class

Returns:



384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/solargraph/api_map.rb', line 384

def get_instance_variable_pins namespace, scope = :instance
  result = []
  [namespace]
  result.concat store.get_instance_variables(namespace, scope)
  sc_fqns = namespace
  while (sc = store.get_superclass(sc_fqns))
    # @sg-ignore flow sensitive typing needs to handle "if foo = bar"
    sc_fqns = store.constants.dereference(sc)
    result.concat store.get_instance_variables(sc_fqns, scope)
  end
  result
end

#get_method_stack(rooted_tag, name, scope: :instance, visibility: %i[private protected public],, preserve_generics: false) ⇒ Array<Solargraph::Pin::Method>

Get a stack of method pins for a method name in a potentially parameterized namespace. The order of the pins corresponds to the ancestry chain, with highest precedence first.

Examples:

api_map.get_method_stack('Subclass', 'method_name')
  #=> [ <Subclass#method_name pin>, <Superclass#method_name pin> ]

Parameters:

  • rooted_tag (String)

    Parameterized namespace, fully qualified

  • name (String)

    Method name to look up

  • scope (Symbol) (defaults to: :instance)

    :instance or :class

  • visibility (Array<Symbol>) (defaults to: %i[private protected public],)

    :public, :protected, and/or :private

  • preserve_generics (Boolean) (defaults to: false)

    True to preserve any unresolved generic parameters, false to erase them

Returns:



579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
# File 'lib/solargraph/api_map.rb', line 579

def get_method_stack rooted_tag, name, scope: :instance, visibility: %i[private protected public],
                     preserve_generics: false
  rooted_type = ComplexType.parse(rooted_tag)
  fqns = rooted_type.namespace
  namespace_pin = store.get_path_pins(fqns).first
  methods = if namespace_pin.is_a?(Pin::Constant)
              type = namespace_pin.typify(self)
              type = namespace_pin.probe(self) unless type.defined?
              if type.defined?
                namespace_pin = store.get_path_pins(type.namespace).first
                get_methods(type.namespace, scope: scope, visibility: visibility).select { |p| p.name == name }
              else
                []
              end
            else
              get_methods(rooted_tag, scope: scope, visibility: visibility).select { |p| p.name == name }
            end
  methods = erase_generics(namespace_pin, rooted_type, methods) unless preserve_generics
  methods
end

#get_methods(rooted_tag, scope: :instance, visibility: [:public], deep: true) ⇒ Array<Solargraph::Pin::Method>

Get an array of methods available in a particular context.

Parameters:

  • rooted_tag (String)

    The fully qualified namespace to search for methods

  • scope (Symbol) (defaults to: :instance)

    :class or :instance

  • visibility (Array<Symbol>) (defaults to: [:public])

    :public, :protected, and/or :private

  • deep (Boolean) (defaults to: true)

    True to include superclasses, mixins, etc.

Returns:



453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
# File 'lib/solargraph/api_map.rb', line 453

def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
  rooted_type = ComplexType.try_parse(rooted_tag)
  fqns = rooted_type.namespace
  namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
  cached = cache.get_methods(rooted_tag, scope, visibility, deep)
  return cached.clone unless cached.nil?
  # @type [Array<Solargraph::Pin::Method>]
  result = []
  skip = Set.new
  if rooted_tag == ''
    # @todo Implement domains
    conventions_environ.domains.each do |domain|
      type = ComplexType.try_parse(domain)
      next if type.undefined?
      result.concat inner_get_methods(type.name, type.scope, visibility, deep, skip)
    end
    result.concat inner_get_methods(rooted_tag, :class, visibility, deep, skip)
    result.concat inner_get_methods(rooted_tag, :instance, visibility, deep, skip)
    result.concat inner_get_methods('Kernel', :instance, visibility, deep, skip)
  else
    result.concat inner_get_methods(rooted_tag, scope, visibility, deep, skip)
    unless %w[Class Class<Class>].include?(rooted_tag)
      result.map! do |pin|
        next pin unless pin.path == 'Class#new'
        init_pin = get_method_stack(rooted_tag, 'initialize').first
        next pin unless init_pin

        type = ComplexType::SELF
        new_pin = Pin::Method.new(
          name: 'new',
          scope: :class,
          location: init_pin.location,
          return_type: type,
          comments: init_pin.comments,
          closure: init_pin.closure,
          source: init_pin.source,
          type_location: init_pin.type_location
        )
        new_pin.parameters = init_pin.parameters.map do |init_param|
          param = init_param.clone
          param.closure = new_pin
          param.reset_generated!
          param
        end.freeze
        new_pin.signatures = init_pin.signatures.map do |init_sig|
          sig = init_sig.proxy(type)
          sig.parameters = init_sig.parameters.map do |param|
            param = param.clone
            param.closure = new_pin
            param.reset_generated!
            param
          end.freeze
          sig.closure = new_pin
          sig.reset_generated!
          sig
        end.freeze
        new_pin
      end
    end
    result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
    result.concat inner_get_methods('Module', scope, visibility, deep, skip) if scope == :module
  end
  result = resolve_method_aliases(result, visibility)
  if namespace_pin && rooted_tag != rooted_type.name
    result = result.map { |method_pin| method_pin.resolve_generics(namespace_pin, rooted_type) }
  end
  cache.set_methods(rooted_tag, scope, visibility, deep, result)
  result
end

#get_namespace_pins(namespace, context) ⇒ Array<Pin::Namespace>

Parameters:

  • namespace (String)
  • context (String)

Returns:



326
327
328
# File 'lib/solargraph/api_map.rb', line 326

def get_namespace_pins namespace, context
  store.fqns_pins(qualify(namespace, context))
end

#get_path_pins(path) ⇒ Array<Pin::Base>

Get an array of pins that match the specified path.

Parameters:

  • path (String)

Returns:



615
616
617
# File 'lib/solargraph/api_map.rb', line 615

def get_path_pins path
  get_path_suggestions(path)
end

#get_path_suggestions(path) ⇒ Array<Solargraph::Pin::Base>

Deprecated.

Use #get_path_pins instead.

Get an array of all suggestions that match the specified path.

Parameters:

  • path (String)

    The path to find

Returns:



606
607
608
609
# File 'lib/solargraph/api_map.rb', line 606

def get_path_suggestions path
  return [] if path.nil?
  resolve_method_aliases store.get_path_pins(path)
end

#get_symbolsEnumerable<Solargraph::Pin::Base>

Returns:



432
433
434
# File 'lib/solargraph/api_map.rb', line 432

def get_symbols
  store.get_symbols
end

#hashInteger

Returns:

  • (Integer)


66
67
68
# File 'lib/solargraph/api_map.rb', line 66

def hash
  equality_fields.hash
end

#index(pins) ⇒ self

Parameters:

Returns:

  • (self)


83
84
85
86
87
88
89
90
91
# File 'lib/solargraph/api_map.rb', line 83

def index pins
  # @todo This implementation is incomplete. It should probably create a
  #   Bench.
  @source_map_hash = {}
  conventions_environ.clear
  cache.clear
  store.update @@core_map.pins, pins
  self
end

#inner_get_methods_from_reference(fq_reference_tag, namespace_pin, type, scope, visibility, deep, skip, no_core) ⇒ Array<Pin::Base>

Parameters:

  • fq_reference_tag (String)

    A fully qualified whose method should be pulled in

  • namespace_pin (Pin::Base)

    Namespace pin for the rooted_type parameter - used to pull generics information

  • type (ComplexType)

    The type which is having its methods supplemented from fq_reference_tag

  • scope (Symbol)

    :class or :instance

  • visibility (Array<Symbol>)

    :public, :protected, and/or :private

  • deep (Boolean)
  • skip (Set<String>)
  • no_core (Boolean)

    Skip core classes if true

Returns:



773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
# File 'lib/solargraph/api_map.rb', line 773

def inner_get_methods_from_reference fq_reference_tag, namespace_pin, type, scope, visibility, deep, skip, no_core
  logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) starting" }

  # Ensure the types returned by the methods in the referenced
  # type are relative to the generic values passed in the
  # reference.  e.g., Foo<String> might include Enumerable<String>
  #
  # @todo perform the same translation in the other areas
  #  here after adding a spec and handling things correctly
  #  in ApiMap::Store and RbsMap::Conversions for each
  resolved_reference_type = ComplexType.parse(fq_reference_tag).force_rooted.resolve_generics(namespace_pin, type)
  # @todo Can inner_get_methods be cached?  Lots of lookups of base types going on.
  methods = inner_get_methods(resolved_reference_type.tag, scope, visibility, deep, skip, no_core)
  if namespace_pin && !resolved_reference_type.all_params.empty?
    reference_pin = store.get_path_pins(resolved_reference_type.name).select { |p| p.is_a?(Pin::Namespace) }.first
    # logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolving generics with #{reference_pin.generics}, #{resolved_reference_type.rooted_tags}" }
    methods = methods.map do |method_pin|
      method_pin.resolve_generics(reference_pin, resolved_reference_type)
    end
  end
  # logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolved_reference_type: #{resolved_reference_type} for type=#{type}: #{methods.map(&:name)}" }
  methods
end

#inspectObject

avoid enormous dump



77
78
79
# File 'lib/solargraph/api_map.rb', line 77

def inspect
  to_s
end

#keyword_pinsEnumerable<Solargraph::Pin::Keyword>

An array of pins based on Ruby keywords (‘if`, `end`, etc.).

Returns:



287
288
289
# File 'lib/solargraph/api_map.rb', line 287

def keyword_pins
  store.pins_by_class(Pin::Keyword)
end

#locate_pins(location) ⇒ Array<Solargraph::Pin::Base>

Parameters:

Returns:



654
655
656
657
# File 'lib/solargraph/api_map.rb', line 654

def locate_pins location
  return [] if location.nil? || !source_map_hash.key?(location.filename)
  resolve_method_aliases source_map_hash[location.filename].locate_pins(location)
end

#map(source, live: false) ⇒ self

Map a single source.

Parameters:

  • source (Source)
  • live (Boolean) (defaults to: false)

    True for live source map (active editor file)

Returns:

  • (self)


98
99
100
101
102
# File 'lib/solargraph/api_map.rb', line 98

def map source, live: false
  map = Solargraph::SourceMap.map(source)
  catalog Bench.new(source_maps: [map], live_map: live ? map : nil)
  self
end

#named_macro(name) ⇒ Solargraph::YardMap::Macro?

Parameters:

  • name (String, nil)

Returns:



190
191
192
193
# File 'lib/solargraph/api_map.rb', line 190

def named_macro name
  # @sg-ignore Need to add nil check here
  store.named_macros[name]
end

#namespace_exists?(name, context = '') ⇒ Boolean

True if the namespace exists.

Parameters:

  • name (String)

    The namespace to match

  • context (String) (defaults to: '')

    The context to search

Returns:

  • (Boolean)


302
303
304
# File 'lib/solargraph/api_map.rb', line 302

def namespace_exists? name, context = ''
  !qualify(name, context).nil?
end

#pinsArray<Solargraph::Pin::Base>

Returns:



280
281
282
# File 'lib/solargraph/api_map.rb', line 280

def pins
  store.pins.clone.freeze
end

#process_macrosArray<Pin::Base>

Returns:



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/solargraph/api_map.rb', line 136

def process_macros
  macro_pins = []
  Solargraph.logger.debug { "ApiMap#process_macros: processing macros for #{source_maps.size} source maps" }
  Solargraph.logger.debug { "ApiMap#process_macros: store has #{store.macro_method_name_pins.size} macro method name pins" }
  Solargraph.logger.debug { "ApiMap#process_macros: named macros: #{store.named_macros.keys.join(', ')}" }
  source_maps.each do |source_map|
    method_candidates = source_map.macro_method_candidates(store.macro_method_names)
    Solargraph.logger.debug { "ApiMap#process_macros: processing source map for #{source_map.filename} with #{method_candidates.size} macro method candidates" }
    method_candidates.each do |node|
      closure = source_map.locate_closure_pin(node.location.line, node.location.column)
      chain = Solargraph::Parser::ParserGem::NodeChainer.chain(node)
      if node.children[0].nil? && store.macro_method_name_pins.key?(node.children[1].to_s)
        match = store.macro_method_name_pins[node.children[1].to_s].find do |pin|
          super_and_sub?(pin.namespace, closure.name)
        end
        if match
          match.macros.each do |macro|
            macro_pins.concat macro.generate_pins_from(chain, match, source_map)
          end
          next
        end
      end
    end
  end
  macro_pins
end

#qualify(tag, *gates) ⇒ String?

Determine fully qualified tag for a given tag used inside the definition of another tag (“context”). This method will start the search in the specified context until it finds a match for the tag.

Does not recurse into qualifying the type parameters, but returns any which were passed in unchanged.

Parameters:

  • tag (String, nil)

    The namespace to match, complete with generic parameters set to appropriate values if available

  • gates (Array<String>)

    The fully qualified context in which the tag was referenced; start from here to resolve the name. Should not be prefixed with ‘::’.

Returns:

  • (String, nil)

    fully qualified tag



345
346
347
# File 'lib/solargraph/api_map.rb', line 345

def qualify tag, *gates
  store.constants.qualify(tag, *gates)
end

#qualify_superclass(fq_sub_tag) ⇒ String?

Parameters:

  • fq_sub_tag (String)

Returns:

  • (String, nil)


799
800
801
# File 'lib/solargraph/api_map.rb', line 799

def qualify_superclass fq_sub_tag
  store.qualify_superclass fq_sub_tag
end

#query_symbols(query) ⇒ Array<Pin::Base>

Get an array of all symbols in the workspace that match the query.

Parameters:

  • query (String)

Returns:



645
646
647
648
649
650
# File 'lib/solargraph/api_map.rb', line 645

def query_symbols query
  Pin::Search.new(
    source_map_hash.values.flat_map(&:document_symbols),
    query
  ).results
end

#requiredSet<String>

Returns:

  • (Set<String>)


196
197
198
# File 'lib/solargraph/api_map.rb', line 196

def required
  @required ||= Set.new
end

#resolve(name, *gates) ⇒ String?

Parameters:

  • name (String)
  • gates (Array<String, Array<String>>)

Returns:

  • (String, nil)

See Also:

  • Store::Constants#resolve


354
355
356
# File 'lib/solargraph/api_map.rb', line 354

def resolve name, *gates
  store.constants.resolve(name, *gates)
end

#resolve_method_aliases(pins, visibility = %i[public private protected]) ⇒ Array<Pin::Base>

Parameters:

  • pins (Enumerable<Pin::Base>)
  • visibility (Enumerable<Symbol>) (defaults to: %i[public private protected])

Returns:



743
744
745
746
747
748
749
750
751
752
753
754
755
# File 'lib/solargraph/api_map.rb', line 743

def resolve_method_aliases pins, visibility = %i[public private protected]
  with_resolved_aliases = pins.map do |pin|
    next pin unless pin.is_a?(Pin::MethodAlias)
    resolved = resolve_method_alias(pin)
    # @sg-ignore Need to add nil check here
    next nil if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
    resolved
  end.compact
  logger.debug do
    "ApiMap#resolve_method_aliases(pins=#{pins.map(&:name)}, visibility=#{visibility}) => #{with_resolved_aliases.map(&:name)}"
  end
  with_resolved_aliases
end

#search(query) ⇒ Array<String>

Get a list of documented paths that match the query.

Examples:

api_map.query('str') # Results will include `String` and `Struct`

Parameters:

  • query (String)

    The text to match

Returns:

  • (Array<String>)


626
627
628
629
630
# File 'lib/solargraph/api_map.rb', line 626

def search query
  pins.map(&:path)
      .compact
      .select { |path| path.downcase.include?(query.downcase) }
end

#source_map(filename) ⇒ SourceMap

Get a source map by filename.

Parameters:

  • filename (String)

Returns:

Raises:



686
687
688
689
# File 'lib/solargraph/api_map.rb', line 686

def source_map filename
  raise FileNotFoundError, "Source map for `#{filename}` not found" unless source_map_hash.key?(filename)
  source_map_hash[filename]
end

#source_mapsArray<SourceMap>

Returns:



678
679
680
# File 'lib/solargraph/api_map.rb', line 678

def source_maps
  source_map_hash.values
end

#super_and_sub?(sup, sub) ⇒ Boolean

Check if a class is a superclass of another class.

Parameters:

  • sup (String)

    The superclass

  • sub (String)

    The subclass

Returns:

  • (Boolean)


704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
# File 'lib/solargraph/api_map.rb', line 704

def super_and_sub? sup, sub
  sup = ComplexType.try_parse(sup)
  sub = ComplexType.try_parse(sub)
  # @todo If two literals are different values of the same type, it would
  #   make more sense for super_and_sub? to return true, but there are a
  #   few callers that currently expect this to be false.
  # @sg-ignore flow-sensitive typing should be able to handle redefinition
  return false if sup.literal? && sub.literal? && sup.to_s != sub.to_s
  # @sg-ignore flow sensitive typing should be able to handle redefinition
  sup = sup.simplify_literals.to_s
  # @sg-ignore flow sensitive typing should be able to handle redefinition
  sub = sub.simplify_literals.to_s
  return true if sup == sub
  sc_fqns = sub
  while (sc = store.get_superclass(sc_fqns))
    # @sg-ignore flow sensitive typing needs to handle "if foo = bar"
    sc_new = store.constants.dereference(sc)
    # Cyclical inheritance is invalid
    return false if sc_new == sc_fqns
    sc_fqns = sc_new
    return true if sc_fqns == sup
  end
  false
end

#to_sObject



72
73
74
# File 'lib/solargraph/api_map.rb', line 72

def to_s
  self.class.to_s
end

#type_include?(host_ns, module_ns) ⇒ Boolean

Check if the host class includes the specified module, ignoring type parameters used.

Parameters:

  • host_ns (String)

    The class namesapce (no type parameters)

  • module_ns (String)

    The module namespace (no type parameters)

Returns:

  • (Boolean)


736
737
738
# File 'lib/solargraph/api_map.rb', line 736

def type_include? host_ns, module_ns
  store.get_includes(host_ns).map { |inc_tag| inc_tag.type.name }.include?(module_ns)
end

#unalias(name) ⇒ ComplexType?

Parameters:

  • name (String)

Returns:



293
294
295
# File 'lib/solargraph/api_map.rb', line 293

def unalias name
  store.unalias(name)
end

#uncached_gemspecs::Array<Gem::Specification>

Returns:

  • (::Array<Gem::Specification>)


169
170
171
# File 'lib/solargraph/api_map.rb', line 169

def uncached_gemspecs
  doc_map.uncached_gemspecs || []
end

#uncached_rbs_collection_gemspecs::Array<Gem::Specification>

Returns:

  • (::Array<Gem::Specification>)


174
175
176
# File 'lib/solargraph/api_map.rb', line 174

def uncached_rbs_collection_gemspecs
  @doc_map.uncached_rbs_collection_gemspecs
end

#uncached_yard_gemspecs::Array<Gem::Specification>

Returns:

  • (::Array<Gem::Specification>)


179
180
181
# File 'lib/solargraph/api_map.rb', line 179

def uncached_yard_gemspecs
  @doc_map.uncached_yard_gemspecs
end

#var_at_location(candidates, name, closure, location) ⇒ Pin::BaseVariable?

Find a variable pin by name and where it is used.

Resolves our most specific view of this variable’s type by preferring pins created by flow-sensitive typing when we have them based on the Closure and Location.

Parameters:

Returns:



409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/solargraph/api_map.rb', line 409

def var_at_location candidates, name, closure, location
  # @todo Location can be nil if clips have trouble finding node recipients
  return unless location

  with_correct_name = candidates.select { |pin| pin.name == name }
  vars_at_location = with_correct_name.reject do |pin|
    # visible_at? excludes the starting position, but we want to
    # include it for this purpose
    !pin.visible_at?(closure, location) && !pin.starts_at?(location)
  end

  vars_at_location.inject(&:combine_with)
end

#workspaceWorkspace?

Returns:



758
759
760
# File 'lib/solargraph/api_map.rb', line 758

def workspace
  doc_map.workspace
end