solargraph 0.55.3 → 0.55.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +2 -0
  3. data/.github/workflows/typecheck.yml +3 -1
  4. data/.gitignore +2 -0
  5. data/CHANGELOG.md +7 -1
  6. data/README.md +13 -3
  7. data/lib/solargraph/api_map/index.rb +23 -15
  8. data/lib/solargraph/api_map/store.rb +8 -4
  9. data/lib/solargraph/api_map.rb +150 -57
  10. data/lib/solargraph/complex_type/type_methods.rb +6 -1
  11. data/lib/solargraph/complex_type/unique_type.rb +10 -2
  12. data/lib/solargraph/convention/base.rb +3 -3
  13. data/lib/solargraph/convention.rb +3 -3
  14. data/lib/solargraph/doc_map.rb +192 -46
  15. data/lib/solargraph/gem_pins.rb +53 -37
  16. data/lib/solargraph/language_server/host.rb +11 -2
  17. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  18. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  19. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  20. data/lib/solargraph/library.rb +7 -4
  21. data/lib/solargraph/location.rb +13 -0
  22. data/lib/solargraph/logging.rb +1 -0
  23. data/lib/solargraph/parser/comment_ripper.rb +1 -0
  24. data/lib/solargraph/parser/flow_sensitive_typing.rb +2 -1
  25. data/lib/solargraph/parser/node_processor.rb +3 -1
  26. data/lib/solargraph/parser/parser_gem/class_methods.rb +5 -8
  27. data/lib/solargraph/parser/parser_gem/node_methods.rb +1 -1
  28. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  29. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
  30. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +4 -2
  31. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +4 -3
  32. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  33. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  34. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  35. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  36. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  37. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  38. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +6 -4
  39. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  40. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
  41. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +28 -16
  42. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +2 -1
  43. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +1 -0
  44. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +1 -0
  45. data/lib/solargraph/parser/region.rb +1 -1
  46. data/lib/solargraph/pin/base.rb +295 -28
  47. data/lib/solargraph/pin/base_variable.rb +9 -8
  48. data/lib/solargraph/pin/callable.rb +74 -3
  49. data/lib/solargraph/pin/closure.rb +18 -1
  50. data/lib/solargraph/pin/common.rb +5 -0
  51. data/lib/solargraph/pin/delegated_method.rb +2 -0
  52. data/lib/solargraph/pin/documenting.rb +16 -0
  53. data/lib/solargraph/pin/keyword.rb +7 -2
  54. data/lib/solargraph/pin/local_variable.rb +8 -5
  55. data/lib/solargraph/pin/method.rb +147 -25
  56. data/lib/solargraph/pin/namespace.rb +7 -2
  57. data/lib/solargraph/pin/parameter.rb +47 -6
  58. data/lib/solargraph/pin/proxy_type.rb +3 -3
  59. data/lib/solargraph/pin/reference/override.rb +10 -6
  60. data/lib/solargraph/pin/reference/require.rb +2 -2
  61. data/lib/solargraph/pin/signature.rb +42 -0
  62. data/lib/solargraph/pin/singleton.rb +1 -1
  63. data/lib/solargraph/pin/symbol.rb +3 -2
  64. data/lib/solargraph/pin.rb +1 -1
  65. data/lib/solargraph/pin_cache.rb +185 -0
  66. data/lib/solargraph/position.rb +9 -0
  67. data/lib/solargraph/range.rb +9 -0
  68. data/lib/solargraph/rbs_map/conversions.rb +183 -56
  69. data/lib/solargraph/rbs_map/core_fills.rb +24 -15
  70. data/lib/solargraph/rbs_map/core_map.rb +34 -11
  71. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  72. data/lib/solargraph/rbs_map.rb +74 -17
  73. data/lib/solargraph/shell.rb +12 -15
  74. data/lib/solargraph/source/chain/array.rb +7 -4
  75. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  76. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  77. data/lib/solargraph/source/chain/call.rb +8 -7
  78. data/lib/solargraph/source/chain/hash.rb +1 -1
  79. data/lib/solargraph/source/chain/head.rb +1 -1
  80. data/lib/solargraph/source/chain/if.rb +1 -1
  81. data/lib/solargraph/source/chain/literal.rb +2 -2
  82. data/lib/solargraph/source/chain/or.rb +1 -1
  83. data/lib/solargraph/source/chain.rb +2 -2
  84. data/lib/solargraph/source_map/mapper.rb +9 -5
  85. data/lib/solargraph/source_map.rb +0 -17
  86. data/lib/solargraph/version.rb +1 -1
  87. data/lib/solargraph/views/_method.erb +10 -10
  88. data/lib/solargraph/views/_namespace.erb +3 -3
  89. data/lib/solargraph/views/document.erb +10 -10
  90. data/lib/solargraph/workspace.rb +15 -5
  91. data/lib/solargraph/yard_map/mapper/to_constant.rb +4 -2
  92. data/lib/solargraph/yard_map/mapper/to_method.rb +14 -1
  93. data/lib/solargraph/yard_map/mapper/to_namespace.rb +4 -2
  94. data/lib/solargraph/yard_map/mapper.rb +4 -3
  95. data/lib/solargraph/yard_map/to_method.rb +4 -2
  96. data/lib/solargraph/yardoc.rb +3 -11
  97. data/lib/solargraph.rb +18 -1
  98. data/rbs/fills/tuple.rbs +150 -0
  99. data/rbs_collection.yaml +19 -0
  100. data/solargraph.gemspec +1 -0
  101. metadata +20 -7
  102. data/lib/solargraph/cache.rb +0 -77
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b92431804c7f970e2e2584375047eedef4155a24ac07e37dd0cfd5b9f3a4b562
4
- data.tar.gz: e60ed915ee5ff35d91e66d0d15287d8a58f7c295080041d601c833092767bde9
3
+ metadata.gz: 9e015963ad868b3671d88892483ec3c06a3e7c96757f2013ba56c514af35eb0e
4
+ data.tar.gz: 22a6383d6f179ec708a930fbf8cb81bea8cbbee694de559f43208c859240a0cd
5
5
  SHA512:
6
- metadata.gz: e4d6a6fd86d4942dac41fbfe67d7860ed1bdc9534414c26adae8bba3b6cf2a402691a0de5adaf89fcf49fbb8d11fba81230d683ec4b7aed01c5b0a73671dd3fa
7
- data.tar.gz: 1b12d4bfbdb9bcca0e87585fc985252ec6d343929b16f9317f12223f8e6d2d413ebb6a9674911eb09189c817703c35fbe5acb3c364666cb1f05dadd188279940
6
+ metadata.gz: cd7b151efc8a584829cdc5c4424c81dd3703dd22f8287c8edfcfc32d65b8409e8be9d8354ed5369c6fa0955cc1ccd534014f6782aa71ca7b0a89c5df8a0d9b06
7
+ data.tar.gz: 818390cee111c7948e40904e1eb48dd407dd8f15045a29b96881e6bb520022438d9fca6a7ec678dbc6d793f74b3bcdaf17d4b152e86bb5b1f563f1703423a7ed
@@ -34,6 +34,8 @@ jobs:
34
34
  bundle exec solargraph config
35
35
  yq -yi '.plugins += ["solargraph-rails"]' .solargraph.yml
36
36
  yq -yi '.plugins += ["solargraph-rspec"]' .solargraph.yml
37
+ - name: Install gem types
38
+ run: bundle exec rbs collection install
37
39
  - name: Ensure typechecking still works
38
40
  run: bundle exec solargraph typecheck --level typed
39
41
  - name: Ensure specs still run
@@ -30,5 +30,7 @@ jobs:
30
30
  bundler-cache: false
31
31
  - name: Install gems
32
32
  run: bundle install
33
+ - name: Install gem types
34
+ run: bundle exec rbs collection install
33
35
  - name: Typecheck self
34
- run: bundle exec solargraph typecheck --level typed
36
+ run: SOLARGRAPH_ASSERTS=on bundle exec solargraph typecheck --level typed
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
+ /.gem_rbs_collection
2
+ /rbs_collection.lock.yaml
1
3
  /Gemfile.lock
2
4
  .Gemfile
3
5
  .idea
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
+ ## 0.55.5 - July 1, 2025
2
+ - Ignore directory paths in Workspace#would_require? (#988)
3
+
4
+ ## 0.55.4 - June 27, 2025
5
+ - Flatten results of DocMap external bundle query (#981)
6
+
1
7
  ## 0.55.3 - June 25, 2025
2
- - Nil guards in flow-sensitive typing (patch release) #980
8
+ - Nil guards in flow-sensitive typing (patch release) (#980)
3
9
 
4
10
  ## 0.55.2 - June 21, 2025
5
11
  - Require external bundle (#972)
data/README.md CHANGED
@@ -63,12 +63,22 @@ The RSpec framework is supported via [solargraph-rspec](https://github.com/lekem
63
63
 
64
64
  **Note: Before version 0.53.0, it was recommended to run `yard gems` periodically or automate it with `yard config` to ensure that Solargraph had access to gem documentation. These steps are no longer necessary. Solargraph maintains its own gem documentation cache independent of the yardocs in your gem installations.**
65
65
 
66
- Solargraph automatically generates code maps from installed gems. You can also manage your cached gem documentation with the `solargraph gems` command.
67
-
68
- When editing code, a `require` call that references a gem will pull the documentation into the code maps and include the gem's API in code completion and intellisense.
66
+ When editing code, a `require` call that references a gem will pull the documentation into the code maps and include the gem's API in code completion and intellisense. Solargraph automatically generates code maps from installed gems, based on the YARD or RBS type information inside the gem. You can also eagerly cache gem documentation with the `solargraph gems` command.
69
67
 
70
68
  If your project automatically requires bundled gems (e.g., `require 'bundler/require'`), Solargraph will add all of the Gemfile's default dependencies to the map.
71
69
 
70
+ To ensure you have types for gems which contain neither RBS nor YARD
71
+ information, use
72
+ [gem\_rbs\_collection](https://github.com/ruby/gem_rbs_collection) to
73
+ install a community-supported set of RBS types for various gems:
74
+
75
+ ```sh
76
+ bundle exec rbs collection init
77
+ bundle exec rbs collection install
78
+ ```
79
+
80
+ Once installed, you can also insert your own local overrides and definitions in RBS in a directory configured in the `rbs_collection.yaml` that the above commands create.
81
+
72
82
  ### Type Checking
73
83
 
74
84
  As of version 0.33.0, Solargraph includes a [type checker](https://github.com/castwide/solargraph/issues/192) that uses a combination of YARD tags and code analysis to report missing type definitions. In strict mode, it performs type inference to determine whether the tags match the types it detects from code.
@@ -3,6 +3,8 @@
3
3
  module Solargraph
4
4
  class ApiMap
5
5
  class Index
6
+ include Logging
7
+
6
8
  # @param pins [Array<Pin::Base>]
7
9
  def initialize pins = []
8
10
  catalog pins
@@ -132,21 +134,24 @@ module Solargraph
132
134
  # @return [void]
133
135
  def map_overrides
134
136
  pins_by_class(Pin::Reference::Override).each do |ovr|
135
- pin = path_pin_hash[ovr.name].first
136
- next if pin.nil?
137
- new_pin = if pin.path.end_with?('#initialize')
138
- path_pin_hash[pin.path.sub(/#initialize/, '.new')].first
139
- end
140
- (ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
141
- pin.docstring.delete_tags tag
142
- new_pin.docstring.delete_tags tag if new_pin
143
- end
144
- ovr.tags.each do |tag|
145
- pin.docstring.add_tag(tag)
146
- redefine_return_type pin, tag
147
- if new_pin
148
- new_pin.docstring.add_tag(tag)
149
- redefine_return_type new_pin, tag
137
+ logger.debug { "ApiMap::Index#map_overrides: Looking at override #{ovr} for #{ovr.name}" }
138
+ pins = path_pin_hash[ovr.name]
139
+ logger.debug { "ApiMap::Index#map_overrides: pins for path=#{ovr.name}: #{pins}" }
140
+ pins.each do |pin|
141
+ new_pin = if pin.path.end_with?('#initialize')
142
+ path_pin_hash[pin.path.sub(/#initialize/, '.new')].first
143
+ end
144
+ (ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
145
+ pin.docstring.delete_tags tag
146
+ new_pin.docstring.delete_tags tag if new_pin
147
+ end
148
+ ovr.tags.each do |tag|
149
+ pin.docstring.add_tag(tag)
150
+ redefine_return_type pin, tag
151
+ if new_pin
152
+ new_pin.docstring.add_tag(tag)
153
+ redefine_return_type new_pin, tag
154
+ end
150
155
  end
151
156
  end
152
157
  end
@@ -156,11 +161,14 @@ module Solargraph
156
161
  # @param tag [YARD::Tags::Tag]
157
162
  # @return [void]
158
163
  def redefine_return_type pin, tag
164
+ # @todo can this be made to not mutate existing pins and use
165
+ # proxy() / proxy_with_signatures() instead?
159
166
  return unless pin && tag.tag_name == 'return'
160
167
  pin.instance_variable_set(:@return_type, ComplexType.try_parse(tag.type))
161
168
  pin.signatures.each do |sig|
162
169
  sig.instance_variable_set(:@return_type, ComplexType.try_parse(tag.type))
163
170
  end
171
+ pin.reset_generated!
164
172
  end
165
173
  end
166
174
  end
@@ -61,15 +61,19 @@ module Solargraph
61
61
  # @param visibility [Array<Symbol>]
62
62
  # @return [Enumerable<Solargraph::Pin::Method>]
63
63
  def get_methods fqns, scope: :instance, visibility: [:public]
64
- namespace_children(fqns).select do |pin|
64
+ all_pins = namespace_children(fqns).select do |pin|
65
65
  pin.is_a?(Pin::Method) && pin.scope == scope && visibility.include?(pin.visibility)
66
66
  end
67
+ GemPins.combine_method_pins_by_path(all_pins)
67
68
  end
68
69
 
69
- # @param fqns [String]
70
+ # @param fq_tag [String]
70
71
  # @return [String, nil]
71
- def get_superclass fqns
72
- raise "Do not prefix fully qualified namespaces with '::' - #{fqns.inspect}" if fqns.start_with?('::')
72
+ def get_superclass fq_tag
73
+ raise "Do not prefix fully qualified tags with '::' - #{fq_tag.inspect}" if fq_tag.start_with?('::')
74
+ sub = ComplexType.parse(fq_tag)
75
+ fqns = sub.namespace
76
+ return superclass_references[fq_tag].first if superclass_references.key?(fq_tag)
73
77
  return superclass_references[fqns].first if superclass_references.key?(fqns)
74
78
  return 'Object' if fqns != 'BasicObject' && namespace_exists?(fqns)
75
79
  return 'Object' if fqns == 'Boolean'
@@ -93,9 +93,13 @@ module Solargraph
93
93
  implicit.merge map.environ
94
94
  end
95
95
  unresolved_requires = (bench.external_requires + implicit.requires + bench.workspace.config.required).to_a.compact.uniq
96
- if @unresolved_requires != unresolved_requires || @doc_map&.uncached_gemspecs&.any?
96
+ recreate_docmap = @unresolved_requires != unresolved_requires ||
97
+ @doc_map&.uncached_yard_gemspecs&.any? ||
98
+ @doc_map&.uncached_rbs_collection_gemspecs&.any? ||
99
+ @doc_map&.rbs_collection_path != bench.workspace.rbs_collection_path
100
+ if recreate_docmap
97
101
  @doc_map = DocMap.new(unresolved_requires, [], bench.workspace) # @todo Implement gem preferences
98
- @unresolved_requires = unresolved_requires
102
+ @unresolved_requires = @doc_map.unresolved_requires
99
103
  end
100
104
  @cache.clear if store.update(@@core_map.pins, @doc_map.pins, implicit.pins, iced_pins, live_pins)
101
105
  @missing_docs = [] # @todo Implement missing docs
@@ -109,11 +113,25 @@ module Solargraph
109
113
  [self.class, @source_map_hash, implicit, @doc_map, @unresolved_requires]
110
114
  end
111
115
 
116
+ def doc_map
117
+ @doc_map ||= DocMap.new([], [])
118
+ end
119
+
112
120
  # @return [::Array<Gem::Specification>]
113
121
  def uncached_gemspecs
114
122
  @doc_map&.uncached_gemspecs || []
115
123
  end
116
124
 
125
+ # @return [::Array<Gem::Specification>]
126
+ def uncached_rbs_collection_gemspecs
127
+ @doc_map.uncached_rbs_collection_gemspecs
128
+ end
129
+
130
+ # @return [::Array<Gem::Specification>]
131
+ def uncached_yard_gemspecs
132
+ @doc_map.uncached_yard_gemspecs
133
+ end
134
+
117
135
  # @return [Array<Pin::Base>]
118
136
  def core_pins
119
137
  @@core_map.pins
@@ -168,6 +186,18 @@ module Solargraph
168
186
  api_map
169
187
  end
170
188
 
189
+ def cache_all!(out)
190
+ @doc_map.cache_all!(out)
191
+ end
192
+
193
+ def cache_gem(gemspec, rebuild: false, out: nil)
194
+ @doc_map.cache(gemspec, rebuild: rebuild, out: out)
195
+ end
196
+
197
+ class << self
198
+ include Logging
199
+ end
200
+
171
201
  # Create an ApiMap with a workspace in the specified directory and cache
172
202
  # any missing gems.
173
203
  #
@@ -178,15 +208,14 @@ module Solargraph
178
208
  # @param directory [String]
179
209
  # @param out [IO] The output stream for messages
180
210
  # @return [ApiMap]
181
- def self.load_with_cache directory, out = IO::NULL
211
+ def self.load_with_cache directory, out
182
212
  api_map = load(directory)
183
- return api_map if api_map.uncached_gemspecs.empty?
184
-
185
- api_map.uncached_gemspecs.each do |gemspec|
186
- out.puts "Caching gem #{gemspec.name} #{gemspec.version}"
187
- pins = GemPins.build(gemspec)
188
- Solargraph::Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
213
+ if api_map.uncached_gemspecs.empty?
214
+ logger.info { "All gems cached for #{directory}" }
215
+ return api_map
189
216
  end
217
+
218
+ api_map.cache_all!(out)
190
219
  load(directory)
191
220
  end
192
221
 
@@ -359,6 +388,11 @@ module Solargraph
359
388
  # @param deep [Boolean] True to include superclasses, mixins, etc.
360
389
  # @return [Array<Solargraph::Pin::Method>]
361
390
  def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
391
+ if rooted_tag.start_with? 'Array('
392
+ # Array() are really tuples - use our fill, as the RBS repo
393
+ # does not give us definitions for it
394
+ rooted_tag = "Solargraph::Fills::Tuple(#{rooted_tag[6..-2]})"
395
+ end
362
396
  rooted_type = ComplexType.try_parse(rooted_tag)
363
397
  fqns = rooted_type.namespace
364
398
  namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
@@ -386,18 +420,35 @@ module Solargraph
386
420
  next pin unless init_pin
387
421
 
388
422
  type = ComplexType::SELF
389
- Pin::Method.new(
423
+ new_pin = Pin::Method.new(
390
424
  name: 'new',
391
425
  scope: :class,
392
426
  location: init_pin.location,
393
- parameters: init_pin.parameters,
394
- signatures: init_pin.signatures.map { |sig| sig.proxy(type) },
395
427
  return_type: type,
396
428
  comments: init_pin.comments,
397
429
  closure: init_pin.closure,
398
430
  source: init_pin.source,
399
431
  type_location: init_pin.type_location,
400
432
  )
433
+ new_pin.parameters = init_pin.parameters.map do |init_param|
434
+ param = init_param.clone
435
+ param.closure = new_pin
436
+ param.reset_generated!
437
+ param
438
+ end.freeze
439
+ new_pin.signatures = init_pin.signatures.map do |init_sig|
440
+ sig = init_sig.proxy(type)
441
+ sig.parameters = init_sig.parameters.map do |param|
442
+ param = param.clone
443
+ param.closure = new_pin
444
+ param.reset_generated!
445
+ param
446
+ end.freeze
447
+ sig.closure = new_pin
448
+ sig.reset_generated!
449
+ sig
450
+ end.freeze
451
+ new_pin
401
452
  end
402
453
  end
403
454
  result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
@@ -436,7 +487,7 @@ module Solargraph
436
487
  result = Set.new
437
488
  complex_type.each do |type|
438
489
  if type.duck_type?
439
- result.add Pin::DuckMethod.new(name: type.to_s[1..-1])
490
+ result.add Pin::DuckMethod.new(name: type.to_s[1..-1], source: :api_map)
440
491
  result.merge get_methods('Object')
441
492
  else
442
493
  unless type.nil? || type.name == 'void'
@@ -505,13 +556,8 @@ module Solargraph
505
556
  .select { |path| path.downcase.include?(query.downcase) }
506
557
  end
507
558
 
508
- # Get YARD documentation for the specified path.
509
- #
510
- # @example
511
- # api_map.document('String#split')
512
- #
513
- # @todo This method is likely superfluous. Calling get_path_pins directly
514
- # should be sufficient.
559
+ # @deprecated This method is likely superfluous. Calling #get_path_pins
560
+ # directly should be sufficient.
515
561
  #
516
562
  # @param path [String] The path to find
517
563
  # @return [Enumerable<Pin::Base>]
@@ -605,6 +651,19 @@ module Solargraph
605
651
  store.get_includes(host_ns).map { |inc_tag| ComplexType.parse(inc_tag).name }.include?(module_ns)
606
652
  end
607
653
 
654
+ # @param pins [Enumerable<Pin::Base>]
655
+ # @param visibility [Enumerable<Symbol>]
656
+ # @return [Array<Pin::Base>]
657
+ def resolve_method_aliases pins, visibility = [:public, :private, :protected]
658
+ with_resolved_aliases = pins.map do |pin|
659
+ resolved = resolve_method_alias(pin)
660
+ next nil if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
661
+ resolved
662
+ end.compact
663
+ logger.debug { "ApiMap#resolve_method_aliases(pins=#{pins.map(&:name)}, visibility=#{visibility}) => #{with_resolved_aliases.map(&:name)}" }
664
+ GemPins.combine_method_pins_by_path(with_resolved_aliases)
665
+ end
666
+
608
667
  private
609
668
 
610
669
  # A hash of source maps with filename keys.
@@ -653,29 +712,20 @@ module Solargraph
653
712
  if scope == :instance
654
713
  store.get_includes(fqns).reverse.each do |include_tag|
655
714
  rooted_include_tag = qualify(include_tag, rooted_tag)
656
- # Ensure the types returned by the included methods are
657
- # relative to the generics passed to the include. e.g.,
658
- # Foo<String> might include Enumerable<String>
659
- #
660
- # @todo perform the same translation in the other areas
661
- # here after adding a spec and handling things correctly
662
- # in ApiMap::Store and RbsMap::Conversions
663
- resolved_include_type = ComplexType.parse(rooted_include_tag).force_rooted.resolve_generics(namespace_pin, rooted_type)
664
- methods = inner_get_methods(resolved_include_type.tag, scope, visibility, deep, skip, true)
665
- result.concat methods
715
+ result.concat inner_get_methods_from_reference(rooted_include_tag, namespace_pin, rooted_type, scope, visibility, deep, skip, true)
666
716
  end
667
- fqsc = qualify_superclass(fqns)
668
- unless fqsc.nil?
669
- result.concat inner_get_methods(fqsc, scope, visibility, true, skip, no_core) unless fqsc.nil?
717
+ rooted_sc_tag = qualify_superclass(rooted_tag)
718
+ unless rooted_sc_tag.nil?
719
+ result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope, visibility, true, skip, no_core)
670
720
  end
671
721
  else
672
722
  store.get_extends(fqns).reverse.each do |em|
673
723
  fqem = qualify(em, fqns)
674
724
  result.concat inner_get_methods(fqem, :instance, visibility, deep, skip, true) unless fqem.nil?
675
725
  end
676
- fqsc = qualify_superclass(fqns)
677
- unless fqsc.nil?
678
- result.concat inner_get_methods(fqsc, scope, visibility, true, skip, true) unless fqsc.nil?
726
+ rooted_sc_tag = qualify_superclass(rooted_tag)
727
+ unless rooted_sc_tag.nil?
728
+ result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope, visibility, true, skip, true)
679
729
  end
680
730
  unless no_core || fqns.empty?
681
731
  type = get_namespace_type(fqns)
@@ -691,6 +741,41 @@ module Solargraph
691
741
  result
692
742
  end
693
743
 
744
+ # @param fq_reference_tag [String] A fully qualified whose method should be pulled in
745
+ # @param namespace_pin [Pin::Base] Namespace pin for the rooted_type
746
+ # parameter - used to pull generics information
747
+ # @param type [ComplexType] The type which is having its
748
+ # methods supplemented from fq_reference_tag
749
+ # @param scope [Symbol] :class or :instance
750
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
751
+ # @param deep [Boolean]
752
+ # @param skip [Set<String>]
753
+ # @param no_core [Boolean] Skip core classes if true
754
+ # @return [Array<Pin::Base>]
755
+ def inner_get_methods_from_reference(fq_reference_tag, namespace_pin, type, scope, visibility, deep, skip, no_core)
756
+ # logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) starting" }
757
+
758
+ # Ensure the types returned by the methods in the referenced
759
+ # type are relative to the generic values passed in the
760
+ # reference. e.g., Foo<String> might include Enumerable<String>
761
+ #
762
+ # @todo perform the same translation in the other areas
763
+ # here after adding a spec and handling things correctly
764
+ # in ApiMap::Store and RbsMap::Conversions for each
765
+ resolved_reference_type = ComplexType.parse(fq_reference_tag).force_rooted.resolve_generics(namespace_pin, type)
766
+ # @todo Can inner_get_methods be cached? Lots of lookups of base types going on.
767
+ methods = inner_get_methods(resolved_reference_type.tag, scope, visibility, deep, skip, no_core)
768
+ if namespace_pin && !resolved_reference_type.all_params.empty?
769
+ reference_pin = store.get_path_pins(resolved_reference_type.name).select { |p| p.is_a?(Pin::Namespace) }.first
770
+ # logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolving generics with #{reference_pin.generics}, #{resolved_reference_type.rooted_tags}" }
771
+ methods = methods.map do |method_pin|
772
+ method_pin.resolve_generics(reference_pin, resolved_reference_type)
773
+ end
774
+ end
775
+ # logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolved_reference_type: #{resolved_reference_type} for type=#{type}: #{methods.map(&:name)}" }
776
+ methods
777
+ end
778
+
694
779
  # @param fqns [String]
695
780
  # @param visibility [Array<Symbol>]
696
781
  # @param skip [Set<String>]
@@ -726,15 +811,19 @@ module Solargraph
726
811
  qualify namespace, context.split('::')[0..-2].join('::')
727
812
  end
728
813
 
729
- # @param fqsub [String]
814
+ # @param fq_tag [String]
730
815
  # @return [String, nil]
731
- def qualify_superclass fqsub
732
- sup = store.get_superclass(fqsub)
733
- return nil if sup.nil?
734
- parts = fqsub.split('::')
816
+ def qualify_superclass fq_sub_tag
817
+ fq_sub_type = ComplexType.try_parse(fq_sub_tag)
818
+ fq_sub_ns = fq_sub_type.name
819
+ sup_tag = store.get_superclass(fq_sub_tag)
820
+ sup_type = ComplexType.try_parse(sup_tag)
821
+ sup_ns = sup_type.name
822
+ return nil if sup_tag.nil?
823
+ parts = fq_sub_ns.split('::')
735
824
  last = parts.pop
736
- parts.pop if last == sup
737
- qualify(sup, parts.join('::'))
825
+ parts.pop if last == sup_ns
826
+ qualify(sup_tag, parts.join('::'))
738
827
  end
739
828
 
740
829
  # @param name [String] Namespace to fully qualify
@@ -807,17 +896,6 @@ module Solargraph
807
896
  result + nil_pins
808
897
  end
809
898
 
810
- # @param pins [Enumerable<Pin::Base>]
811
- # @param visibility [Enumerable<Symbol>]
812
- # @return [Array<Pin::Base>]
813
- def resolve_method_aliases pins, visibility = [:public, :private, :protected]
814
- pins.map do |pin|
815
- resolved = resolve_method_alias(pin)
816
- next pin if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
817
- resolved
818
- end.compact
819
- end
820
-
821
899
  # @param pin [Pin::MethodAlias, Pin::Base]
822
900
  # @return [Pin::Method]
823
901
  def resolve_method_alias pin
@@ -829,18 +907,33 @@ module Solargraph
829
907
  return nil if origin.nil?
830
908
  args = {
831
909
  location: pin.location,
910
+ type_location: origin.type_location,
832
911
  closure: pin.closure,
833
912
  name: pin.name,
834
913
  comments: origin.comments,
835
914
  scope: origin.scope,
836
915
  # context: pin.context,
837
916
  visibility: origin.visibility,
838
- signatures: origin.signatures,
917
+ signatures: origin.signatures.map(&:clone).freeze,
839
918
  attribute: origin.attribute?,
840
- generics: origin.generics,
919
+ generics: origin.generics.clone,
841
920
  return_type: origin.return_type,
921
+ source: :resolve_method_alias
842
922
  }
843
- Pin::Method.new **args
923
+ out = Pin::Method.new **args
924
+ out.signatures.each do |sig|
925
+ sig.parameters = sig.parameters.map(&:clone).freeze
926
+ sig.source = :resolve_method_alias
927
+ sig.parameters.each do |param|
928
+ param.closure = out
929
+ param.source = :resolve_method_alias
930
+ param.reset_generated!
931
+ end
932
+ sig.closure = out
933
+ sig.reset_generated!
934
+ end
935
+ logger.debug { "ApiMap#resolve_method_alias(pin=#{pin}) - returning #{out} from #{origin}" }
936
+ out
844
937
  end
845
938
 
846
939
  include Logging
@@ -88,6 +88,7 @@ module Solargraph
88
88
  # @return [Symbol, nil]
89
89
  attr_reader :parameters_type
90
90
 
91
+ # @type [Hash{String => Symbol}]
91
92
  PARAMETERS_TYPE_BY_STARTING_TAG = {
92
93
  '{' => :hash,
93
94
  '(' => :fixed,
@@ -171,7 +172,11 @@ module Solargraph
171
172
  elsif fixed_parameters?
172
173
  "(#{subtypes_str})"
173
174
  else
174
- "<#{subtypes_str}>"
175
+ if name == 'Hash'
176
+ "<#{key_types_str}, #{subtypes_str}>"
177
+ else
178
+ "<#{key_types_str}#{subtypes_str}>"
179
+ end
175
180
  end
176
181
  end
177
182
 
@@ -55,6 +55,13 @@ module Solargraph
55
55
  key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
56
56
  # @sg-ignore
57
57
  subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
58
+ elsif parameters_type == :list && name == 'Hash'
59
+ # Treat Hash<A, B> as Hash{A => B}
60
+ if subs.length != 2
61
+ raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring} - must have exactly two parameters"
62
+ end
63
+ key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
64
+ subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
58
65
  else
59
66
  subtypes.concat subs
60
67
  end
@@ -306,7 +313,8 @@ module Solargraph
306
313
 
307
314
  transform(name) do |t|
308
315
  if t.name == GENERIC_TAG_NAME
309
- idx = definitions.generics.index(t.subtypes.first&.name)
316
+ generic_name = t.subtypes.first&.name
317
+ idx = definitions.generics.index(generic_name)
310
318
  next t if idx.nil?
311
319
  if context_type.parameters_type == :hash
312
320
  if idx == 0
@@ -323,7 +331,7 @@ module Solargraph
323
331
  ComplexType::UNDEFINED
324
332
  end
325
333
  else
326
- context_type.all_params[idx] || ComplexType::UNDEFINED
334
+ context_type.all_params[idx] || definitions.generic_defaults[generic_name] || ComplexType::UNDEFINED
327
335
  end
328
336
  else
329
337
  t
@@ -20,12 +20,12 @@ module Solargraph
20
20
  EMPTY_ENVIRON
21
21
  end
22
22
 
23
- # The Environ for a YARD map.
23
+ # The Environ for a DocMap.
24
24
  # Subclasses can override this method.
25
25
  #
26
- # @param yard_map [YardMap]
26
+ # @param doc_map [DocMap]
27
27
  # @return [Environ]
28
- def global yard_map
28
+ def global doc_map
29
29
  EMPTY_ENVIRON
30
30
  end
31
31
  end
@@ -31,12 +31,12 @@ module Solargraph
31
31
  result
32
32
  end
33
33
 
34
- # @param yard_map [YardMap]
34
+ # @param yard_map [DocMap]
35
35
  # @return [Environ]
36
- def self.for_global(yard_map)
36
+ def self.for_global(doc_map)
37
37
  result = Environ.new
38
38
  @@conventions.each do |conv|
39
- result.merge conv.global(yard_map)
39
+ result.merge conv.global(doc_map)
40
40
  end
41
41
  result
42
42
  end