solargraph 0.50.0 → 0.53.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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +40 -0
  3. data/.github/workflows/rspec.yml +4 -8
  4. data/.github/workflows/typecheck.yml +34 -0
  5. data/.yardopts +2 -2
  6. data/CHANGELOG.md +81 -3
  7. data/README.md +13 -16
  8. data/SPONSORS.md +2 -9
  9. data/lib/solargraph/api_map/cache.rb +60 -20
  10. data/lib/solargraph/api_map/store.rb +47 -11
  11. data/lib/solargraph/api_map.rb +161 -95
  12. data/lib/solargraph/bench.rb +2 -2
  13. data/lib/solargraph/cache.rb +30 -6
  14. data/lib/solargraph/complex_type/type_methods.rb +54 -9
  15. data/lib/solargraph/complex_type/unique_type.rb +154 -57
  16. data/lib/solargraph/complex_type.rb +91 -17
  17. data/lib/solargraph/convention.rb +0 -3
  18. data/lib/solargraph/converters/dd.rb +5 -0
  19. data/lib/solargraph/converters/dl.rb +3 -0
  20. data/lib/solargraph/converters/dt.rb +3 -0
  21. data/lib/solargraph/diagnostics/rubocop.rb +8 -7
  22. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
  23. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  24. data/lib/solargraph/diagnostics.rb +2 -2
  25. data/lib/solargraph/doc_map.rb +146 -0
  26. data/lib/solargraph/gem_pins.rb +64 -0
  27. data/lib/solargraph/language_server/host/cataloger.rb +1 -0
  28. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  29. data/lib/solargraph/language_server/host/dispatch.rb +10 -4
  30. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  31. data/lib/solargraph/language_server/host/sources.rb +7 -4
  32. data/lib/solargraph/language_server/host.rb +26 -7
  33. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  34. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  35. data/lib/solargraph/language_server/message/initialize.rb +11 -0
  36. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  37. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  38. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -4
  39. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  40. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  41. data/lib/solargraph/language_server/message/text_document.rb +1 -1
  42. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  43. data/lib/solargraph/language_server/message.rb +1 -0
  44. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  45. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  46. data/lib/solargraph/library.rb +86 -16
  47. data/lib/solargraph/location.rb +1 -0
  48. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  49. data/lib/solargraph/parser/node_methods.rb +47 -7
  50. data/lib/solargraph/parser/node_processor/base.rb +9 -0
  51. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -5
  52. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  53. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
  54. data/lib/solargraph/parser/parser_gem/node_methods.rb +499 -0
  55. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  56. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
  57. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  58. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  59. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
  60. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  61. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +1 -1
  62. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  63. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  65. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  67. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  68. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  69. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +2 -2
  71. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -0
  73. data/lib/solargraph/parser/parser_gem.rb +12 -0
  74. data/lib/solargraph/parser/region.rb +1 -1
  75. data/lib/solargraph/parser/snippet.rb +2 -0
  76. data/lib/solargraph/parser.rb +9 -10
  77. data/lib/solargraph/pin/base.rb +64 -9
  78. data/lib/solargraph/pin/base_variable.rb +6 -2
  79. data/lib/solargraph/pin/block.rb +19 -9
  80. data/lib/solargraph/pin/closure.rb +17 -2
  81. data/lib/solargraph/pin/common.rb +7 -3
  82. data/lib/solargraph/pin/conversions.rb +33 -3
  83. data/lib/solargraph/pin/delegated_method.rb +97 -0
  84. data/lib/solargraph/pin/documenting.rb +25 -34
  85. data/lib/solargraph/pin/instance_variable.rb +4 -0
  86. data/lib/solargraph/pin/local_variable.rb +13 -1
  87. data/lib/solargraph/pin/method.rb +182 -18
  88. data/lib/solargraph/pin/namespace.rb +18 -5
  89. data/lib/solargraph/pin/parameter.rb +44 -14
  90. data/lib/solargraph/pin/reference/override.rb +2 -2
  91. data/lib/solargraph/pin/reference.rb +8 -0
  92. data/lib/solargraph/pin/search.rb +4 -4
  93. data/lib/solargraph/pin/signature.rb +123 -3
  94. data/lib/solargraph/pin.rb +1 -1
  95. data/lib/solargraph/range.rb +4 -6
  96. data/lib/solargraph/rbs_map/conversions.rb +294 -50
  97. data/lib/solargraph/rbs_map/core_fills.rb +7 -24
  98. data/lib/solargraph/rbs_map/core_map.rb +3 -2
  99. data/lib/solargraph/rbs_map/core_signs.rb +2 -0
  100. data/lib/solargraph/rbs_map/stdlib_map.rb +2 -5
  101. data/lib/solargraph/rbs_map.rb +20 -11
  102. data/lib/solargraph/shell.rb +62 -59
  103. data/lib/solargraph/source/chain/array.rb +32 -0
  104. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  105. data/lib/solargraph/source/chain/call.rb +99 -46
  106. data/lib/solargraph/source/chain/constant.rb +15 -1
  107. data/lib/solargraph/source/chain/if.rb +23 -0
  108. data/lib/solargraph/source/chain/link.rb +8 -2
  109. data/lib/solargraph/source/chain/or.rb +1 -1
  110. data/lib/solargraph/source/chain/z_super.rb +3 -3
  111. data/lib/solargraph/source/chain.rb +29 -14
  112. data/lib/solargraph/source/change.rb +3 -0
  113. data/lib/solargraph/source/cursor.rb +2 -0
  114. data/lib/solargraph/source/source_chainer.rb +8 -5
  115. data/lib/solargraph/source.rb +18 -19
  116. data/lib/solargraph/source_map/clip.rb +25 -23
  117. data/lib/solargraph/source_map/mapper.rb +12 -1
  118. data/lib/solargraph/source_map.rb +30 -7
  119. data/lib/solargraph/type_checker/checks.rb +10 -2
  120. data/lib/solargraph/type_checker.rb +123 -45
  121. data/lib/solargraph/version.rb +1 -1
  122. data/lib/solargraph/workspace/config.rb +14 -11
  123. data/lib/solargraph/workspace.rb +3 -2
  124. data/lib/solargraph/yard_map/cache.rb +6 -0
  125. data/lib/solargraph/yard_map/helpers.rb +1 -1
  126. data/lib/solargraph/yard_map/mapper/to_method.rb +11 -1
  127. data/lib/solargraph/yard_map/mapper.rb +1 -1
  128. data/lib/solargraph/yard_map/to_method.rb +11 -4
  129. data/lib/solargraph/yard_map.rb +1 -284
  130. data/lib/solargraph/yard_tags.rb +20 -0
  131. data/lib/solargraph/yardoc.rb +52 -0
  132. data/lib/solargraph.rb +6 -4
  133. data/solargraph.gemspec +11 -5
  134. metadata +131 -75
  135. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  136. data/lib/solargraph/convention/rspec.rb +0 -30
  137. data/lib/solargraph/documentor.rb +0 -76
  138. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  139. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  140. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
  141. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  142. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +0 -23
  143. data/lib/solargraph/parser/legacy/node_processors/gvasgn_node.rb +0 -23
  144. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
  145. data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
  146. data/lib/solargraph/parser/legacy.rb +0 -12
  147. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -149
  148. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  149. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
  150. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  151. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  152. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
  153. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
  154. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
  155. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  156. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  157. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  158. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  159. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  160. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  161. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  162. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
  163. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
  164. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  165. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
  166. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
  167. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
  168. data/lib/solargraph/parser/rubyvm.rb +0 -40
  169. data/lib/yard-solargraph.rb +0 -33
@@ -38,23 +38,20 @@ module Solargraph
38
38
  end
39
39
 
40
40
  def to_s
41
- return "\n```ruby\n#{@plaintext}#{@plaintext.end_with?("\n") ? '' : "\n"}```\n\n" if code?
42
- ReverseMarkdown.convert unescape_brackets(Kramdown::Document.new(escape_brackets(@plaintext), input: 'GFM').to_html)
41
+ return to_code if code?
42
+ to_markdown
43
43
  end
44
44
 
45
45
  private
46
46
 
47
- # @param text [String]
48
47
  # @return [String]
49
- def escape_brackets text
50
- # text.gsub(/(\[[^\]]*\])([^\(]|\z)/, '!!!^\1^!!!\2')
51
- text.gsub('[', '!!!!b').gsub(']', 'e!!!!')
48
+ def to_code
49
+ "\n```ruby\n#{Documenting.normalize_indentation(@plaintext)}#{@plaintext.end_with?("\n") ? '' : "\n"}```\n\n"
52
50
  end
53
51
 
54
- # @param text [String]
55
52
  # @return [String]
56
- def unescape_brackets text
57
- text.gsub('!!!!b', '[').gsub('e!!!!', ']')
53
+ def to_markdown
54
+ ReverseMarkdown.convert Kramdown::Document.new(@plaintext, input: 'GFM').to_html
58
55
  end
59
56
  end
60
57
 
@@ -65,40 +62,34 @@ module Solargraph
65
62
  # line and at least two spaces of indentation. This is a common
66
63
  # convention in Ruby core documentation, e.g., String#split.
67
64
  sections = [DocSection.new(false)]
68
- normalize_indentation(docstring.to_s).gsub(/\t/, ' ').lines.each do |l|
69
- if l.strip.empty?
70
- sections.last.concat l
71
- else
72
- if (l =~ /^ [^\s]/ && sections.last.plaintext =~ /(\r?\n[ \t]*?){2,}$/) || (l.start_with?(' ') && sections.last.code?)
73
- # Code block
74
- sections.push DocSection.new(true) unless sections.last.code?
75
- sections.last.concat l[2..-1]
76
- else
77
- # Regular documentation
78
- sections.push DocSection.new(false) if sections.last.code?
79
- sections.last.concat l
80
- end
65
+ Documenting.normalize_indentation(Documenting.strip_html_comments(docstring.to_s.gsub("\t", ' '))).lines.each do |l|
66
+ if l.start_with?(' ')
67
+ # Code block
68
+ sections.push DocSection.new(true) unless sections.last.code?
69
+ elsif sections.last.code?
70
+ # Regular documentation
71
+ sections.push DocSection.new(false)
81
72
  end
73
+ sections.last.concat l
82
74
  end
83
75
  sections.map(&:to_s).join.strip
84
76
  end
85
77
  end
86
78
 
87
- private
88
-
89
- # @param text [String]
90
- # @return [String]
91
- def normalize_indentation text
92
- text.lines.map { |l| remove_odd_spaces(l) }.join
79
+ def self.strip_html_comments text
80
+ text.gsub(/<!--([\s\S]*?)-->/, '').strip
93
81
  end
94
82
 
95
- # @param line [String]
83
+ # @param text [String]
96
84
  # @return [String]
97
- def remove_odd_spaces line
98
- return line unless line.start_with?(' ')
99
- spaces = line.match(/^ +/)[0].length
100
- return line unless spaces.odd?
101
- line[1..-1]
85
+ def self.normalize_indentation text
86
+ left = text.lines.map do |line|
87
+ match = line.match(/^ +/)
88
+ next 0 unless match
89
+ match[0].length
90
+ end.min
91
+ return text if left.nil? || left.zero?
92
+ text.lines.map { |line| line[left..] }.join
102
93
  end
103
94
  end
104
95
  end
@@ -3,14 +3,17 @@
3
3
  module Solargraph
4
4
  module Pin
5
5
  class InstanceVariable < BaseVariable
6
+ # @return [ComplexType]
6
7
  def binder
7
8
  closure.binder
8
9
  end
9
10
 
11
+ # @return [::Symbol]
10
12
  def scope
11
13
  closure.binder.scope
12
14
  end
13
15
 
16
+ # @return [ComplexType]
14
17
  def context
15
18
  @context ||= begin
16
19
  result = super
@@ -22,6 +25,7 @@ module Solargraph
22
25
  end
23
26
  end
24
27
 
28
+ # @param other [InstanceVariable]
25
29
  def nearly? other
26
30
  super && binder == other.binder
27
31
  end
@@ -6,12 +6,16 @@ module Solargraph
6
6
  # @return [Range]
7
7
  attr_reader :presence
8
8
 
9
+ # @param assignment [AST::Node, nil]
10
+ # @param presence [Range, nil]
11
+ # @param splat [Hash]
9
12
  def initialize assignment: nil, presence: nil, **splat
10
13
  super(**splat)
11
14
  @assignment = assignment
12
15
  @presence = presence
13
16
  end
14
17
 
18
+ # @param pin [self]
15
19
  def try_merge! pin
16
20
  return false unless super
17
21
  @presence = pin.presence
@@ -21,11 +25,16 @@ module Solargraph
21
25
  # @param other_closure [Pin::Closure]
22
26
  # @param other_loc [Location]
23
27
  def visible_at?(other_closure, other_loc)
24
- return true if location.filename == other_loc.filename &&
28
+ location.filename == other_loc.filename &&
25
29
  presence.include?(other_loc.range.start) &&
26
30
  match_named_closure(other_closure, closure)
27
31
  end
28
32
 
33
+ # @return [String]
34
+ def to_rbs
35
+ (name || '(anon)') + ' ' + (return_type&.to_rbs || 'untyped')
36
+ end
37
+
29
38
  private
30
39
 
31
40
  # @param tag1 [String]
@@ -40,6 +49,9 @@ module Solargraph
40
49
  (['', 'Class<>'].include?(tag1) && ['', 'Class<>'].include?(tag2))
41
50
  end
42
51
 
52
+ # @param needle [Pin::Base]
53
+ # @param haystack [Pin::Base]
54
+ # @return [Boolean]
43
55
  def match_named_closure needle, haystack
44
56
  return true if needle == haystack || haystack.is_a?(Pin::Block)
45
57
  cursor = haystack
@@ -7,7 +7,7 @@ module Solargraph
7
7
  class Method < Closure
8
8
  include Solargraph::Parser::NodeMethods
9
9
 
10
- # @return [Array<Pin::Parameter>]
10
+ # @return [::Array<Pin::Parameter>]
11
11
  attr_reader :parameters
12
12
 
13
13
  # @return [::Symbol] :public, :private, or :protected
@@ -18,21 +18,66 @@ module Solargraph
18
18
 
19
19
  # @param visibility [::Symbol] :public, :protected, or :private
20
20
  # @param explicit [Boolean]
21
- # @param parameters [Array<Pin::Parameter>]
22
- # @param node [Parser::AST::Node, RubyVM::AbstractSyntaxTree::Node]
21
+ # @param parameters [::Array<Pin::Parameter>]
22
+ # @param block [Pin::Signature, nil, ::Symbol]
23
+ # @param node [Parser::AST::Node, RubyVM::AbstractSyntaxTree::Node, nil]
23
24
  # @param attribute [Boolean]
24
- def initialize visibility: :public, explicit: true, parameters: [], node: nil, attribute: false, signatures: nil, anon_splat: false, **splat
25
+ # @param signatures [::Array<Signature>, nil]
26
+ # @param anon_splat [Boolean]
27
+ # @param return_type [ComplexType, nil]
28
+ def initialize visibility: :public, explicit: true, parameters: [], block: :undefined, node: nil, attribute: false, signatures: nil, anon_splat: false, return_type: nil, **splat
25
29
  super(**splat)
26
30
  @visibility = visibility
27
31
  @explicit = explicit
28
32
  @parameters = parameters
33
+ @block = block
29
34
  @node = node
30
35
  @attribute = attribute
31
36
  @signatures = signatures
32
37
  @anon_splat = anon_splat
38
+ @return_type = return_type
33
39
  end
34
40
 
35
- # @return [Array<String>]
41
+ def transform_types(&transform)
42
+ # @todo 'super' alone should work here I think, but doesn't typecheck at level typed
43
+ m = super(&transform)
44
+ m.signatures = m.signatures.map do |sig|
45
+ sig.transform_types(&transform)
46
+ end
47
+ m.parameters = m.parameters.map do |param|
48
+ param.transform_types(&transform)
49
+ end
50
+ m.block = block&.transform_types(&transform)
51
+ m.signature_help = nil
52
+ m.documentation = nil
53
+ m
54
+ end
55
+
56
+ # @param signature [Pin::Signature]
57
+ # @return [Pin::Method]
58
+ def with_single_signature(signature)
59
+ m = proxy signature.return_type
60
+ m.signature_help = nil
61
+ m.documentation = nil
62
+ # @todo populating the single parameters/return_type/block
63
+ # arguments here seems to be needed for some specs to pass,
64
+ # even though we have a signature with the same information.
65
+ # Is this a problem for RBS-populated methods, which don't
66
+ # populate these three?
67
+ m.parameters = signature.parameters
68
+ m.return_type = signature.return_type
69
+ m.block = signature.block
70
+ m.signatures = [signature]
71
+ m
72
+ end
73
+
74
+ # @return [Pin::Signature, nil]
75
+ def block
76
+ return @block unless @block == :undefined
77
+ @block = signatures.first.block
78
+ end
79
+
80
+ # @return [::Array<String>]
36
81
  def parameter_names
37
82
  @parameter_names ||= parameters.map(&:name)
38
83
  end
@@ -46,22 +91,56 @@ module Solargraph
46
91
  end
47
92
 
48
93
  def return_type
49
- @return_type ||= ComplexType.try_parse(*signatures.map(&:return_type).map(&:to_s))
94
+ @return_type ||= ComplexType.new(signatures.map(&:return_type).flat_map(&:items))
50
95
  end
51
96
 
52
- # @return [Array<Signature>]
97
+ # @param parameters [::Array<Parameter>]
98
+ # @param return_type [ComplexType]
99
+ # @return [Signature]
100
+ def generate_signature(parameters, return_type)
101
+ block = nil
102
+ yieldparam_tags = docstring.tags(:yieldparam)
103
+ yieldreturn_tags = docstring.tags(:yieldreturn)
104
+ generics = docstring.tags(:generic).map(&:name)
105
+ needs_block_param_signature =
106
+ parameters.last&.block? || !yieldreturn_tags.empty? || !yieldparam_tags.empty?
107
+ if needs_block_param_signature
108
+ yield_parameters = yieldparam_tags.map do |p|
109
+ name = p.name
110
+ decl = :arg
111
+ if name
112
+ decl = select_decl(name, false)
113
+ name = clean_param(name)
114
+ end
115
+ Pin::Parameter.new(
116
+ location: location,
117
+ closure: self,
118
+ comments: p.text,
119
+ name: name,
120
+ decl: decl,
121
+ presence: location ? location.range : nil,
122
+ return_type: ComplexType.try_parse(*p.types)
123
+ )
124
+ end
125
+ yield_return_type = ComplexType.try_parse(*yieldreturn_tags.flat_map(&:types))
126
+ block = Signature.new(generics, yield_parameters, yield_return_type)
127
+ end
128
+ Signature.new(generics, parameters, return_type, block)
129
+ end
130
+
131
+ # @return [::Array<Signature>]
53
132
  def signatures
54
133
  @signatures ||= begin
55
134
  top_type = generate_complex_type
56
135
  result = []
57
- result.push Signature.new(parameters, top_type) if top_type.defined?
58
- result.concat(overloads.map { |meth| Signature.new(meth.parameters, meth.return_type) })
59
- result.push Signature.new(parameters, top_type) if result.empty?
136
+ result.push generate_signature(parameters, top_type) if top_type.defined?
137
+ result.concat(overloads.map { |meth| generate_signature(meth.parameters, meth.return_type) }) unless overloads.empty?
138
+ result.push generate_signature(parameters, top_type) if result.empty?
60
139
  result
61
140
  end
62
141
  end
63
142
 
64
- # @return [String]
143
+ # @return [String, nil]
65
144
  def detail
66
145
  # This property is not cached in an instance variable because it can
67
146
  # change when pins get proxied.
@@ -77,7 +156,7 @@ module Solargraph
77
156
  detail
78
157
  end
79
158
 
80
- # @return [Array<Hash>]
159
+ # @return [::Array<Hash>]
81
160
  def signature_help
82
161
  @signature_help ||= signatures.map do |sig|
83
162
  {
@@ -87,6 +166,27 @@ module Solargraph
87
166
  end
88
167
  end
89
168
 
169
+ def desc
170
+ # ensure the signatures line up when logged
171
+ if signatures.length > 1
172
+ "\n#{to_rbs}\n"
173
+ else
174
+ to_rbs
175
+ end
176
+ end
177
+
178
+ def to_rbs
179
+ return nil if signatures.empty?
180
+
181
+ rbs = "def #{name}: #{signatures.first.to_rbs}"
182
+ signatures[1..].each do |sig|
183
+ rbs += "\n"
184
+ rbs += (' ' * (4 + name.length))
185
+ rbs += "| #{name}: #{sig.to_rbs}"
186
+ end
187
+ rbs
188
+ end
189
+
90
190
  def path
91
191
  @path ||= "#{namespace}#{(scope == :instance ? '#' : '.')}#{name}"
92
192
  end
@@ -115,6 +215,32 @@ module Solargraph
115
215
  end
116
216
  @documentation += lines.join("\n")
117
217
  end
218
+ yieldparam_tags = docstring.tags(:yieldparam)
219
+ unless yieldparam_tags.nil? or yieldparam_tags.empty?
220
+ @documentation += "\n\n" unless @documentation.empty?
221
+ @documentation += "Block Params:\n"
222
+ lines = []
223
+ yieldparam_tags.each do |p|
224
+ l = "* #{p.name}"
225
+ l += " [#{escape_brackets(p.types.join(', '))}]" unless p.types.nil? or p.types.empty?
226
+ l += " #{p.text}"
227
+ lines.push l
228
+ end
229
+ @documentation += lines.join("\n")
230
+ end
231
+ yieldreturn_tags = docstring.tags(:yieldreturn)
232
+ unless yieldreturn_tags.empty?
233
+ @documentation += "\n\n" unless @documentation.empty?
234
+ @documentation += "Block Returns:\n"
235
+ lines = []
236
+ yieldreturn_tags.each do |r|
237
+ l = "*"
238
+ l += " [#{escape_brackets(r.types.join(', '))}]" unless r.types.nil? or r.types.empty?
239
+ l += " #{r.text}"
240
+ lines.push l
241
+ end
242
+ @documentation += lines.join("\n")
243
+ end
118
244
  return_tags = docstring.tags(:return)
119
245
  unless return_tags.empty?
120
246
  @documentation += "\n\n" unless @documentation.empty?
@@ -130,6 +256,7 @@ module Solargraph
130
256
  end
131
257
  @documentation += "\n\n" unless @documentation.empty?
132
258
  @documentation += "Visibility: #{visibility}"
259
+ concat_example_tags
133
260
  end
134
261
  @documentation.to_s
135
262
  end
@@ -159,10 +286,11 @@ module Solargraph
159
286
  true
160
287
  end
161
288
 
162
- # @return [Array<Pin::Method>]
289
+ # @return [::Array<Pin::Method>]
163
290
  def overloads
164
291
  @overloads ||= docstring.tags(:overload).map do |tag|
165
292
  Pin::Signature.new(
293
+ generics,
166
294
  tag.parameters.map do |src|
167
295
  name, decl = parse_overload_param(src.first)
168
296
  Pin::Parameter.new(
@@ -185,8 +313,24 @@ module Solargraph
185
313
  @anon_splat
186
314
  end
187
315
 
316
+ protected
317
+
318
+ attr_writer :block
319
+
320
+ attr_writer :parameters
321
+
322
+ attr_writer :signatures
323
+
324
+ attr_writer :signature_help
325
+
326
+ attr_writer :documentation
327
+
188
328
  private
189
329
 
330
+ # @param name [String]
331
+ # @param asgn [Boolean]
332
+ #
333
+ # @return [::Symbol]
190
334
  def select_decl name, asgn
191
335
  if name.start_with?('**')
192
336
  :kwrestarg
@@ -205,11 +349,16 @@ module Solargraph
205
349
  end
206
350
  end
207
351
 
352
+ # @param name [String]
353
+ # @return [String]
208
354
  def clean_param name
209
355
  name.gsub(/[*&:]/, '')
210
356
  end
211
357
 
212
358
  # @param tag [YARD::Tags::OverloadTag]
359
+ # @param name [String]
360
+ #
361
+ # @return [ComplexType]
213
362
  def param_type_from_name(tag, name)
214
363
  param = tag.tags(:param).select { |t| t.name == name }.first
215
364
  return ComplexType::UNDEFINED unless param
@@ -218,7 +367,7 @@ module Solargraph
218
367
 
219
368
  # @return [ComplexType]
220
369
  def generate_complex_type
221
- tags = docstring.tags(:return).map(&:types).flatten.reject(&:nil?)
370
+ tags = docstring.tags(:return).map(&:types).flatten.compact
222
371
  return ComplexType::UNDEFINED if tags.empty?
223
372
  ComplexType.try_parse *tags
224
373
  end
@@ -249,7 +398,7 @@ module Solargraph
249
398
 
250
399
  # @param ref [String]
251
400
  # @param api_map [ApiMap]
252
- # @return [ComplexType]
401
+ # @return [ComplexType, nil]
253
402
  def resolve_reference ref, api_map
254
403
  parts = ref.split(/[\.#]/)
255
404
  if parts.first.empty? || parts.one?
@@ -284,7 +433,7 @@ module Solargraph
284
433
  result = []
285
434
  has_nil = false
286
435
  return ComplexType::NIL if method_body_node.nil?
287
- returns_from(method_body_node).each do |n|
436
+ returns_from_method_body(method_body_node).each do |n|
288
437
  if n.nil? || [:NIL, :nil].include?(n.type)
289
438
  has_nil = true
290
439
  next
@@ -304,6 +453,8 @@ module Solargraph
304
453
  ComplexType.try_parse(*result.map(&:tag).uniq)
305
454
  end
306
455
 
456
+ # @param [ApiMap] api_map
457
+ # @return [ComplexType]
307
458
  def infer_from_iv api_map
308
459
  types = []
309
460
  varname = "@#{name.gsub(/=$/, '')}"
@@ -319,8 +470,8 @@ module Solargraph
319
470
 
320
471
  # When YARD parses an overload tag, it includes rest modifiers in the parameters names.
321
472
  #
322
- # @param arg [String]
323
- # @return [Array(String, Symbol)]
473
+ # @param name [String]
474
+ # @return [::Array(String, ::Symbol)]
324
475
  def parse_overload_param(name)
325
476
  if name.start_with?('**')
326
477
  [name[2..-1], :kwrestarg]
@@ -330,6 +481,19 @@ module Solargraph
330
481
  [name, :arg]
331
482
  end
332
483
  end
484
+
485
+ # @return [void]
486
+ def concat_example_tags
487
+ example_tags = docstring.tags(:example)
488
+ return if example_tags.empty?
489
+ @documentation += "\n\nExamples:\n\n```ruby\n"
490
+ @documentation += example_tags.map do |tag|
491
+ (tag.name && !tag.name.empty? ? "# #{tag.name}\n" : '') +
492
+ "#{tag.text}\n"
493
+ end
494
+ .join("\n")
495
+ .concat("```\n")
496
+ end
333
497
  end
334
498
  end
335
499
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'solargraph/yard_tags'
4
+
3
5
  module Solargraph
4
6
  module Pin
5
7
  class Namespace < Closure
@@ -9,12 +11,10 @@ module Solargraph
9
11
  # @return [::Symbol] :class or :module
10
12
  attr_reader :type
11
13
 
12
- attr_reader :parameters
13
-
14
14
  # @param type [::Symbol] :class or :module
15
15
  # @param visibility [::Symbol] :public or :private
16
- # @param gates [Array<String>]
17
- def initialize type: :class, visibility: :public, gates: [''], parameters: [], **splat
16
+ # @param gates [::Array<String>]
17
+ def initialize type: :class, visibility: :public, gates: [''], **splat
18
18
  # super(location, namespace, name, comments)
19
19
  super(**splat)
20
20
  @type = type
@@ -38,7 +38,18 @@ module Solargraph
38
38
  @closure = Pin::Namespace.new(name: closure_name, gates: [parts.join('::')])
39
39
  @context = nil
40
40
  end
41
- @parameters = parameters
41
+ end
42
+
43
+ def to_rbs
44
+ "#{@type.to_s} #{generics_as_rbs}#{return_type.to_rbs}"
45
+ end
46
+
47
+ def desc
48
+ if name.nil?
49
+ '(top-level)'
50
+ else
51
+ to_rbs
52
+ end
42
53
  end
43
54
 
44
55
  def namespace
@@ -66,6 +77,7 @@ module Solargraph
66
77
  (type == :class ? LanguageServer::SymbolKinds::CLASS : LanguageServer::SymbolKinds::MODULE)
67
78
  end
68
79
 
80
+ # @return [String]
69
81
  def path
70
82
  @path ||= (namespace.empty? ? '' : "#{namespace}::") + name
71
83
  end
@@ -74,6 +86,7 @@ module Solargraph
74
86
  @return_type ||= ComplexType.try_parse( (type == :class ? 'Class' : 'Module') + "<#{path}>" )
75
87
  end
76
88
 
89
+ # @return [Array<String>]
77
90
  def domains
78
91
  @domains ||= []
79
92
  end
@@ -9,6 +9,9 @@ module Solargraph
9
9
  # @return [String]
10
10
  attr_reader :asgn_code
11
11
 
12
+ # @param decl [::Symbol] :arg, :optarg, :kwarg, :kwoptarg, :restarg, :kwrestarg, :block, :blockarg
13
+ # @param asgn_code [String, nil]
14
+ # @param return_type [ComplexType, nil]
12
15
  def initialize decl: :arg, asgn_code: nil, return_type: nil, **splat
13
16
  super(**splat)
14
17
  @asgn_code = asgn_code
@@ -36,6 +39,24 @@ module Solargraph
36
39
  [:block, :blockarg].include?(decl)
37
40
  end
38
41
 
42
+ def to_rbs
43
+ case decl
44
+ when :optarg
45
+ "?#{super}"
46
+ when :kwarg
47
+ "#{name}: #{return_type.to_rbs}"
48
+ when :kwoptarg
49
+ "?#{name}: #{return_type.to_rbs}"
50
+ when :restarg
51
+ "*#{super}"
52
+ when :kwrestarg
53
+ "**#{super}"
54
+ else
55
+ super
56
+ end
57
+ end
58
+
59
+ # @return [String]
39
60
  def full
40
61
  case decl
41
62
  when :optarg
@@ -100,7 +121,7 @@ module Solargraph
100
121
 
101
122
  private
102
123
 
103
- # @return [YARD::Tags::Tag]
124
+ # @return [YARD::Tags::Tag, nil]
104
125
  def param_tag
105
126
  found = nil
106
127
  params = closure.docstring.tags(:param)
@@ -119,21 +140,30 @@ module Solargraph
119
140
  # @return [ComplexType]
120
141
  def typify_block_param api_map
121
142
  if closure.is_a?(Pin::Block) && closure.receiver
122
- chain = Parser.chain(closure.receiver, filename)
143
+ chain = Parser.chain(closure.receiver, filename, closure.node)
123
144
  clip = api_map.clip_at(location.filename, location.range.start)
124
145
  locals = clip.locals - [self]
125
146
  meths = chain.define(api_map, closure, locals)
147
+ receiver_type = chain.base.infer(api_map, closure, locals)
126
148
  meths.each do |meth|
127
- if meth.docstring.has_tag?(:yieldparam_single_parameter)
128
- type = chain.base.infer(api_map, closure, locals)
129
- if type.defined? && !type.subtypes.empty?
130
- bmeth = chain.base.define(api_map, closure, locals).first
131
- return type.subtypes.first.qualify(api_map, bmeth.context.namespace)
132
- end
149
+ block_signature = meth.block
150
+ if block_signature
151
+ yield_type = block_signature.parameters[index]&.return_type
133
152
  else
153
+ # @todo move the yieldparam tag parsing logic into the
154
+ # creation of Method pins so we don't need this else
155
+ # statement
134
156
  yps = meth.docstring.tags(:yieldparam)
135
157
  unless yps[index].nil? or yps[index].types.nil? or yps[index].types.empty?
136
- return ComplexType.try_parse(yps[index].types.first).self_to(chain.base.infer(api_map, closure, locals).namespace).qualify(api_map, meth.context.namespace)
158
+ yield_type = ComplexType.try_parse(yps[index].types.first)
159
+ end
160
+ end
161
+ unless yield_type.nil?
162
+ if yield_type.generic? && receiver_type.defined?
163
+ namespace_pin = api_map.get_namespace_pins(meth.namespace, closure.namespace).first
164
+ return yield_type.resolve_generics(namespace_pin, receiver_type)
165
+ else
166
+ return yield_type.self_to(chain.base.infer(api_map, closure, locals).namespace).qualify(api_map, meth.context.namespace)
137
167
  end
138
168
  end
139
169
  end
@@ -144,7 +174,7 @@ module Solargraph
144
174
  # @param api_map [ApiMap]
145
175
  # @return [ComplexType]
146
176
  def typify_method_param api_map
147
- meths = api_map.get_method_stack(closure.full_context.namespace, closure.name, scope: closure.scope)
177
+ meths = api_map.get_method_stack(closure.full_context.tag, closure.name, scope: closure.scope)
148
178
  # meths.shift # Ignore the first one
149
179
  meths.each do |meth|
150
180
  found = nil
@@ -164,8 +194,8 @@ module Solargraph
164
194
 
165
195
  # @param heredoc [YARD::Docstring]
166
196
  # @param api_map [ApiMap]
167
- # @param skip [Array]
168
- # @return [Array<YARD::Tags::Tag>]
197
+ # @param skip [::Array]
198
+ # @return [::Array<YARD::Tags::Tag>]
169
199
  def see_reference heredoc, api_map, skip = []
170
200
  heredoc.ref_tags.each do |ref|
171
201
  next unless ref.tag_name == 'param' && ref.owner
@@ -177,8 +207,8 @@ module Solargraph
177
207
 
178
208
  # @param ref [String]
179
209
  # @param api_map [ApiMap]
180
- # @param skip [Array]
181
- # @return [Array<YARD::Tags::Tag>, nil]
210
+ # @param skip [::Array]
211
+ # @return [::Array<YARD::Tags::Tag>, nil]
182
212
  def resolve_reference ref, api_map, skip
183
213
  return nil if skip.include?(ref)
184
214
  skip.push ref
@@ -4,10 +4,10 @@ module Solargraph
4
4
  module Pin
5
5
  class Reference
6
6
  class Override < Reference
7
- # @return [Array<YARD::Tags::Tag>]
7
+ # @return [::Array<YARD::Tags::Tag>]
8
8
  attr_reader :tags
9
9
 
10
- # @return [Array<Symbol>]
10
+ # @return [::Array<Symbol>]
11
11
  attr_reader :delete
12
12
 
13
13
  def initialize location, name, tags, delete = []