solargraph 0.54.4 → 0.56.2

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 (135) 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 +62 -0
  6. data/README.md +13 -3
  7. data/lib/solargraph/api_map/index.rb +24 -16
  8. data/lib/solargraph/api_map/store.rb +48 -23
  9. data/lib/solargraph/api_map.rb +175 -77
  10. data/lib/solargraph/bench.rb +17 -1
  11. data/lib/solargraph/complex_type/type_methods.rb +6 -1
  12. data/lib/solargraph/complex_type/unique_type.rb +98 -9
  13. data/lib/solargraph/complex_type.rb +35 -6
  14. data/lib/solargraph/convention/base.rb +3 -3
  15. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +60 -0
  16. data/lib/solargraph/convention/data_definition/data_definition_node.rb +89 -0
  17. data/lib/solargraph/convention/data_definition.rb +104 -0
  18. data/lib/solargraph/convention/gemspec.rb +2 -1
  19. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +60 -0
  20. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +100 -0
  21. data/lib/solargraph/convention/struct_definition.rb +141 -0
  22. data/lib/solargraph/convention.rb +5 -3
  23. data/lib/solargraph/doc_map.rb +277 -57
  24. data/lib/solargraph/gem_pins.rb +53 -37
  25. data/lib/solargraph/language_server/host/message_worker.rb +10 -7
  26. data/lib/solargraph/language_server/host.rb +12 -2
  27. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  28. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  29. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  30. data/lib/solargraph/library.rb +45 -17
  31. data/lib/solargraph/location.rb +21 -0
  32. data/lib/solargraph/logging.rb +1 -0
  33. data/lib/solargraph/parser/comment_ripper.rb +12 -6
  34. data/lib/solargraph/parser/flow_sensitive_typing.rb +227 -0
  35. data/lib/solargraph/parser/node_methods.rb +14 -0
  36. data/lib/solargraph/parser/node_processor/base.rb +9 -4
  37. data/lib/solargraph/parser/node_processor.rb +21 -8
  38. data/lib/solargraph/parser/parser_gem/class_methods.rb +16 -14
  39. data/lib/solargraph/parser/parser_gem/node_chainer.rb +10 -10
  40. data/lib/solargraph/parser/parser_gem/node_methods.rb +4 -2
  41. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  42. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
  43. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
  44. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +4 -2
  45. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  46. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  47. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  48. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  49. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  50. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +21 -0
  51. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  52. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  53. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +4 -1
  54. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  55. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +42 -0
  56. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  57. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
  58. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
  59. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +28 -16
  60. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  61. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  62. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  63. data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
  64. data/lib/solargraph/parser/region.rb +1 -1
  65. data/lib/solargraph/parser.rb +1 -0
  66. data/lib/solargraph/pin/base.rb +316 -28
  67. data/lib/solargraph/pin/base_variable.rb +16 -9
  68. data/lib/solargraph/pin/block.rb +2 -0
  69. data/lib/solargraph/pin/breakable.rb +9 -0
  70. data/lib/solargraph/pin/callable.rb +74 -3
  71. data/lib/solargraph/pin/closure.rb +18 -1
  72. data/lib/solargraph/pin/common.rb +5 -0
  73. data/lib/solargraph/pin/delegated_method.rb +20 -1
  74. data/lib/solargraph/pin/documenting.rb +16 -0
  75. data/lib/solargraph/pin/keyword.rb +7 -2
  76. data/lib/solargraph/pin/local_variable.rb +15 -6
  77. data/lib/solargraph/pin/method.rb +169 -43
  78. data/lib/solargraph/pin/namespace.rb +17 -9
  79. data/lib/solargraph/pin/parameter.rb +60 -11
  80. data/lib/solargraph/pin/proxy_type.rb +12 -6
  81. data/lib/solargraph/pin/reference/override.rb +10 -6
  82. data/lib/solargraph/pin/reference/require.rb +2 -2
  83. data/lib/solargraph/pin/signature.rb +42 -0
  84. data/lib/solargraph/pin/singleton.rb +1 -1
  85. data/lib/solargraph/pin/symbol.rb +3 -2
  86. data/lib/solargraph/pin/until.rb +18 -0
  87. data/lib/solargraph/pin/while.rb +18 -0
  88. data/lib/solargraph/pin.rb +4 -1
  89. data/lib/solargraph/pin_cache.rb +185 -0
  90. data/lib/solargraph/position.rb +9 -0
  91. data/lib/solargraph/range.rb +9 -0
  92. data/lib/solargraph/rbs_map/conversions.rb +221 -67
  93. data/lib/solargraph/rbs_map/core_fills.rb +32 -16
  94. data/lib/solargraph/rbs_map/core_map.rb +34 -11
  95. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  96. data/lib/solargraph/rbs_map.rb +74 -17
  97. data/lib/solargraph/shell.rb +17 -18
  98. data/lib/solargraph/source/chain/array.rb +11 -7
  99. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  100. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  101. data/lib/solargraph/source/chain/call.rb +53 -23
  102. data/lib/solargraph/source/chain/constant.rb +1 -1
  103. data/lib/solargraph/source/chain/hash.rb +4 -3
  104. data/lib/solargraph/source/chain/head.rb +1 -1
  105. data/lib/solargraph/source/chain/if.rb +1 -1
  106. data/lib/solargraph/source/chain/link.rb +2 -0
  107. data/lib/solargraph/source/chain/literal.rb +22 -2
  108. data/lib/solargraph/source/chain/or.rb +1 -1
  109. data/lib/solargraph/source/chain/z_super.rb +1 -1
  110. data/lib/solargraph/source/chain.rb +78 -48
  111. data/lib/solargraph/source/source_chainer.rb +2 -2
  112. data/lib/solargraph/source_map/clip.rb +3 -1
  113. data/lib/solargraph/source_map/mapper.rb +9 -5
  114. data/lib/solargraph/source_map.rb +0 -17
  115. data/lib/solargraph/type_checker/checks.rb +4 -0
  116. data/lib/solargraph/type_checker.rb +35 -8
  117. data/lib/solargraph/version.rb +1 -1
  118. data/lib/solargraph/views/_method.erb +10 -10
  119. data/lib/solargraph/views/_namespace.erb +3 -3
  120. data/lib/solargraph/views/document.erb +10 -10
  121. data/lib/solargraph/workspace/config.rb +1 -1
  122. data/lib/solargraph/workspace.rb +23 -5
  123. data/lib/solargraph/yard_map/helpers.rb +29 -1
  124. data/lib/solargraph/yard_map/mapper/to_constant.rb +7 -5
  125. data/lib/solargraph/yard_map/mapper/to_method.rb +53 -18
  126. data/lib/solargraph/yard_map/mapper/to_namespace.rb +9 -7
  127. data/lib/solargraph/yard_map/mapper.rb +4 -3
  128. data/lib/solargraph/yard_map/to_method.rb +4 -2
  129. data/lib/solargraph/yardoc.rb +7 -8
  130. data/lib/solargraph.rb +32 -1
  131. data/rbs/fills/tuple.rbs +150 -0
  132. data/rbs_collection.yaml +19 -0
  133. data/solargraph.gemspec +2 -1
  134. metadata +37 -9
  135. 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
@@ -27,17 +28,296 @@ module Solargraph
27
28
  # @return [::Symbol]
28
29
  attr_accessor :source
29
30
 
31
+ def presence_certain?
32
+ true
33
+ end
34
+
30
35
  # @param location [Solargraph::Location, nil]
31
36
  # @param type_location [Solargraph::Location, nil]
32
37
  # @param closure [Solargraph::Pin::Closure, nil]
33
38
  # @param name [String]
34
39
  # @param comments [String]
35
- def initialize location: nil, type_location: nil, closure: 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
36
44
  @location = location
37
45
  @type_location = type_location
38
46
  @closure = closure
39
47
  @name = name
40
48
  @comments = comments
49
+ @source = source
50
+ @identity = nil
51
+ @docstring = docstring
52
+ @directives = directives
53
+ assert_source_provided
54
+ assert_location_provided
55
+ end
56
+
57
+ # @return [void]
58
+ def assert_location_provided
59
+ return unless best_location.nil? && %i[yardoc source rbs].include?(source)
60
+
61
+ Solargraph.assert_or_log(:best_location, "Neither location nor type_location provided - #{path} #{source} #{self.class}")
62
+ end
63
+
64
+ # @param other [self]
65
+ # @param attrs [Hash{Symbol => Object}]
66
+ #
67
+ # @return [self]
68
+ def combine_with(other, attrs={})
69
+ raise "tried to combine #{other.class} with #{self.class}" unless other.class == self.class
70
+ type_location = choose(other, :type_location)
71
+ location = choose(other, :location)
72
+ combined_name = combine_name(other)
73
+ new_attrs = {
74
+ location: location,
75
+ type_location: type_location,
76
+ name: combined_name,
77
+ closure: choose_pin_attr_with_same_name(other, :closure),
78
+ comments: choose_longer(other, :comments),
79
+ source: :combined,
80
+ docstring: choose(other, :docstring),
81
+ directives: combine_directives(other),
82
+ }.merge(attrs)
83
+ assert_same_macros(other)
84
+ logger.debug { "Base#combine_with(path=#{path}) - other.comments=#{other.comments.inspect}, self.comments = #{self.comments}" }
85
+ out = self.class.new(**new_attrs)
86
+ out.reset_generated!
87
+ out
88
+ end
89
+
90
+ # @param other [self]
91
+ # @param attr [::Symbol]
92
+ # @sg-ignore
93
+ # @return [undefined]
94
+ def choose_longer(other, attr)
95
+ # @type [undefined]
96
+ val1 = send(attr)
97
+ # @type [undefined]
98
+ val2 = other.send(attr)
99
+ return val1 if val1 == val2
100
+ return val2 if val1.nil?
101
+ # @sg-ignore
102
+ val1.length > val2.length ? val1 : val2
103
+ end
104
+
105
+ # @param other [self]
106
+ # @return [::Array<YARD::Tags::Directive>, nil]
107
+ def combine_directives(other)
108
+ return self.directives if other.directives.empty?
109
+ return other.directives if directives.empty?
110
+ [directives + other.directives].uniq
111
+ end
112
+
113
+ # @param other [self]
114
+ # @return [String]
115
+ def combine_name(other)
116
+ if needs_consistent_name? || other.needs_consistent_name?
117
+ assert_same(other, :name)
118
+ else
119
+ choose(other, :name)
120
+ end
121
+ end
122
+
123
+ # @return [void]
124
+ def reset_generated!
125
+ # @return_type doesn't go here as subclasses tend to assign it
126
+ # themselves in constructors, and they will deal with setting
127
+ # it in any methods that call this
128
+ #
129
+ # @docstring also doesn't go here, as there is code which
130
+ # directly manipulates docstring without editing comments
131
+ # (e.g., Api::Map::Store#index processes overrides that way
132
+ #
133
+ # Same with @directives, @macros, @maybe_directives, which
134
+ # regenerate docstring
135
+ @deprecated = nil
136
+ reset_conversions
137
+ end
138
+
139
+ def needs_consistent_name?
140
+ true
141
+ end
142
+
143
+ # @sg-ignore def should infer as symbol - "Not enough arguments to Module#protected"
144
+ protected def equality_fields
145
+ [name, location, type_location, closure, source]
146
+ end
147
+
148
+ # @param other [self]
149
+ # @return [ComplexType]
150
+ def combine_return_type(other)
151
+ if return_type.undefined?
152
+ other.return_type
153
+ elsif other.return_type.undefined?
154
+ return_type
155
+ elsif dodgy_return_type_source? && !other.dodgy_return_type_source?
156
+ other.return_type
157
+ elsif other.dodgy_return_type_source? && !dodgy_return_type_source?
158
+ return_type
159
+ else
160
+ all_items = return_type.items + other.return_type.items
161
+ if all_items.any? { |item| item.selfy? } && all_items.any? { |item| item.rooted_tag == context.rooted_tag }
162
+ # assume this was a declaration that should have said 'self'
163
+ all_items.delete_if { |item| item.rooted_tag == context.rooted_tag }
164
+ end
165
+ ComplexType.new(all_items)
166
+ end
167
+ end
168
+
169
+ def dodgy_return_type_source?
170
+ # uses a lot of 'Object' instead of 'self'
171
+ location&.filename&.include?('core_ext/object/')
172
+ end
173
+
174
+ # when choices are arbitrary, make sure the choice is consistent
175
+ #
176
+ # @param other [Pin::Base]
177
+ # @param attr [::Symbol]
178
+ #
179
+ # @return [Object, nil]
180
+ def choose(other, attr)
181
+ results = [self, other].map(&attr).compact
182
+ # true and false are different classes and can't be sorted
183
+ return true if results.any? { |r| r == true || r == false }
184
+ results.min
185
+ rescue
186
+ 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}")
187
+ raise
188
+ end
189
+
190
+ # @param other [self]
191
+ # @param attr [Symbol]
192
+ # @sg-ignore
193
+ # @return [undefined]
194
+ def choose_node(other, attr)
195
+ if other.object_id < attr.object_id
196
+ other.send(attr)
197
+ else
198
+ send(attr)
199
+ end
200
+ end
201
+
202
+ # @param other [self]
203
+ # @param attr [::Symbol]
204
+ # @sg-ignore
205
+ # @return [undefined]
206
+ def prefer_rbs_location(other, attr)
207
+ if rbs_location? && !other.rbs_location?
208
+ self.send(attr)
209
+ elsif !rbs_location? && other.rbs_location?
210
+ other.send(attr)
211
+ else
212
+ choose(other, attr)
213
+ end
214
+ end
215
+
216
+ def rbs_location?
217
+ type_location&.rbs?
218
+ end
219
+
220
+ # @param other [self]
221
+ # @return [void]
222
+ def assert_same_macros(other)
223
+ return unless self.source == :yardoc && other.source == :yardoc
224
+ assert_same_count(other, :macros)
225
+ assert_same_array_content(other, :macros) { |macro| macro.tag.name }
226
+ end
227
+
228
+ # @param other [self]
229
+ # @param attr [::Symbol]
230
+ # @return [void]
231
+ # @todo strong typechecking should complain when there are no block-related tags
232
+ def assert_same_array_content(other, attr, &block)
233
+ arr1 = send(attr)
234
+ raise "Expected #{attr} on #{self} to be an Enumerable, got #{arr1.class}" unless arr1.is_a?(::Enumerable)
235
+ # @type arr1 [::Enumerable]
236
+ arr2 = other.send(attr)
237
+ raise "Expected #{attr} on #{other} to be an Enumerable, got #{arr2.class}" unless arr2.is_a?(::Enumerable)
238
+ # @type arr2 [::Enumerable]
239
+
240
+ # @sg-ignore
241
+ # @type [undefined]
242
+ values1 = arr1.map(&block)
243
+ # @type [undefined]
244
+ values2 = arr2.map(&block)
245
+ # @sg-ignore
246
+ return arr1 if values1 == values2
247
+ Solargraph.assert_or_log("combine_with_#{attr}".to_sym,
248
+ "Inconsistent #{attr.inspect} values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self values = #{values1}\nother values =#{attr} = #{values2}")
249
+ arr1
250
+ end
251
+
252
+ # @param other [self]
253
+ # @param attr [::Symbol]
254
+ #
255
+ # @return [::Enumerable]
256
+ def assert_same_count(other, attr)
257
+ # @type [::Enumerable]
258
+ arr1 = self.send(attr)
259
+ raise "Expected #{attr} on #{self} to be an Enumerable, got #{arr1.class}" unless arr1.is_a?(::Enumerable)
260
+ # @type [::Enumerable]
261
+ arr2 = other.send(attr)
262
+ raise "Expected #{attr} on #{other} to be an Enumerable, got #{arr2.class}" unless arr2.is_a?(::Enumerable)
263
+ return arr1 if arr1.count == arr2.count
264
+ Solargraph.assert_or_log("combine_with_#{attr}".to_sym,
265
+ "Inconsistent #{attr.inspect} count value between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{arr1.inspect}\nother.#{attr} = #{arr2.inspect}")
266
+ arr1
267
+ end
268
+
269
+ # @param other [self]
270
+ # @param attr [::Symbol]
271
+ #
272
+ # @return [Object, nil]
273
+ def assert_same(other, attr)
274
+ return false if other.nil?
275
+ val1 = send(attr)
276
+ val2 = other.send(attr)
277
+ return val1 if val1 == val2
278
+ Solargraph.assert_or_log("combine_with_#{attr}".to_sym,
279
+ "Inconsistent #{attr.inspect} values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}")
280
+ val1
281
+ end
282
+
283
+ # @param other [self]
284
+ # @param attr [::Symbol]
285
+ # @sg-ignore
286
+ # @return [undefined]
287
+ def choose_pin_attr_with_same_name(other, attr)
288
+ # @type [Pin::Base, nil]
289
+ val1 = send(attr)
290
+ # @type [Pin::Base, nil]
291
+ val2 = other.send(attr)
292
+ raise "Expected pin for #{attr} on\n#{self.inspect},\ngot #{val1.inspect}" unless val1.nil? || val1.is_a?(Pin::Base)
293
+ raise "Expected pin for #{attr} on\n#{other.inspect},\ngot #{val2.inspect}" unless val2.nil? || val2.is_a?(Pin::Base)
294
+ if val1&.name != val2&.name
295
+ Solargraph.assert_or_log("combine_with_#{attr}_name".to_sym,
296
+ "Inconsistent #{attr.inspect} name values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}")
297
+ end
298
+ choose_pin_attr(other, attr)
299
+ end
300
+
301
+ # @param other [self]
302
+ # @param attr [::Symbol]
303
+ # @return [undefined]
304
+ def choose_pin_attr(other, attr)
305
+ # @type [Pin::Base, nil]
306
+ val1 = send(attr)
307
+ # @type [Pin::Base, nil]
308
+ val2 = other.send(attr)
309
+ if val1.class != val2.class
310
+ Solargraph.assert_or_log("combine_with_#{attr}_class".to_sym,
311
+ "Inconsistent #{attr.inspect} class values between \nself =#{inspect} and \nother=#{other.inspect}:\n\n self.#{attr} = #{val1.inspect}\nother.#{attr} = #{val2.inspect}")
312
+ return val1
313
+ end
314
+ # arbitrary way of choosing a pin
315
+ [val1, val2].compact.min_by { _1.best_location.to_s }
316
+ end
317
+
318
+ # @return [void]
319
+ def assert_source_provided
320
+ Solargraph.assert_or_log(:source, "source not provided - #{@path} #{@source} #{self.class}") if source.nil?
41
321
  end
42
322
 
43
323
  # @return [String]
@@ -134,6 +414,7 @@ module Solargraph
134
414
  # Pin equality is determined using the #nearly? method and also
135
415
  # requiring both pins to have the same location.
136
416
  #
417
+ # @param other [self]
137
418
  def == other
138
419
  return false unless nearly? other
139
420
  comments == other.comments && location == other.location
@@ -148,13 +429,13 @@ module Solargraph
148
429
 
149
430
  # @return [YARD::Docstring]
150
431
  def docstring
151
- parse_comments unless defined?(@docstring)
432
+ parse_comments unless @docstring
152
433
  @docstring ||= Solargraph::Source.parse_docstring('').to_docstring
153
434
  end
154
435
 
155
436
  # @return [::Array<YARD::Tags::Directive>]
156
437
  def directives
157
- parse_comments unless defined?(@directives)
438
+ parse_comments unless @directives
158
439
  @directives
159
440
  end
160
441
 
@@ -172,7 +453,7 @@ module Solargraph
172
453
  #
173
454
  # @return [Boolean]
174
455
  def maybe_directives?
175
- return !@directives.empty? if defined?(@directives)
456
+ return !@directives.empty? if defined?(@directives) && @directives
176
457
  @maybe_directives ||= comments.include?('@!')
177
458
  end
178
459
 
@@ -211,26 +492,6 @@ module Solargraph
211
492
  probe api_map
212
493
  end
213
494
 
214
- # Try to merge data from another pin. Merges are only possible if the
215
- # pins are near matches (see the #nearly? method). The changes should
216
- # not have any side effects on the API surface.
217
- #
218
- # @param pin [Pin::Base] The pin to merge into this one
219
- # @return [Boolean] True if the pins were merged
220
- def try_merge! pin
221
- return false unless nearly?(pin)
222
- @location = pin.location
223
- @closure = pin.closure
224
- return true if comments == pin.comments
225
- @comments = pin.comments
226
- @docstring = pin.docstring
227
- @return_type = pin.return_type
228
- @documentation = nil
229
- @deprecated = nil
230
- reset_conversions
231
- true
232
- end
233
-
234
495
  def proxied?
235
496
  @proxied ||= false
236
497
  end
@@ -268,7 +529,7 @@ module Solargraph
268
529
  # @deprecated
269
530
  # @return [String]
270
531
  def identity
271
- @identity ||= "#{closure&.path}|#{name}"
532
+ @identity ||= "#{closure&.path}|#{name}|#{location}"
272
533
  end
273
534
 
274
535
  # @return [String, nil]
@@ -293,14 +554,37 @@ module Solargraph
293
554
  end
294
555
 
295
556
  # @return [String]
296
- def desc
557
+ def inner_desc
297
558
  closure_info = closure&.desc
298
559
  binder_info = binder&.desc
299
- "[#{type_desc}, closure=#{closure_info}, binder=#{binder}"
560
+ "name=#{name.inspect} return_type=#{type_desc}, context=#{context.rooted_tags}, closure=#{closure_info}, binder=#{binder_info}"
561
+ end
562
+
563
+ # @return [String]
564
+ def desc
565
+ "[#{inner_desc}]"
300
566
  end
301
567
 
568
+ # @return [String]
302
569
  def inspect
303
- "#<#{self.class} `#{self.desc}` at #{self.location.inspect}>"
570
+ "#<#{self.class} `#{self.inner_desc}`#{all_location_text} via #{source.inspect}>"
571
+ end
572
+
573
+ # @return [String]
574
+ def all_location_text
575
+ if location.nil? && type_location.nil?
576
+ ''
577
+ elsif !location.nil? && type_location.nil?
578
+ " at #{location.inspect})"
579
+ elsif !type_location.nil? && location.nil?
580
+ " at #{type_location.inspect})"
581
+ else
582
+ " at (#{location.inspect} and #{type_location.inspect})"
583
+ end
584
+ end
585
+
586
+ # @return [void]
587
+ def reset_generated!
304
588
  end
305
589
 
306
590
  protected
@@ -314,6 +598,10 @@ module Solargraph
314
598
  # @return [ComplexType]
315
599
  attr_writer :return_type
316
600
 
601
+ attr_writer :docstring
602
+
603
+ attr_writer :directives
604
+
317
605
  private
318
606
 
319
607
  # @return [void]
@@ -11,12 +11,23 @@ module Solargraph
11
11
 
12
12
  attr_accessor :mass_assignment
13
13
 
14
+ # @param return_type [ComplexType, nil]
14
15
  # @param assignment [Parser::AST::Node, nil]
15
- def initialize assignment: nil, **splat
16
+ def initialize assignment: nil, return_type: nil, **splat
16
17
  super(**splat)
17
18
  @assignment = assignment
18
19
  # @type [nil, ::Array(Parser::AST::Node, Integer)]
19
20
  @mass_assignment = nil
21
+ @return_type = return_type
22
+ end
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)
20
31
  end
21
32
 
22
33
  def completion_item_kind
@@ -32,7 +43,10 @@ module Solargraph
32
43
  @return_type ||= generate_complex_type
33
44
  end
34
45
 
46
+ # @sg-ignore
35
47
  def nil_assignment?
48
+ # this will always be false - should it be return_type ==
49
+ # ComplexType::NIL or somesuch?
36
50
  return_type.nil?
37
51
  end
38
52
 
@@ -88,19 +102,12 @@ module Solargraph
88
102
  ComplexType::UNDEFINED
89
103
  end
90
104
 
105
+ # @param other [Object]
91
106
  def == other
92
107
  return false unless super
93
108
  assignment == other.assignment
94
109
  end
95
110
 
96
- # @param pin [self]
97
- def try_merge! pin
98
- return false unless super
99
- @assignment = pin.assignment
100
- @return_type = pin.return_type
101
- true
102
- end
103
-
104
111
  def type_desc
105
112
  "#{super} = #{assignment&.type.inspect}"
106
113
  end
@@ -3,6 +3,8 @@
3
3
  module Solargraph
4
4
  module Pin
5
5
  class Block < Callable
6
+ include Breakable
7
+
6
8
  # @return [Parser::AST::Node]
7
9
  attr_reader :receiver
8
10
 
@@ -0,0 +1,9 @@
1
+ module Solargraph
2
+ module Pin
3
+ # Mix-in for pins which enclose code which the 'break' statement works with-in - e.g., blocks, when, until, ...
4
+ module Breakable
5
+ # @return [Parser::AST::Node]
6
+ attr_reader :node
7
+ end
8
+ end
9
+ 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 ||= ''
@@ -24,8 +24,26 @@ module Solargraph
24
24
  @receiver_method_name = receiver_method_name
25
25
  end
26
26
 
27
- %i[comments parameters return_type location].each do |method|
27
+ def inner_desc
28
+ "#{name} => #{@receiver_chain}##{@receiver_method_name}"
29
+ end
30
+
31
+ def location
32
+ return super if super
33
+
34
+ @resolved_method&.send(:location)
35
+ end
36
+
37
+
38
+ def type_location
39
+ return super if super
40
+
41
+ @resolved_method&.send(:type_location)
42
+ end
43
+
44
+ %i[comments parameters return_type signatures].each do |method|
28
45
  define_method(method) do
46
+ # @sg-ignore Need to set context correctly in define_method blocks
29
47
  @resolved_method ? @resolved_method.send(method) : super()
30
48
  end
31
49
  end
@@ -34,6 +52,7 @@ module Solargraph
34
52
  # @param api_map [ApiMap]
35
53
  define_method(method) do |api_map|
36
54
  resolve_method(api_map)
55
+ # @sg-ignore Need to set context correctly in define_method blocks
37
56
  @resolved_method ? @resolved_method.send(method, api_map) : super(api_map)
38
57
  end
39
58
  end