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
@@ -8,6 +8,7 @@ module Solargraph
8
8
  include Common
9
9
  include Conversions
10
10
  include Documenting
11
+ include Logging
11
12
 
12
13
  # @return [YARD::CodeObjects::Base]
13
14
  attr_reader :code_object
@@ -36,14 +37,275 @@ module Solargraph
36
37
  # @param closure [Solargraph::Pin::Closure, nil]
37
38
  # @param name [String]
38
39
  # @param comments [String]
39
- def initialize location: nil, type_location: nil, closure: nil, source: nil, name: '', comments: ''
40
+ # @param source [Symbol, nil]
41
+ # @param docstring [YARD::Docstring, nil]
42
+ # @param directives [::Array<YARD::Tags::Directive>, nil]
43
+ def initialize location: nil, type_location: nil, closure: nil, source: nil, name: '', comments: '', docstring: nil, directives: nil
40
44
  @location = location
41
45
  @type_location = type_location
42
46
  @closure = closure
43
47
  @name = name
44
- @source = source
45
48
  @comments = comments
46
49
  @source = source
50
+ @identity = nil
51
+ @docstring = docstring
52
+ @directives = directives
53
+ assert_source_provided
54
+ end
55
+
56
+ # @param other [self]
57
+ # @param attrs [Hash{Symbol => Object}]
58
+ #
59
+ # @return [self]
60
+ def combine_with(other, attrs={})
61
+ raise "tried to combine #{other.class} with #{self.class}" unless other.class == self.class
62
+ type_location = choose(other, :type_location)
63
+ location = choose(other, :location)
64
+ combined_name = combine_name(other)
65
+ new_attrs = {
66
+ location: location,
67
+ type_location: type_location,
68
+ name: combined_name,
69
+ closure: choose_pin_attr_with_same_name(other, :closure),
70
+ comments: choose_longer(other, :comments),
71
+ source: :combined,
72
+ docstring: choose(other, :docstring),
73
+ directives: combine_directives(other),
74
+ }.merge(attrs)
75
+ assert_same_macros(other)
76
+ logger.debug { "Base#combine_with(path=#{path}) - other.comments=#{other.comments.inspect}, self.comments = #{self.comments}" }
77
+ out = self.class.new(**new_attrs)
78
+ out.reset_generated!
79
+ out
80
+ end
81
+
82
+ # @param other [self]
83
+ # @param attr [::Symbol]
84
+ # @sg-ignore
85
+ # @return [undefined]
86
+ def choose_longer(other, attr)
87
+ # @type [undefined]
88
+ val1 = send(attr)
89
+ # @type [undefined]
90
+ val2 = other.send(attr)
91
+ return val1 if val1 == val2
92
+ return val2 if val1.nil?
93
+ # @sg-ignore
94
+ val1.length > val2.length ? val1 : val2
95
+ end
96
+
97
+ # @param other [self]
98
+ # @return [::Array<YARD::Tags::Directive>, nil]
99
+ def combine_directives(other)
100
+ return self.directives if other.directives.empty?
101
+ return other.directives if directives.empty?
102
+ [directives + other.directives].uniq
103
+ end
104
+
105
+ # @param other [self]
106
+ # @return [String]
107
+ def combine_name(other)
108
+ if needs_consistent_name? || other.needs_consistent_name?
109
+ assert_same(other, :name)
110
+ else
111
+ choose(other, :name)
112
+ end
113
+ end
114
+
115
+ # @return [void]
116
+ def reset_generated!
117
+ # @return_type doesn't go here as subclasses tend to assign it
118
+ # themselves in constructors, and they will deal with setting
119
+ # it in any methods that call this
120
+ #
121
+ # @docstring also doesn't go here, as there is code which
122
+ # directly manipulates docstring without editing comments
123
+ # (e.g., Api::Map::Store#index processes overrides that way
124
+ #
125
+ # Same with @directives, @macros, @maybe_directives, which
126
+ # regenerate docstring
127
+ @deprecated = nil
128
+ reset_conversions
129
+ end
130
+
131
+ def needs_consistent_name?
132
+ true
133
+ end
134
+
135
+ # @sg-ignore def should infer as symbol - "Not enough arguments to Module#protected"
136
+ protected def equality_fields
137
+ [name, location, type_location, closure, source]
138
+ end
139
+
140
+ # @param other [self]
141
+ # @return [ComplexType]
142
+ def combine_return_type(other)
143
+ if return_type.undefined?
144
+ other.return_type
145
+ elsif other.return_type.undefined?
146
+ return_type
147
+ elsif dodgy_return_type_source? && !other.dodgy_return_type_source?
148
+ other.return_type
149
+ elsif other.dodgy_return_type_source? && !dodgy_return_type_source?
150
+ return_type
151
+ else
152
+ all_items = return_type.items + other.return_type.items
153
+ if all_items.any? { |item| item.selfy? } && all_items.any? { |item| item.rooted_tag == context.rooted_tag }
154
+ # assume this was a declaration that should have said 'self'
155
+ all_items.delete_if { |item| item.rooted_tag == context.rooted_tag }
156
+ end
157
+ ComplexType.new(all_items)
158
+ end
159
+ end
160
+
161
+ def dodgy_return_type_source?
162
+ # uses a lot of 'Object' instead of 'self'
163
+ location&.filename&.include?('core_ext/object/')
164
+ end
165
+
166
+ # when choices are arbitrary, make sure the choice is consistent
167
+ #
168
+ # @param other [Pin::Base]
169
+ # @param attr [::Symbol]
170
+ #
171
+ # @return [Object, nil]
172
+ def choose(other, attr)
173
+ results = [self, other].map(&attr).compact
174
+ # true and false are different classes and can't be sorted
175
+ return true if results.any? { |r| r == true || r == false }
176
+ results.min
177
+ rescue
178
+ 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}")
179
+ raise
180
+ end
181
+
182
+ # @param other [self]
183
+ # @param attr [Symbol]
184
+ # @sg-ignore
185
+ # @return [undefined]
186
+ def choose_node(other, attr)
187
+ if other.object_id < attr.object_id
188
+ other.send(attr)
189
+ else
190
+ send(attr)
191
+ end
192
+ end
193
+
194
+ # @param other [self]
195
+ # @param attr [::Symbol]
196
+ # @sg-ignore
197
+ # @return [undefined]
198
+ def prefer_rbs_location(other, attr)
199
+ if rbs_location? && !other.rbs_location?
200
+ self.send(attr)
201
+ elsif !rbs_location? && other.rbs_location?
202
+ other.send(attr)
203
+ else
204
+ choose(other, attr)
205
+ end
206
+ end
207
+
208
+ def rbs_location?
209
+ type_location&.rbs?
210
+ end
211
+
212
+ # @param other [self]
213
+ # @return [void]
214
+ def assert_same_macros(other)
215
+ return unless self.source == :yardoc && other.source == :yardoc
216
+ assert_same_count(other, :macros)
217
+ assert_same_array_content(other, :macros) { |macro| macro.tag.name }
218
+ end
219
+
220
+ # @param other [self]
221
+ # @param attr [::Symbol]
222
+ # @return [void]
223
+ # @todo strong typechecking should complain when there are no block-related tags
224
+ def assert_same_array_content(other, attr, &block)
225
+ arr1 = send(attr)
226
+ raise "Expected #{attr} on #{self} to be an Enumerable, got #{arr1.class}" unless arr1.is_a?(::Enumerable)
227
+ # @type arr1 [::Enumerable]
228
+ arr2 = other.send(attr)
229
+ raise "Expected #{attr} on #{other} to be an Enumerable, got #{arr2.class}" unless arr2.is_a?(::Enumerable)
230
+ # @type arr2 [::Enumerable]
231
+
232
+ # @sg-ignore
233
+ # @type [undefined]
234
+ values1 = arr1.map(&block)
235
+ # @type [undefined]
236
+ values2 = arr2.map(&block)
237
+ # @sg-ignore
238
+ return arr1 if values1 == values2
239
+ Solargraph.assert_or_log("combine_with_#{attr}".to_sym,
240
+ "Inconsistent #{attr.inspect} values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self values = #{values1}\nother values =#{attr} = #{values2}")
241
+ arr1
242
+ end
243
+
244
+ # @param other [self]
245
+ # @param attr [::Symbol]
246
+ #
247
+ # @return [::Enumerable]
248
+ def assert_same_count(other, attr)
249
+ # @type [::Enumerable]
250
+ arr1 = self.send(attr)
251
+ raise "Expected #{attr} on #{self} to be an Enumerable, got #{arr1.class}" unless arr1.is_a?(::Enumerable)
252
+ # @type [::Enumerable]
253
+ arr2 = other.send(attr)
254
+ raise "Expected #{attr} on #{other} to be an Enumerable, got #{arr2.class}" unless arr2.is_a?(::Enumerable)
255
+ return arr1 if arr1.count == arr2.count
256
+ Solargraph.assert_or_log("combine_with_#{attr}".to_sym,
257
+ "Inconsistent #{attr.inspect} count value between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{arr1.inspect}\nother.#{attr} = #{arr2.inspect}")
258
+ arr1
259
+ end
260
+
261
+ # @param other [self]
262
+ # @param attr [::Symbol]
263
+ #
264
+ # @return [Object, nil]
265
+ def assert_same(other, attr)
266
+ return false if other.nil?
267
+ val1 = send(attr)
268
+ val2 = other.send(attr)
269
+ return val1 if val1 == val2
270
+ Solargraph.assert_or_log("combine_with_#{attr}".to_sym,
271
+ "Inconsistent #{attr.inspect} values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}")
272
+ val1
273
+ end
274
+
275
+ # @param other [self]
276
+ # @param attr [::Symbol]
277
+ # @sg-ignore
278
+ # @return [undefined]
279
+ def choose_pin_attr_with_same_name(other, attr)
280
+ # @type [Pin::Base, nil]
281
+ val1 = send(attr)
282
+ # @type [Pin::Base, nil]
283
+ val2 = other.send(attr)
284
+ raise "Expected pin for #{attr} on\n#{self.inspect},\ngot #{val1.inspect}" unless val1.nil? || val1.is_a?(Pin::Base)
285
+ raise "Expected pin for #{attr} on\n#{other.inspect},\ngot #{val2.inspect}" unless val2.nil? || val2.is_a?(Pin::Base)
286
+ if val1&.name != val2&.name
287
+ Solargraph.assert_or_log("combine_with_#{attr}_name".to_sym,
288
+ "Inconsistent #{attr.inspect} name values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}")
289
+ end
290
+ choose_pin_attr(other, attr)
291
+ end
292
+
293
+ def choose_pin_attr(other, attr)
294
+ # @type [Pin::Base, nil]
295
+ val1 = send(attr)
296
+ # @type [Pin::Base, nil]
297
+ val2 = other.send(attr)
298
+ if val1.class != val2.class
299
+ Solargraph.assert_or_log("combine_with_#{attr}_class".to_sym,
300
+ "Inconsistent #{attr.inspect} class values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}")
301
+ return val1
302
+ end
303
+ # arbitrary way of choosing a pin
304
+ [val1, val2].compact.min_by { _1.best_location.to_s }
305
+ end
306
+
307
+ def assert_source_provided
308
+ Solargraph.assert_or_log(:source, "source not provided - #{@path} #{@source} #{self.class}") if source.nil?
47
309
  end
48
310
 
49
311
  # @return [String]
@@ -140,6 +402,7 @@ module Solargraph
140
402
  # Pin equality is determined using the #nearly? method and also
141
403
  # requiring both pins to have the same location.
142
404
  #
405
+ # @param other [self]
143
406
  def == other
144
407
  return false unless nearly? other
145
408
  comments == other.comments && location == other.location
@@ -154,13 +417,13 @@ module Solargraph
154
417
 
155
418
  # @return [YARD::Docstring]
156
419
  def docstring
157
- parse_comments unless defined?(@docstring)
420
+ parse_comments unless @docstring
158
421
  @docstring ||= Solargraph::Source.parse_docstring('').to_docstring
159
422
  end
160
423
 
161
424
  # @return [::Array<YARD::Tags::Directive>]
162
425
  def directives
163
- parse_comments unless defined?(@directives)
426
+ parse_comments unless @directives
164
427
  @directives
165
428
  end
166
429
 
@@ -178,7 +441,7 @@ module Solargraph
178
441
  #
179
442
  # @return [Boolean]
180
443
  def maybe_directives?
181
- return !@directives.empty? if defined?(@directives)
444
+ return !@directives.empty? if defined?(@directives) && @directives
182
445
  @maybe_directives ||= comments.include?('@!')
183
446
  end
184
447
 
@@ -217,26 +480,6 @@ module Solargraph
217
480
  probe api_map
218
481
  end
219
482
 
220
- # Try to merge data from another pin. Merges are only possible if the
221
- # pins are near matches (see the #nearly? method). The changes should
222
- # not have any side effects on the API surface.
223
- #
224
- # @param pin [Pin::Base] The pin to merge into this one
225
- # @return [Boolean] True if the pins were merged
226
- def try_merge! pin
227
- return false unless nearly?(pin)
228
- @location = pin.location
229
- @closure = pin.closure
230
- return true if comments == pin.comments
231
- @comments = pin.comments
232
- @docstring = pin.docstring
233
- @return_type = pin.return_type
234
- @documentation = nil
235
- @deprecated = nil
236
- reset_conversions
237
- true
238
- end
239
-
240
483
  def proxied?
241
484
  @proxied ||= false
242
485
  end
@@ -299,14 +542,34 @@ module Solargraph
299
542
  end
300
543
 
301
544
  # @return [String]
302
- def desc
545
+ def inner_desc
303
546
  closure_info = closure&.desc
304
547
  binder_info = binder&.desc
305
- "[name=#{name.inspect} return_type=#{type_desc}, context=#{context.rooted_tags}, closure=#{closure_info}, binder=#{binder_info}]"
548
+ "name=#{name.inspect} return_type=#{type_desc}, context=#{context.rooted_tags}, closure=#{closure_info}, binder=#{binder_info}"
306
549
  end
307
550
 
551
+ def desc
552
+ "[#{inner_desc}]"
553
+ end
554
+
555
+ # @return [String]
308
556
  def inspect
309
- "#<#{self.class} `#{self.desc}` at #{self.location.inspect}>"
557
+ "#<#{self.class} `#{self.inner_desc}`#{all_location_text} via #{source.inspect}>"
558
+ end
559
+
560
+ def all_location_text
561
+ if location.nil? && type_location.nil?
562
+ ''
563
+ elsif !location.nil? && type_location.nil?
564
+ " at #{location.inspect})"
565
+ elsif !type_location.nil? && location.nil?
566
+ " at #{type_location.inspect})"
567
+ else
568
+ " at (#{location.inspect} and #{type_location.inspect})"
569
+ end
570
+ end
571
+
572
+ def reset_generated!
310
573
  end
311
574
 
312
575
  protected
@@ -320,6 +583,10 @@ module Solargraph
320
583
  # @return [ComplexType]
321
584
  attr_writer :return_type
322
585
 
586
+ attr_writer :docstring
587
+
588
+ attr_writer :directives
589
+
323
590
  private
324
591
 
325
592
  # @return [void]
@@ -21,6 +21,15 @@ module Solargraph
21
21
  @return_type = return_type
22
22
  end
23
23
 
24
+ def combine_with(other, attrs={})
25
+ attrs.merge({
26
+ assignment: assert_same(other, :assignment),
27
+ mass_assignment: assert_same(other, :mass_assignment),
28
+ return_type: combine_return_type(other),
29
+ })
30
+ super(other, attrs)
31
+ end
32
+
24
33
  def completion_item_kind
25
34
  Solargraph::LanguageServer::CompletionItemKinds::VARIABLE
26
35
  end
@@ -99,14 +108,6 @@ module Solargraph
99
108
  assignment == other.assignment
100
109
  end
101
110
 
102
- # @param pin [self]
103
- def try_merge! pin
104
- return false unless super
105
- @assignment = pin.assignment
106
- @return_type = pin.return_type
107
- true
108
- end
109
-
110
111
  def type_desc
111
112
  "#{super} = #{assignment&.type.inspect}"
112
113
  end
@@ -6,7 +6,7 @@ module Solargraph
6
6
  # @return [Signature]
7
7
  attr_reader :block
8
8
 
9
- attr_reader :parameters
9
+ attr_accessor :parameters
10
10
 
11
11
  # @return [ComplexType, nil]
12
12
  attr_reader :return_type
@@ -21,11 +21,67 @@ module Solargraph
21
21
  @parameters = parameters
22
22
  end
23
23
 
24
+ def method_namespace
25
+ closure.namespace
26
+ end
27
+
28
+ def combine_blocks(other)
29
+ if block.nil?
30
+ other.block
31
+ elsif other.block.nil?
32
+ block
33
+ else
34
+ choose_pin_attr(other, :block)
35
+ end
36
+ end
37
+
38
+ # @param other [self]
39
+ # @param attrs [Hash{Symbol => Object}]
40
+ #
41
+ # @return [self]
42
+ def combine_with(other, attrs={})
43
+ new_attrs = {
44
+ block: combine_blocks(other),
45
+ return_type: combine_return_type(other),
46
+ }.merge(attrs)
47
+ new_attrs[:parameters] = choose_parameters(other).clone.freeze unless new_attrs.key?(:parameters)
48
+ super(other, new_attrs)
49
+ end
50
+
24
51
  # @return [::Array<String>]
25
52
  def parameter_names
26
53
  @parameter_names ||= parameters.map(&:name)
27
54
  end
28
55
 
56
+ def generics
57
+ []
58
+ end
59
+
60
+ def choose_parameters(other)
61
+ raise "Trying to combine two pins with different arities - \nself =#{inspect}, \nother=#{other.inspect}, \n\n self.arity=#{self.arity}, \nother.arity=#{other.arity}" if other.arity != arity
62
+ parameters.zip(other.parameters).map do |param, other_param|
63
+ if param.nil? && other_param.block?
64
+ other_param
65
+ elsif other_param.nil? && param.block?
66
+ param
67
+ else
68
+ param.combine_with(other_param)
69
+ end
70
+ end
71
+ end
72
+
73
+ def blockless_parameters
74
+ if parameters.last&.block?
75
+ parameters[0..-2]
76
+ else
77
+ parameters
78
+ end
79
+ end
80
+
81
+ def arity
82
+ [generics, blockless_parameters.map(&:arity_decl), block&.arity]
83
+ end
84
+
29
85
  # @param generics_to_resolve [Enumerable<String>]
30
86
  # @param arg_types [Array<ComplexType>, nil]
31
87
  # @param return_type_context [ComplexType, nil]
@@ -57,6 +113,23 @@ module Solargraph
57
113
  callable
58
114
  end
59
115
 
116
+ def typify api_map
117
+ type = super
118
+ return type if type.defined?
119
+ if method_name.end_with?('?')
120
+ logger.debug { "Callable#typify(self=#{self}) => Boolean (? suffix)" }
121
+ ComplexType::BOOLEAN
122
+ else
123
+ logger.debug { "Callable#typify(self=#{self}) => undefined" }
124
+ ComplexType::UNDEFINED
125
+ end
126
+ end
127
+
128
+ def method_name
129
+ raise "closure was nil in #{self.inspect}" if closure.nil?
130
+ @method_name ||= closure.name
131
+ end
132
+
60
133
  # @param generics_to_resolve [::Array<String>]
61
134
  # @param arg_types [Array<ComplexType>, nil]
62
135
  # @param return_type_context [ComplexType, nil]
@@ -140,8 +213,6 @@ module Solargraph
140
213
  protected
141
214
 
142
215
  attr_writer :block
143
-
144
- attr_writer :parameters
145
216
  end
146
217
  end
147
218
  end
@@ -8,10 +8,27 @@ module Solargraph
8
8
 
9
9
  # @param scope [::Symbol] :class or :instance
10
10
  # @param generics [::Array<Pin::Parameter>, nil]
11
- def initialize scope: :class, generics: nil, **splat
11
+ def initialize scope: :class, generics: nil, generic_defaults: {}, **splat
12
12
  super(**splat)
13
13
  @scope = scope
14
14
  @generics = generics
15
+ @generic_defaults = generic_defaults
16
+ end
17
+
18
+ def generic_defaults
19
+ @generic_defaults ||= {}
20
+ end
21
+
22
+ # @param other [self]
23
+ # @param attrs [Hash{Symbol => Object}]
24
+ #
25
+ # @return [self]
26
+ def combine_with(other, attrs={})
27
+ new_attrs = {
28
+ scope: assert_same(other, :scope),
29
+ generics: generics.empty? ? other.generics : generics,
30
+ }.merge(attrs)
31
+ super(other, new_attrs)
15
32
  end
16
33
 
17
34
  def context
@@ -9,6 +9,11 @@ module Solargraph
9
9
  # @return [Pin::Closure, nil]
10
10
  attr_reader :closure
11
11
 
12
+ def closure
13
+ Solargraph.assert_or_log(:closure, "Closure not set on #{self.class} #{name.inspect} from #{source.inspect}") unless @closure
14
+ @closure
15
+ end
16
+
12
17
  # @return [String]
13
18
  def name
14
19
  @name ||= ''
@@ -43,6 +43,7 @@ module Solargraph
43
43
 
44
44
  %i[comments parameters return_type signatures].each do |method|
45
45
  define_method(method) do
46
+ # @sg-ignore Need to set context correctly in define_method blocks
46
47
  @resolved_method ? @resolved_method.send(method) : super()
47
48
  end
48
49
  end
@@ -51,6 +52,7 @@ module Solargraph
51
52
  # @param api_map [ApiMap]
52
53
  define_method(method) do |api_map|
53
54
  resolve_method(api_map)
55
+ # @sg-ignore Need to set context correctly in define_method blocks
54
56
  @resolved_method ? @resolved_method.send(method, api_map) : super(api_map)
55
57
  end
56
58
  end
@@ -9,6 +9,22 @@ require 'solargraph/converters/dt'
9
9
  require 'solargraph/converters/dd'
10
10
  require 'solargraph/converters/misc'
11
11
 
12
+ # @todo upstream this definition
13
+
14
+ # @!parse
15
+ # module ::Kramdown
16
+ # class Document
17
+ # # @return [String]
18
+ # def to_html; end
19
+ # end
20
+ # end
21
+ # module ReverseMarkdown
22
+ # # @param input [String]
23
+ # # @param options [Hash]
24
+ # # @return [String]
25
+ # def self.convert(input, options = {}); end
26
+ # end
27
+
12
28
  module Solargraph
13
29
  module Pin
14
30
  # A module to add the Pin::Base#documentation method.
@@ -3,8 +3,13 @@
3
3
  module Solargraph
4
4
  module Pin
5
5
  class Keyword < Base
6
- def initialize name
7
- super(name: name)
6
+ def initialize(name, **kwargs)
7
+ # @sg-ignore "Unrecognized keyword argument kwargs to Solargraph::Pin::Base#initialize"
8
+ super(name: name, **kwargs)
9
+ end
10
+
11
+ def closure
12
+ @closure ||= Pin::ROOT_PIN
8
13
  end
9
14
 
10
15
  def name
@@ -21,11 +21,14 @@ module Solargraph
21
21
  @presence_certain = presence_certain
22
22
  end
23
23
 
24
- # @param pin [self]
25
- def try_merge! pin
26
- return false unless super
27
- @presence = pin.presence
28
- true
24
+ def combine_with(other, attrs={})
25
+ new_attrs = {
26
+ assignment: assert_same(other, :assignment),
27
+ presence_certain: assert_same(other, :presence_certain?),
28
+ }.merge(attrs)
29
+ new_attrs[:presence] = assert_same(other, :presence) unless attrs.key?(:presence)
30
+
31
+ super(other, new_attrs)
29
32
  end
30
33
 
31
34
  # @param other_closure [Pin::Closure]