solargraph 0.59.0 → 0.59.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48702da784ad5e4ba9333e3389532a20af5bd0474cde01f0b00b9b07a53203ce
4
- data.tar.gz: 93df9a47dde759e2de2f92f6e65609e4de5ba83403c4f481915e984d05111bab
3
+ metadata.gz: 9346852d9ba48c677a63c6ac2dd3bf6b7cb536309f28569c256bc8654c19c865
4
+ data.tar.gz: 9fd017aedc2b705156999d93f5bc8f5f6b99cd7cc3716565ef42ab26936336eb
5
5
  SHA512:
6
- metadata.gz: 40c2a0be04ee36e8c0c7328e51e751c04becaddd5f405a302ec369bb7bae365705f75bf3852c1c99183e8ac00d58a61177216e75f60b2af9fb0d064c95496715
7
- data.tar.gz: 41c1a1dd7c926debbb79a8f63b24e550d6b3a389ad71f09e392ce8216b66fa33b73d2a6269d5b624ecdf5aa86add0a81e40c2b3b24483a4555fb3a53d61e1e9c
6
+ metadata.gz: 5b8d3c627dec8757b70444e444a66dd024818f3e62e7c8d9ea57a638182de64524cca532c7b8ae9c5944d373cfdb2e0f3a1ede46e1e8b3e4e728d02b2f9db0e0
7
+ data.tar.gz: 41321b8ad277092a434241bc099488c99c721fb7bf593cb3c41f703329ba2d90e2416b5f407ed858db69776d02eb9bb3c93025d094de6f4413fd368f933a7398
@@ -23,7 +23,7 @@ jobs:
23
23
  - name: Set up Ruby
24
24
  uses: ruby/setup-ruby@v1
25
25
  with:
26
- ruby-version: 3.4 # keep same as typecheck.yml
26
+ ruby-version: 4.0 # keep same as typecheck.yml
27
27
  bundler-cache: true
28
28
  - uses: awalsh128/cache-apt-pkgs-action@latest
29
29
  with:
@@ -27,7 +27,7 @@ jobs:
27
27
  - name: Set up Ruby
28
28
  uses: ruby/setup-ruby@v1
29
29
  with:
30
- ruby-version: 3.4
30
+ ruby-version: 4.0
31
31
  bundler-cache: false
32
32
  - name: Install gems
33
33
  run: |
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.59.1 - May 18, 2026
2
+ - Fix signatureHelp bug (#1185)
3
+ - Linting fixes for Ruby 3.1 (#1193)
4
+ - Parameters shadow local variables with same name (#1192)
5
+
1
6
  ## 0.59.0 - May 13, 2026
2
7
  - Ensure pathname is required for rbs in shell caching processes (#1183)
3
8
  - Pre-release branch 2026-01-12 (#1152)
@@ -482,8 +482,8 @@ module Solargraph
482
482
  # @yieldparam t [self]
483
483
  # @yieldreturn [self]
484
484
  # @return [Enumerable<self>]
485
- def each &block
486
- [self].each(&block)
485
+ def each(&)
486
+ [self].each(&)
487
487
  end
488
488
 
489
489
  # @return [Array<UniqueType>]
@@ -166,7 +166,7 @@ module Solargraph
166
166
  # @param name [Symbol]
167
167
  # @param include_private [Boolean]
168
168
  def respond_to_missing? name, include_private = false
169
- TypeMethods.public_instance_methods.include?(name) || super
169
+ TypeMethods.public_method_defined?(name) || super
170
170
  end
171
171
 
172
172
  def to_s
@@ -648,15 +648,14 @@ module Solargraph
648
648
  # @param text [String]
649
649
  # @param type [Integer] A MessageType constant
650
650
  # @param actions [Array<String>] Response options for the client
651
- # @param block [Proc] The block that processes the response
652
651
  # @yieldparam [String] The action received from the client
653
652
  # @return [void]
654
- def show_message_request text, type, actions, &block
655
- send_request 'window/showMessageRequest', {
656
- type: type,
657
- message: text,
658
- actions: actions
659
- }, &block
653
+ def show_message_request(text, type, actions, &)
654
+ send_request('window/showMessageRequest', {
655
+ type: type,
656
+ message: text,
657
+ actions: actions
658
+ }, &)
660
659
  end
661
660
 
662
661
  # Get a list of IDs for server requests that are waiting for responses
@@ -4,6 +4,7 @@ require 'parser'
4
4
  require 'ast'
5
5
 
6
6
  # https://github.com/whitequark/parser
7
+ # rubocop:disable Metrics/ModuleLength
7
8
  module Solargraph
8
9
  module Parser
9
10
  module ParserGem
@@ -246,15 +247,100 @@ module Solargraph
246
247
  end
247
248
  prev = node
248
249
  end
249
- nil
250
+ find_recipient_node_by_text(source, offset)
251
+ end
252
+
253
+ # Text-based fallback for finding a method call recipient when the AST
254
+ # is unavailable (e.g., unparseable source with syntax errors).
255
+ #
256
+ # Scans backward from cursor offset to find '(' and the method name
257
+ # before it, then creates a minimal :send node.
258
+ #
259
+ # @param source [Solargraph::Source]
260
+ # @param offset [Integer]
261
+ # @return [Parser::AST::Node, nil]
262
+ def find_recipient_node_by_text source, offset
263
+ code = source.code
264
+ return nil if offset.nil? || offset <= 0 || offset > code.length
265
+
266
+ # The '(' could be at offset-1 (cursor after '(') or at offset (cursor on '(')
267
+ start_pos = offset - 1
268
+ if start_pos.positive? && code[start_pos] != '(' && code[offset] == '('
269
+ start_pos = offset
270
+ end
271
+
272
+ # Scan backward to find the matching '(' (handle nested parens)
273
+ depth = 0
274
+ paren_pos = nil
275
+ pos = start_pos
276
+ while pos >= 0
277
+ case code[pos]
278
+ when ')'
279
+ depth += 1
280
+ when '('
281
+ if depth.zero?
282
+ paren_pos = pos
283
+ break
284
+ end
285
+ depth -= 1
286
+ end
287
+ pos -= 1
288
+ end
289
+ return nil if paren_pos.nil?
290
+
291
+ # Skip whitespace before '(' to find method name
292
+ idx = paren_pos - 1
293
+ idx -= 1 while idx >= 0 && code[idx] =~ /\s/
294
+ return nil if idx.negative?
295
+
296
+ # Read method name (including ? and !)
297
+ name_end = idx + 1
298
+ idx -= 1 while idx >= 0 && code[idx] =~ /[a-zA-Z0-9_?!]/
299
+ name_start = idx + 1
300
+ return nil if name_start >= name_end
301
+ method_name = code[name_start...name_end]
302
+ return nil if method_name.empty?
303
+
304
+ # Check for receiver pattern: receiver.method( or receiver::method(
305
+ idx = name_start - 1
306
+ idx -= 1 while idx >= 0 && code[idx] =~ /\s/
307
+ if idx >= 0 && code[idx] == '.'
308
+ idx -= 1
309
+ idx -= 1 while idx >= 0 && code[idx] =~ /\s/
310
+ recv_end = idx + 1
311
+ idx -= 1 while idx >= 0 && code[idx] =~ /[a-zA-Z0-9_@$]/
312
+ recv_start = idx + 1
313
+ if recv_start < recv_end
314
+ recv_name = code[recv_start...recv_end]
315
+ unless recv_name.empty?
316
+ receiver_node = ::Parser::AST::Node.new(:send, [nil, recv_name.to_sym])
317
+ return ::Parser::AST::Node.new(:send, [receiver_node, method_name.to_sym])
318
+ end
319
+ end
320
+ elsif idx >= 0 && idx.positive? && code[idx - 1] == ':' && code[idx] == ':'
321
+ const_end = idx - 1
322
+ const_start = const_end
323
+ const_start -= 1 while const_start.positive? && code[const_start - 1] =~ /[a-zA-Z0-9_]/
324
+ const_name = code[const_start...const_end]
325
+ unless const_name.empty? || method_name.empty?
326
+ const_node = ::Parser::AST::Node.new(:const, [nil, const_name.to_sym])
327
+ return ::Parser::AST::Node.new(:send, [const_node, method_name.to_sym])
328
+ end
329
+ end
330
+
331
+ # Simple method call without receiver
332
+ ::Parser::AST::Node.new(:send, [nil, method_name.to_sym])
250
333
  end
251
334
 
252
335
  # @param cursor [Solargraph::Source::Cursor]
253
336
  # @return [Parser::AST::Node, nil]
254
337
  def repaired_find_recipient_node cursor
255
- cursor = cursor.source.cursor_at([cursor.position.line, cursor.position.column - 1])
256
- node = cursor.source.tree_at(cursor.position.line, cursor.position.column).first
257
- node if node && node.type == :send
338
+ c = cursor.source.cursor_at([cursor.position.line, cursor.position.column - 1])
339
+ tree = c.source.tree_at(c.position.line, c.position.column)
340
+ tree.each do |node|
341
+ return node if node.type == :send
342
+ end
343
+ find_recipient_node_by_text(cursor.source, cursor.offset)
258
344
  end
259
345
 
260
346
  #
@@ -505,3 +591,4 @@ module Solargraph
505
591
  end
506
592
  end
507
593
  end
594
+ # rubocop:enable Metrics/ModuleLength
@@ -1,40 +1,40 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Parser
5
- module ParserGem
6
- module NodeProcessors
7
- class NamespaceNode < Parser::NodeProcessor::Base
8
- include ParserGem::NodeMethods
9
-
10
- def process
11
- superclass_name = nil
12
- superclass_name = unpack_name(node.children[1]) if node.type == :class && node.children[1]&.type == :const
13
-
14
- loc = get_node_location(node)
15
- nspin = Solargraph::Pin::Namespace.new(
16
- type: node.type,
17
- location: loc,
18
- closure: region.closure,
19
- name: unpack_name(node.children[0]),
20
- comments: comments_for(node),
21
- visibility: :public,
22
- gates: region.closure.gates.freeze,
23
- source: :parser
24
- )
25
- pins.push nspin
26
- unless superclass_name.nil?
27
- pins.push Pin::Reference::Superclass.new(
28
- location: loc,
29
- closure: pins.last,
30
- name: superclass_name,
31
- source: :parser
32
- )
33
- end
34
- process_children region.update(closure: nspin, visibility: :public)
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class NamespaceNode < Parser::NodeProcessor::Base
8
+ include ParserGem::NodeMethods
9
+
10
+ def process
11
+ superclass_name = nil
12
+ superclass_name = unpack_name(node.children[1]) if node.type == :class && node.children[1]&.type == :const
13
+
14
+ loc = get_node_location(node)
15
+ nspin = Solargraph::Pin::Namespace.new(
16
+ type: node.type,
17
+ location: loc,
18
+ closure: region.closure,
19
+ name: unpack_name(node.children[0]),
20
+ comments: comments_for(node),
21
+ visibility: :public,
22
+ gates: region.closure.gates.freeze,
23
+ source: :parser
24
+ )
25
+ pins.push nspin
26
+ unless superclass_name.nil?
27
+ pins.push Pin::Reference::Superclass.new(
28
+ location: loc,
29
+ closure: pins.last,
30
+ name: superclass_name,
31
+ source: :parser
32
+ )
33
+ end
34
+ process_children region.update(closure: nspin, visibility: :public)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -293,7 +293,7 @@ module Solargraph
293
293
  # @param attr [::Symbol]
294
294
  # @return [void]
295
295
  # @todo strong typechecking should complain when there are no block-related tags
296
- def assert_same_array_content other, attr, &block
296
+ def assert_same_array_content(other, attr, &)
297
297
  arr1 = send(attr)
298
298
  raise "Expected #{attr} on #{self} to be an Enumerable, got #{arr1.class}" unless arr1.is_a?(::Enumerable)
299
299
  # @type arr1 [::Enumerable]
@@ -302,9 +302,9 @@ module Solargraph
302
302
  # @type arr2 [::Enumerable]
303
303
 
304
304
  # @type [undefined]
305
- values1 = arr1.map(&block)
305
+ values1 = arr1.map(&)
306
306
  # @type [undefined]
307
- values2 = arr2.map(&block)
307
+ values2 = arr2.map(&)
308
308
  # @sg-ignore
309
309
  return arr1 if values1 == values2
310
310
  Solargraph.assert_or_log(:"combine_with_#{attr}",
@@ -508,6 +508,7 @@ module Solargraph
508
508
  # @todo Stubbing this method while we debug an infinite loop bug in Ruby 3.x
509
509
  return same_type_arity_signatures
510
510
 
511
+ # rubocop:disable Lint/UnreachableCode
511
512
  # This is an O(n^2) operation, so bail out if n is not small
512
513
  return same_type_arity_signatures if same_type_arity_signatures.length > 10
513
514
 
@@ -534,6 +535,7 @@ module Solargraph
534
535
  end
535
536
  end
536
537
  end
538
+ # rubocop:enable Lint/UnreachableCode
537
539
  end
538
540
 
539
541
  # @param name [String]
@@ -31,7 +31,9 @@ module Solargraph
31
31
  end
32
32
 
33
33
  def combine_with other, attrs = {}
34
- # Parameters can be combined with local variables
34
+ # Parameters can only be combined with local variables in the same closure
35
+ return self unless other.closure == closure
36
+
35
37
  new_attrs = if other.is_a?(Parameter)
36
38
  {
37
39
  decl: assert_same(other, :decl),
@@ -41,11 +41,11 @@ module Solargraph
41
41
  match = [fuzzy_string_match(pin.path, @query), fuzzy_string_match(pin.name, @query)].max
42
42
  Result.new(match, pin) if match > 0.7
43
43
  end
44
- .compact
45
- # @param a [self]
46
- # @param b [self]
47
- # @sg-ignore https://github.com/castwide/solargraph/pull/1050
48
- .sort { |a, b| b.match <=> a.match }
44
+ .compact
45
+ # @param a [self]
46
+ # @param b [self]
47
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1050
48
+ .sort { |a, b| b.match <=> a.match }
49
49
  .map(&:pin)
50
50
  end
51
51
 
@@ -481,7 +481,7 @@ module Solargraph
481
481
  visibility = VISIBILITY_OVERRIDE[override_key]
482
482
  simple_override_key = [closure.path, scope]
483
483
  visibility ||= VISIBILITY_OVERRIDE[simple_override_key]
484
- if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(decl.name)
484
+ if closure.path == 'Kernel' && Kernel.private_method_defined?(decl.name, false)
485
485
  visibility ||= :private
486
486
  end
487
487
  if decl.kind == :singleton_instance
@@ -115,8 +115,17 @@ module Solargraph
115
115
  def recipient
116
116
  @recipient ||= begin
117
117
  node = recipient_node
118
- # @sg-ignore Need to add nil check here
119
- node ? Cursor.new(source, Range.from_node(node).ending) : nil
118
+ if node.nil?
119
+ nil
120
+ else
121
+ rng = Range.from_node(node)
122
+ if rng
123
+ Cursor.new(source, rng.ending)
124
+ else
125
+ pos = Position.new(position.line, [position.column - 1, 0].max)
126
+ Cursor.new(source, pos)
127
+ end
128
+ end
120
129
  end
121
130
  end
122
131
  alias receiver recipient
@@ -54,8 +54,13 @@ module Solargraph
54
54
  # @return [Array<Pin::Method>]
55
55
  def signify
56
56
  return [] unless cursor.argument?
57
+ return [] if cursor.recipient_node.nil?
57
58
  chain = Parser.chain(cursor.recipient_node, cursor.filename)
58
- chain.define(api_map, context_pin, locals).select { |pin| pin.is_a?(Pin::Method) }
59
+ name_pin = context_pin
60
+ if name_pin.nil?
61
+ name_pin = Pin::ProxyType.anonymous(ComplexType.try_parse('::Object'))
62
+ end
63
+ chain.define(api_map, name_pin, locals).select { |pin| pin.is_a?(Pin::Method) }
59
64
  end
60
65
 
61
66
  # @return [ComplexType]
@@ -283,7 +283,7 @@ module Solargraph
283
283
 
284
284
  # @return [Array<Pin::BaseVariable>]
285
285
  def all_variables
286
- source_map.pins_by_class(Pin::BaseVariable) + source_map.locals.select { |pin| pin.is_a?(Pin::LocalVariable) }
286
+ source_map.pins_by_class(Pin::BaseVariable) + source_map.locals.grep(Pin::LocalVariable)
287
287
  end
288
288
 
289
289
  # @return [Array<Problem>]
@@ -773,9 +773,9 @@ module Solargraph
773
773
  return [] if parameters.any?(&:rest?)
774
774
  opt = optional_param_count(parameters)
775
775
  return [] if unchecked.length <= req + opt
776
- if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (parameters.map(&:decl) & %i[
777
- kwarg kwoptarg kwrestarg
778
- ]).any?
776
+ if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && parameters.map(&:decl).intersect?(%i[
777
+ kwarg kwoptarg kwrestarg
778
+ ])
779
779
  return []
780
780
  end
781
781
  return [] if arguments.length - req == parameters.select { |p| %i[optarg kwoptarg].include?(p.decl) }.length
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = ENV.fetch('SOLARGRAPH_FORCE_VERSION', '0.59.0')
4
+ VERSION = ENV.fetch('SOLARGRAPH_FORCE_VERSION', '0.59.1')
5
5
  end
@@ -32,7 +32,7 @@ module Solargraph
32
32
  # @sg-ignore Need to add nil check here
33
33
  final_visibility ||= VISIBILITY_OVERRIDE[[closure.path, final_scope]]
34
34
  # @sg-ignore Need to add nil check here
35
- if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(name.to_sym)
35
+ if closure.path == 'Kernel' && Kernel.private_method_defined?(name.to_sym, false)
36
36
  final_visibility ||= :private
37
37
  end
38
38
  final_visibility ||= visibility
data/lib/solargraph.rb CHANGED
@@ -113,13 +113,13 @@ module Solargraph
113
113
  # @yieldreturn [generic<T>]
114
114
  # @sg-ignore dynamic call, but both functions behave the same
115
115
  # @return [generic<T>]
116
- def self.with_clean_env &block
116
+ def self.with_clean_env(&)
117
117
  meth = if Bundler.respond_to?(:with_original_env)
118
118
  :with_original_env
119
119
  else
120
120
  :with_clean_env
121
121
  end
122
- Bundler.send meth, &block
122
+ Bundler.send(meth, &)
123
123
  end
124
124
  end
125
125
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.59.0
4
+ version: 0.59.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder