solargraph 0.59.1 → 0.60.0

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +6 -0
  3. data/.github/workflows/plugins.yml +8 -0
  4. data/.github/workflows/rspec.yml +4 -1
  5. data/.github/workflows/typecheck.yml +2 -0
  6. data/.rubocop.yml +1 -0
  7. data/.rubocop_todo.yml +1 -1
  8. data/CHANGELOG.md +18 -0
  9. data/Gemfile +3 -0
  10. data/lib/solargraph/api_map/index.rb +13 -2
  11. data/lib/solargraph/api_map/store.rb +22 -8
  12. data/lib/solargraph/api_map.rb +38 -8
  13. data/lib/solargraph/complex_type/type_methods.rb +1 -0
  14. data/lib/solargraph/complex_type/unique_type.rb +16 -13
  15. data/lib/solargraph/complex_type.rb +5 -0
  16. data/lib/solargraph/convention/active_support_concern.rb +111 -111
  17. data/lib/solargraph/convention/base.rb +50 -50
  18. data/lib/solargraph/diagnostics.rb +55 -55
  19. data/lib/solargraph/doc_map.rb +1 -0
  20. data/lib/solargraph/environ.rb +52 -52
  21. data/lib/solargraph/gem_pins.rb +0 -11
  22. data/lib/solargraph/language_server/message/extended/environment.rb +25 -25
  23. data/lib/solargraph/language_server/message/initialized.rb +28 -28
  24. data/lib/solargraph/language_server/message/text_document.rb +28 -28
  25. data/lib/solargraph/language_server/progress.rb +143 -143
  26. data/lib/solargraph/language_server/transport/adapter.rb +68 -68
  27. data/lib/solargraph/language_server.rb +20 -20
  28. data/lib/solargraph/parser/parser_gem/node_chainer.rb +1 -0
  29. data/lib/solargraph/parser/parser_gem/node_methods.rb +42 -0
  30. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +24 -24
  31. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +36 -36
  32. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +24 -24
  33. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +24 -24
  34. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +29 -5
  35. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +20 -20
  36. data/lib/solargraph/pin/base.rb +31 -3
  37. data/lib/solargraph/pin/callable.rb +2 -2
  38. data/lib/solargraph/pin/common.rb +12 -0
  39. data/lib/solargraph/pin/method.rb +56 -16
  40. data/lib/solargraph/pin/reference/require.rb +14 -14
  41. data/lib/solargraph/pin/singleton.rb +11 -11
  42. data/lib/solargraph/rbs_map/conversions.rb +103 -145
  43. data/lib/solargraph/rbs_translator.rb +206 -0
  44. data/lib/solargraph/shell.rb +131 -64
  45. data/lib/solargraph/source/chain/array.rb +1 -12
  46. data/lib/solargraph/source/chain/block_symbol.rb +13 -13
  47. data/lib/solargraph/source/chain/block_variable.rb +13 -13
  48. data/lib/solargraph/source/chain/call.rb +8 -76
  49. data/lib/solargraph/source/chain/head.rb +19 -19
  50. data/lib/solargraph/source/chain/literal.rb +18 -14
  51. data/lib/solargraph/source/source_chainer.rb +4 -4
  52. data/lib/solargraph/source_map/mapper.rb +5 -135
  53. data/lib/solargraph/source_map.rb +14 -0
  54. data/lib/solargraph/version.rb +19 -1
  55. data/lib/solargraph/yard_map/cache.rb +25 -25
  56. data/lib/solargraph/yard_map/directives/attribute_directive.rb +65 -0
  57. data/lib/solargraph/yard_map/directives/domain_directive.rb +30 -0
  58. data/lib/solargraph/yard_map/directives/method_directive.rb +51 -0
  59. data/lib/solargraph/yard_map/directives/override_directive.rb +30 -0
  60. data/lib/solargraph/yard_map/directives/parse_directive.rb +53 -0
  61. data/lib/solargraph/yard_map/directives/visibility_directive.rb +70 -0
  62. data/lib/solargraph/yard_map/directives.rb +35 -0
  63. data/lib/solargraph/yard_map/macro.rb +113 -0
  64. data/lib/solargraph/yard_map/mapper/to_constant.rb +28 -28
  65. data/lib/solargraph/yard_map/mapper.rb +19 -1
  66. data/lib/solargraph/yard_map.rb +2 -0
  67. data/lib/solargraph.rb +1 -0
  68. data/solargraph.gemspec +1 -0
  69. metadata +24 -2
  70. data/rbs/fills/tuple/tuple.rbs +0 -177
@@ -1,24 +1,24 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Parser
5
- module ParserGem
6
- module NodeProcessors
7
- class AliasNode < Parser::NodeProcessor::Base
8
- def process
9
- loc = get_node_location(node)
10
- pins.push Solargraph::Pin::MethodAlias.new(
11
- location: loc,
12
- closure: region.closure,
13
- name: node.children[0].children[0].to_s,
14
- original: node.children[1].children[0].to_s,
15
- scope: region.scope || :instance,
16
- source: :parser
17
- )
18
- process_children
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class AliasNode < Parser::NodeProcessor::Base
8
+ def process
9
+ loc = get_node_location(node)
10
+ pins.push Solargraph::Pin::MethodAlias.new(
11
+ location: loc,
12
+ closure: region.closure,
13
+ name: node.children[0].children[0].to_s,
14
+ original: node.children[1].children[0].to_s,
15
+ scope: region.scope || :instance,
16
+ source: :parser
17
+ )
18
+ process_children
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,36 +1,36 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Parser
5
- module ParserGem
6
- module NodeProcessors
7
- class CasgnNode < Parser::NodeProcessor::Base
8
- include ParserGem::NodeMethods
9
-
10
- def process
11
- pins.push Solargraph::Pin::Constant.new(
12
- location: get_node_location(node),
13
- closure: region.closure,
14
- name: const_name,
15
- comments: comments_for(node),
16
- assignment: node.children[2],
17
- source: :parser
18
- )
19
- process_children
20
- end
21
-
22
- private
23
-
24
- # @return [String]
25
- def const_name
26
- if node.children[0]
27
- Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
28
- else
29
- node.children[1].to_s
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
36
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class CasgnNode < Parser::NodeProcessor::Base
8
+ include ParserGem::NodeMethods
9
+
10
+ def process
11
+ pins.push Solargraph::Pin::Constant.new(
12
+ location: get_node_location(node),
13
+ closure: region.closure,
14
+ name: const_name,
15
+ comments: comments_for(node),
16
+ assignment: node.children[2],
17
+ source: :parser
18
+ )
19
+ process_children
20
+ end
21
+
22
+ private
23
+
24
+ # @return [String]
25
+ def const_name
26
+ if node.children[0]
27
+ Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
28
+ else
29
+ node.children[1].to_s
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,24 +1,24 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Parser
5
- module ParserGem
6
- module NodeProcessors
7
- class CvasgnNode < Parser::NodeProcessor::Base
8
- def process
9
- loc = get_node_location(node)
10
- pins.push Solargraph::Pin::ClassVariable.new(
11
- location: loc,
12
- closure: region.closure,
13
- name: node.children[0].to_s,
14
- comments: comments_for(node),
15
- assignment: node.children[1],
16
- source: :parser
17
- )
18
- process_children
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class CvasgnNode < Parser::NodeProcessor::Base
8
+ def process
9
+ loc = get_node_location(node)
10
+ pins.push Solargraph::Pin::ClassVariable.new(
11
+ location: loc,
12
+ closure: region.closure,
13
+ name: node.children[0].to_s,
14
+ comments: comments_for(node),
15
+ assignment: node.children[1],
16
+ source: :parser
17
+ )
18
+ process_children
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,24 +1,24 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Parser
5
- module ParserGem
6
- module NodeProcessors
7
- class GvasgnNode < Parser::NodeProcessor::Base
8
- def process
9
- loc = get_node_location(node)
10
- pins.push Solargraph::Pin::GlobalVariable.new(
11
- location: loc,
12
- closure: region.closure,
13
- name: node.children[0].to_s,
14
- comments: comments_for(node),
15
- assignment: node.children[1],
16
- source: :parser
17
- )
18
- process_children
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class GvasgnNode < Parser::NodeProcessor::Base
8
+ def process
9
+ loc = get_node_location(node)
10
+ pins.push Solargraph::Pin::GlobalVariable.new(
11
+ location: loc,
12
+ closure: region.closure,
13
+ name: node.children[0].to_s,
14
+ comments: comments_for(node),
15
+ assignment: node.children[1],
16
+ source: :parser
17
+ )
18
+ process_children
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -8,22 +8,27 @@ module Solargraph
8
8
  include ParserGem::NodeMethods
9
9
 
10
10
  def process
11
- superclass_name = nil
12
- superclass_name = unpack_name(node.children[1]) if node.type == :class && node.children[1]&.type == :const
11
+ name = unpack_name(node.children[0])
12
+ comments = comments_for(node)
13
+
14
+ superclass_name = if node.type == :class && node.children[1]&.type == :const
15
+ "#{type_from_node}#{parameters_from_inline_rbs}"
16
+ end
13
17
 
14
18
  loc = get_node_location(node)
15
19
  nspin = Solargraph::Pin::Namespace.new(
16
20
  type: node.type,
17
21
  location: loc,
18
22
  closure: region.closure,
19
- name: unpack_name(node.children[0]),
20
- comments: comments_for(node),
23
+ name: name,
24
+ comments: comments,
21
25
  visibility: :public,
22
26
  gates: region.closure.gates.freeze,
23
27
  source: :parser
24
28
  )
25
29
  pins.push nspin
26
- unless superclass_name.nil?
30
+ Solargraph.logger.warn "Superclass: #{superclass_name}" if superclass_name&.start_with?('Array')
31
+ if superclass_name
27
32
  pins.push Pin::Reference::Superclass.new(
28
33
  location: loc,
29
34
  closure: pins.last,
@@ -33,6 +38,25 @@ module Solargraph
33
38
  end
34
39
  process_children region.update(closure: nspin, visibility: :public)
35
40
  end
41
+
42
+ private
43
+
44
+ # @param comments [String]
45
+ # @return [String, nil]
46
+ def parameters_from_inline_rbs
47
+ source = region.source.code_for(node)
48
+ match = source.match(/[^\n]*?#\s?+\[([^\]]*)/)
49
+ return unless match && match[1]
50
+
51
+ code = match[1].strip
52
+ return if code.empty?
53
+
54
+ "<#{code}>"
55
+ end
56
+
57
+ def type_from_node
58
+ unpack_name(node.children[1]) if node.children[1]&.type == :const
59
+ end
36
60
  end
37
61
  end
38
62
  end
@@ -1,20 +1,20 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Parser
5
- module ParserGem
6
- module NodeProcessors
7
- class SymNode < Parser::NodeProcessor::Base
8
- # @return [void]
9
- def process
10
- pins.push Solargraph::Pin::Symbol.new(
11
- get_node_location(node),
12
- ":#{node.children[0]}",
13
- source: :parser
14
- )
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class SymNode < Parser::NodeProcessor::Base
8
+ # @return [void]
9
+ def process
10
+ pins.push Solargraph::Pin::Symbol.new(
11
+ get_node_location(node),
12
+ ":#{node.children[0]}",
13
+ source: :parser
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -534,11 +534,20 @@ module Solargraph
534
534
  @directives
535
535
  end
536
536
 
537
- # @return [::Array<YARD::Tags::MacroDirective>]
537
+ # @return [::Array<Solargraph::YardMap::Macro>]
538
538
  def macros
539
539
  @macros ||= collect_macros
540
540
  end
541
541
 
542
+ def macro_names
543
+ parse_comments unless @macro_names
544
+ @macro_names ||= collect_macro_names
545
+ end
546
+
547
+ def macro_names?
548
+ macro_names.any?
549
+ end
550
+
542
551
  # Perform a quick check to see if this pin possibly includes YARD
543
552
  # directives. This method does not require parsing the comments.
544
553
  #
@@ -569,6 +578,15 @@ module Solargraph
569
578
  return_type.qualify(api_map, *(closure&.gates || ['']))
570
579
  end
571
580
 
581
+ # @todo Candidate for deprecation (see ApiMap#process_macros)
582
+ def maybe_macros?
583
+ comments.include?('@macro')
584
+ end
585
+
586
+ def macros_names?
587
+ macro_names.any?
588
+ end
589
+
572
590
  # Infer the pin's return type via static code analysis.
573
591
  #
574
592
  # @param api_map [ApiMap]
@@ -619,6 +637,8 @@ module Solargraph
619
637
  result = dup
620
638
  result.return_type = return_type
621
639
  result.proxied = true
640
+ # Macros should have been processed already
641
+ result.macro_names.clear
622
642
  result
623
643
  end
624
644
 
@@ -717,12 +737,14 @@ module Solargraph
717
737
  if comments.nil? || comments.empty? || comments.strip.end_with?('@overload')
718
738
  @docstring = nil
719
739
  @directives = []
740
+ @macro_names = []
720
741
  else
721
742
  # HACK: Pass a dummy code object to the parser for plugins that
722
743
  # expect it not to be nil
723
744
  parse = Solargraph::Source.parse_docstring(comments)
724
745
  @docstring = parse.to_docstring
725
746
  @directives = parse.directives
747
+ @macro_names = collect_macro_names
726
748
  end
727
749
  end
728
750
 
@@ -762,11 +784,17 @@ module Solargraph
762
784
  tag1.types == tag2.types
763
785
  end
764
786
 
765
- # @return [::Array<YARD::Tags::Handlers::Directive>]
787
+ # @return [::Array<Solargraph::YardMap::Macro>]
766
788
  def collect_macros
767
789
  return [] unless maybe_directives?
768
790
  parse = Solargraph::Source.parse_docstring(comments)
769
- parse.directives.select { |d| d.tag.tag_name == 'macro' }
791
+ parse.directives.select { |d| d.tag.tag_name == 'macro' }.map do |macro_directive|
792
+ Solargraph::YardMap::Macro.from_directive macro_directive, self
793
+ end
794
+ end
795
+
796
+ def collect_macro_names
797
+ "#{comments}\n".scan(/\s*?@macro +(\S+).*?[\n]/).map { |match| match[0] }
770
798
  end
771
799
  end
772
800
  end
@@ -161,8 +161,8 @@ module Solargraph
161
161
  end
162
162
 
163
163
  def typify api_map
164
- type = super
165
- return type if type.defined?
164
+ type = return_type
165
+ return type.qualify(api_map, *gates) if type.defined?
166
166
  if method_name.end_with?('?')
167
167
  logger.debug { "Callable#typify(self=#{self}) => Boolean (? suffix)" }
168
168
  ComplexType::BOOLEAN
@@ -72,6 +72,18 @@ module Solargraph
72
72
  @path ||= name.empty? ? context.namespace : "#{context.namespace}::#{name}"
73
73
  end
74
74
 
75
+ # @yieldparam [Pin::Base]
76
+ # @return [void, Enumerator<Pin::Base>]
77
+ def each_closure &block
78
+ return enum_for(:each_closure) unless block_given?
79
+
80
+ here = closure
81
+ until here.nil?
82
+ yield here
83
+ here = here&.closure
84
+ end
85
+ end
86
+
75
87
  protected
76
88
 
77
89
  attr_writer :context
@@ -143,7 +143,7 @@ module Solargraph
143
143
  end
144
144
 
145
145
  def return_type
146
- @return_type ||= ComplexType.new(signatures.map(&:return_type).flat_map(&:items))
146
+ @return_type ||= return_type_from_inline_rbs || ComplexType.new(signatures.map(&:return_type).flat_map(&:items))
147
147
  end
148
148
 
149
149
  # @param parameters [::Array<Parameter>]
@@ -188,18 +188,11 @@ module Solargraph
188
188
 
189
189
  # @return [::Array<Signature>]
190
190
  def signatures
191
- @signatures ||= begin
192
- top_type = generate_complex_type
193
- result = []
194
- result.push generate_signature(parameters, top_type) if top_type.defined?
195
- unless overloads.empty?
196
- result.concat(overloads.map do |meth|
197
- generate_signature(meth.parameters, meth.return_type)
198
- end)
199
- end
200
- result.push generate_signature(parameters, @return_type || ComplexType::UNDEFINED) if result.empty?
201
- result
202
- end
191
+ @signatures ||= if inline_rbs.empty?
192
+ signatures_from_yard
193
+ else
194
+ signatures_from_inline_rbs
195
+ end
203
196
  end
204
197
 
205
198
  # @param return_type [ComplexType]
@@ -279,7 +272,19 @@ module Solargraph
279
272
  # @sg-ignore Need to add nil check here
280
273
  "Method#typify(self=#{self}, binder=#{binder}, closure=#{closure}, context=#{context.rooted_tags}, return_type=#{return_type.rooted_tags}) - starting"
281
274
  end
282
- decl = super
275
+ decl = if macro_names?
276
+ types = macro_names.flat_map do |mac|
277
+ directive = api_map.named_macro(mac)
278
+ next unless directive
279
+ macro = Solargraph::YardMap::Macro.from_directive(directive, self)
280
+ expanded = macro.macro_object.expand([name, *parameter_names])
281
+ docstring = Solargraph::Source.parse_docstring(expanded).to_docstring
282
+ docstring.tags(:return).flat_map(&:types)
283
+ end
284
+ ComplexType.try_parse(*types)
285
+ else
286
+ super
287
+ end
283
288
  unless decl.undefined?
284
289
  logger.debug do
285
290
  "Method#typify(self=#{self}, binder=#{binder}, closure=#{closure}, context=#{context}) => #{decl.rooted_tags.inspect} - decl found"
@@ -451,7 +456,6 @@ module Solargraph
451
456
 
452
457
  attr_writer :block, :signature_help, :documentation, :return_type
453
458
 
454
- # @sg-ignore Need to add nil check here
455
459
  def dodgy_visibility_source?
456
460
  # as of 2025-03-12, the RBS generator used for
457
461
  # e.g. activesupport did not understand 'private' markings
@@ -505,7 +509,8 @@ module Solargraph
505
509
  #
506
510
  # @return [Array<Pin::Signature>]
507
511
  def combine_same_type_arity_signatures same_type_arity_signatures
508
- # @todo Stubbing this method while we debug an infinite loop bug in Ruby 3.x
512
+ # @todo Stubbing this method while we debug an infinite loop bug in Ruby 3.x.
513
+ # The body below is intentionally preserved for when the stub is removed.
509
514
  return same_type_arity_signatures
510
515
 
511
516
  # rubocop:disable Lint/UnreachableCode
@@ -721,6 +726,41 @@ module Solargraph
721
726
  .join("\n")
722
727
  .concat("```\n")
723
728
  end
729
+
730
+ # @return [ComplexType, nil]
731
+ def return_type_from_inline_rbs
732
+ return nil if inline_rbs.empty?
733
+ method_type = RBS::Parser.parse_method_type(inline_rbs)
734
+ RbsTranslator.to_complex_type(method_type.type.return_type)
735
+ rescue RBS::ParsingError
736
+ nil
737
+ end
738
+
739
+ # @return [Array<Pin::Signature>]
740
+ def signatures_from_inline_rbs
741
+ method_type = RBS::Parser.parse_method_type(inline_rbs)
742
+ [RbsTranslator.to_signature(method_type, self, parameter_names)]
743
+ rescue RBS::ParsingError
744
+ signatures_from_yard
745
+ end
746
+
747
+ # @return [Array<Pin::Signature>]
748
+ def signatures_from_yard
749
+ top_type = generate_complex_type
750
+ result = []
751
+ result.push generate_signature(parameters, top_type) if top_type.defined?
752
+ result.concat(overloads.map { |meth| generate_signature(meth.parameters, meth.return_type) }) unless overloads.empty?
753
+ result.push generate_signature(parameters, @return_type || ComplexType::UNDEFINED) if result.empty?
754
+ result
755
+ end
756
+
757
+ # @return [String]
758
+ def inline_rbs
759
+ comments.lines
760
+ .select { |line| line.start_with?(': ') }
761
+ .map { |line| line[2..].strip }
762
+ .join("\n")
763
+ end
724
764
  end
725
765
  end
726
766
  end
@@ -1,14 +1,14 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Pin
5
- class Reference
6
- class Require < Reference
7
- def initialize location, name, **splat
8
- # super(location, '', name)
9
- super(location: location, name: name, closure: Pin::ROOT_PIN, **splat)
10
- end
11
- end
12
- end
13
- end
14
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ class Reference
6
+ class Require < Reference
7
+ def initialize location, name, **splat
8
+ # super(location, '', name)
9
+ super(location: location, name: name, closure: Pin::ROOT_PIN, **splat)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,11 +1,11 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Pin
5
- class Singleton < Closure
6
- def initialize name: '', location: nil, closure: nil, **splat
7
- super
8
- end
9
- end
10
- end
11
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ class Singleton < Closure
6
+ def initialize name: '', location: nil, closure: nil, **splat
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end