solargraph 0.58.3 → 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 (238) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +12 -5
  4. data/.github/workflows/plugins.yml +54 -34
  5. data/.github/workflows/rspec.yml +18 -28
  6. data/.github/workflows/typecheck.yml +6 -3
  7. data/.rubocop.yml +39 -6
  8. data/.rubocop_todo.yml +53 -966
  9. data/CHANGELOG.md +35 -0
  10. data/Gemfile +6 -1
  11. data/README.md +3 -3
  12. data/Rakefile +26 -23
  13. data/bin/solargraph +2 -1
  14. data/lib/solargraph/api_map/cache.rb +3 -3
  15. data/lib/solargraph/api_map/constants.rb +12 -3
  16. data/lib/solargraph/api_map/index.rb +42 -20
  17. data/lib/solargraph/api_map/source_to_yard.rb +22 -9
  18. data/lib/solargraph/api_map/store.rb +61 -36
  19. data/lib/solargraph/api_map.rb +192 -78
  20. data/lib/solargraph/bench.rb +2 -3
  21. data/lib/solargraph/complex_type/conformance.rb +176 -0
  22. data/lib/solargraph/complex_type/type_methods.rb +31 -18
  23. data/lib/solargraph/complex_type/unique_type.rb +225 -63
  24. data/lib/solargraph/complex_type.rb +177 -59
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -111
  26. data/lib/solargraph/convention/base.rb +50 -50
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +1 -1
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +7 -5
  29. data/lib/solargraph/convention/data_definition.rb +5 -2
  30. data/lib/solargraph/convention/gemfile.rb +1 -1
  31. data/lib/solargraph/convention/gemspec.rb +1 -1
  32. data/lib/solargraph/convention/rakefile.rb +1 -1
  33. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
  34. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -3
  35. data/lib/solargraph/convention/struct_definition.rb +8 -4
  36. data/lib/solargraph/convention.rb +2 -2
  37. data/lib/solargraph/converters/dd.rb +2 -0
  38. data/lib/solargraph/converters/dl.rb +2 -0
  39. data/lib/solargraph/converters/dt.rb +2 -0
  40. data/lib/solargraph/converters/misc.rb +2 -0
  41. data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
  42. data/lib/solargraph/diagnostics/rubocop.rb +11 -10
  43. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  44. data/lib/solargraph/diagnostics/type_check.rb +11 -10
  45. data/lib/solargraph/diagnostics/update_errors.rb +4 -8
  46. data/lib/solargraph/diagnostics.rb +55 -55
  47. data/lib/solargraph/doc_map.rb +39 -39
  48. data/lib/solargraph/environ.rb +52 -52
  49. data/lib/solargraph/equality.rb +4 -4
  50. data/lib/solargraph/gem_pins.rb +4 -15
  51. data/lib/solargraph/language_server/error_codes.rb +10 -10
  52. data/lib/solargraph/language_server/host/diagnoser.rb +1 -1
  53. data/lib/solargraph/language_server/host/dispatch.rb +3 -3
  54. data/lib/solargraph/language_server/host/message_worker.rb +4 -3
  55. data/lib/solargraph/language_server/host/sources.rb +2 -1
  56. data/lib/solargraph/language_server/host.rb +35 -28
  57. data/lib/solargraph/language_server/message/base.rb +1 -1
  58. data/lib/solargraph/language_server/message/client/register_capability.rb +1 -3
  59. data/lib/solargraph/language_server/message/completion_item/resolve.rb +6 -8
  60. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +12 -18
  61. data/lib/solargraph/language_server/message/extended/document.rb +1 -0
  62. data/lib/solargraph/language_server/message/extended/document_gems.rb +7 -7
  63. data/lib/solargraph/language_server/message/extended/download_core.rb +2 -1
  64. data/lib/solargraph/language_server/message/extended/environment.rb +25 -25
  65. data/lib/solargraph/language_server/message/extended/search.rb +1 -1
  66. data/lib/solargraph/language_server/message/initialize.rb +20 -14
  67. data/lib/solargraph/language_server/message/initialized.rb +28 -28
  68. data/lib/solargraph/language_server/message/text_document/completion.rb +10 -8
  69. data/lib/solargraph/language_server/message/text_document/definition.rb +41 -32
  70. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +17 -10
  71. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +29 -19
  72. data/lib/solargraph/language_server/message/text_document/formatting.rb +8 -6
  73. data/lib/solargraph/language_server/message/text_document/hover.rb +5 -5
  74. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +13 -6
  75. data/lib/solargraph/language_server/message/text_document/references.rb +17 -10
  76. data/lib/solargraph/language_server/message/text_document/rename.rb +20 -13
  77. data/lib/solargraph/language_server/message/text_document/signature_help.rb +3 -2
  78. data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -17
  79. data/lib/solargraph/language_server/message/text_document.rb +28 -28
  80. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +34 -28
  81. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +38 -30
  82. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +23 -17
  83. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +27 -17
  84. data/lib/solargraph/language_server/message.rb +1 -1
  85. data/lib/solargraph/language_server/progress.rb +143 -143
  86. data/lib/solargraph/language_server/request.rb +4 -2
  87. data/lib/solargraph/language_server/transport/adapter.rb +68 -68
  88. data/lib/solargraph/language_server/transport/data_reader.rb +11 -13
  89. data/lib/solargraph/language_server/uri_helpers.rb +2 -2
  90. data/lib/solargraph/language_server.rb +20 -20
  91. data/lib/solargraph/library.rb +57 -38
  92. data/lib/solargraph/location.rb +17 -14
  93. data/lib/solargraph/logging.rb +22 -4
  94. data/lib/solargraph/page.rb +1 -1
  95. data/lib/solargraph/parser/comment_ripper.rb +19 -4
  96. data/lib/solargraph/parser/flow_sensitive_typing.rb +324 -108
  97. data/lib/solargraph/parser/node_processor/base.rb +34 -4
  98. data/lib/solargraph/parser/node_processor.rb +8 -7
  99. data/lib/solargraph/parser/parser_gem/class_methods.rb +30 -14
  100. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -1
  101. data/lib/solargraph/parser/parser_gem/node_chainer.rb +51 -25
  102. data/lib/solargraph/parser/parser_gem/node_methods.rb +222 -72
  103. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +24 -24
  104. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
  105. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +13 -11
  106. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
  107. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -12
  108. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +36 -36
  109. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +24 -24
  110. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +10 -3
  111. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +9 -8
  112. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +24 -24
  113. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
  114. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +5 -3
  115. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
  116. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
  117. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +64 -40
  118. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +3 -3
  119. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  120. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
  121. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  122. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -5
  123. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +124 -113
  124. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +20 -20
  125. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +1 -1
  126. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  127. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +6 -2
  128. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  129. data/lib/solargraph/parser/parser_gem.rb +2 -0
  130. data/lib/solargraph/parser/region.rb +9 -3
  131. data/lib/solargraph/parser/snippet.rb +3 -1
  132. data/lib/solargraph/parser.rb +2 -0
  133. data/lib/solargraph/pin/base.rb +156 -84
  134. data/lib/solargraph/pin/base_variable.rb +273 -24
  135. data/lib/solargraph/pin/block.rb +29 -6
  136. data/lib/solargraph/pin/breakable.rb +7 -1
  137. data/lib/solargraph/pin/callable.rb +67 -23
  138. data/lib/solargraph/pin/closure.rb +7 -10
  139. data/lib/solargraph/pin/common.rb +36 -6
  140. data/lib/solargraph/pin/compound_statement.rb +55 -0
  141. data/lib/solargraph/pin/constant.rb +3 -5
  142. data/lib/solargraph/pin/conversions.rb +10 -4
  143. data/lib/solargraph/pin/delegated_method.rb +19 -8
  144. data/lib/solargraph/pin/documenting.rb +4 -2
  145. data/lib/solargraph/pin/instance_variable.rb +5 -1
  146. data/lib/solargraph/pin/keyword.rb +0 -4
  147. data/lib/solargraph/pin/local_variable.rb +15 -59
  148. data/lib/solargraph/pin/method.rb +205 -111
  149. data/lib/solargraph/pin/method_alias.rb +8 -0
  150. data/lib/solargraph/pin/namespace.rb +19 -12
  151. data/lib/solargraph/pin/parameter.rb +102 -36
  152. data/lib/solargraph/pin/proxy_type.rb +4 -1
  153. data/lib/solargraph/pin/reference/override.rb +1 -1
  154. data/lib/solargraph/pin/reference/require.rb +14 -14
  155. data/lib/solargraph/pin/reference/superclass.rb +2 -0
  156. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  157. data/lib/solargraph/pin/reference.rb +20 -0
  158. data/lib/solargraph/pin/search.rb +8 -7
  159. data/lib/solargraph/pin/signature.rb +15 -12
  160. data/lib/solargraph/pin/singleton.rb +11 -11
  161. data/lib/solargraph/pin/symbol.rb +2 -1
  162. data/lib/solargraph/pin/until.rb +2 -4
  163. data/lib/solargraph/pin/while.rb +2 -4
  164. data/lib/solargraph/pin.rb +2 -0
  165. data/lib/solargraph/pin_cache.rb +22 -19
  166. data/lib/solargraph/position.rb +17 -10
  167. data/lib/solargraph/range.rb +16 -15
  168. data/lib/solargraph/rbs_map/conversions.rb +278 -191
  169. data/lib/solargraph/rbs_map/core_fills.rb +18 -11
  170. data/lib/solargraph/rbs_map/core_map.rb +24 -17
  171. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -5
  172. data/lib/solargraph/rbs_map.rb +76 -32
  173. data/lib/solargraph/rbs_translator.rb +206 -0
  174. data/lib/solargraph/server_methods.rb +1 -1
  175. data/lib/solargraph/shell.rb +330 -71
  176. data/lib/solargraph/source/chain/array.rb +3 -12
  177. data/lib/solargraph/source/chain/block_symbol.rb +13 -13
  178. data/lib/solargraph/source/chain/block_variable.rb +13 -13
  179. data/lib/solargraph/source/chain/call.rb +91 -119
  180. data/lib/solargraph/source/chain/class_variable.rb +1 -1
  181. data/lib/solargraph/source/chain/constant.rb +5 -1
  182. data/lib/solargraph/source/chain/global_variable.rb +1 -1
  183. data/lib/solargraph/source/chain/hash.rb +8 -5
  184. data/lib/solargraph/source/chain/head.rb +19 -19
  185. data/lib/solargraph/source/chain/if.rb +12 -10
  186. data/lib/solargraph/source/chain/instance_variable.rb +24 -1
  187. data/lib/solargraph/source/chain/link.rb +12 -22
  188. data/lib/solargraph/source/chain/literal.rb +22 -15
  189. data/lib/solargraph/source/chain/or.rb +10 -4
  190. data/lib/solargraph/source/chain/q_call.rb +2 -0
  191. data/lib/solargraph/source/chain/variable.rb +3 -1
  192. data/lib/solargraph/source/chain/z_super.rb +1 -3
  193. data/lib/solargraph/source/chain.rb +51 -38
  194. data/lib/solargraph/source/change.rb +12 -5
  195. data/lib/solargraph/source/cursor.rb +33 -18
  196. data/lib/solargraph/source/encoding_fixes.rb +6 -7
  197. data/lib/solargraph/source/source_chainer.rb +56 -32
  198. data/lib/solargraph/source/updater.rb +5 -1
  199. data/lib/solargraph/source.rb +59 -35
  200. data/lib/solargraph/source_map/clip.rb +54 -30
  201. data/lib/solargraph/source_map/data.rb +4 -1
  202. data/lib/solargraph/source_map/mapper.rb +28 -131
  203. data/lib/solargraph/source_map.rb +35 -9
  204. data/lib/solargraph/type_checker/problem.rb +3 -1
  205. data/lib/solargraph/type_checker/rules.rb +81 -8
  206. data/lib/solargraph/type_checker.rb +196 -122
  207. data/lib/solargraph/version.rb +19 -1
  208. data/lib/solargraph/workspace/config.rb +14 -11
  209. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  210. data/lib/solargraph/workspace/require_paths.rb +1 -0
  211. data/lib/solargraph/workspace.rb +50 -28
  212. data/lib/solargraph/yard_map/cache.rb +25 -25
  213. data/lib/solargraph/yard_map/directives/attribute_directive.rb +65 -0
  214. data/lib/solargraph/yard_map/directives/domain_directive.rb +30 -0
  215. data/lib/solargraph/yard_map/directives/method_directive.rb +51 -0
  216. data/lib/solargraph/yard_map/directives/override_directive.rb +30 -0
  217. data/lib/solargraph/yard_map/directives/parse_directive.rb +53 -0
  218. data/lib/solargraph/yard_map/directives/visibility_directive.rb +70 -0
  219. data/lib/solargraph/yard_map/directives.rb +35 -0
  220. data/lib/solargraph/yard_map/helpers.rb +8 -3
  221. data/lib/solargraph/yard_map/macro.rb +113 -0
  222. data/lib/solargraph/yard_map/mapper/to_constant.rb +28 -28
  223. data/lib/solargraph/yard_map/mapper/to_method.rb +13 -7
  224. data/lib/solargraph/yard_map/mapper/to_namespace.rb +2 -1
  225. data/lib/solargraph/yard_map/mapper.rb +31 -8
  226. data/lib/solargraph/yard_map.rb +19 -18
  227. data/lib/solargraph/yard_tags.rb +2 -2
  228. data/lib/solargraph/yardoc.rb +7 -4
  229. data/lib/solargraph.rb +34 -10
  230. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  231. data/rbs/shims/ast/0/node.rbs +1 -1
  232. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  233. data/solargraph.gemspec +38 -35
  234. metadata +64 -42
  235. data/lib/solargraph/type_checker/checks.rb +0 -124
  236. data/lib/solargraph/type_checker/param_def.rb +0 -37
  237. data/lib/solargraph/yard_map/to_method.rb +0 -89
  238. data/rbs/fills/tuple/tuple.rbs +0 -149
@@ -22,8 +22,10 @@ module Solargraph
22
22
  # @param attribute [Boolean]
23
23
  # @param signatures [::Array<Signature>, nil]
24
24
  # @param anon_splat [Boolean]
25
+ # @param context [ComplexType, ComplexType::UniqueType, nil]
26
+ # @param [Hash{Symbol => Object}] splat
25
27
  def initialize visibility: :public, explicit: true, block: :undefined, node: nil, attribute: false, signatures: nil, anon_splat: false,
26
- **splat
28
+ context: nil, **splat
27
29
  super(**splat)
28
30
  @visibility = visibility
29
31
  @explicit = explicit
@@ -32,31 +34,12 @@ module Solargraph
32
34
  @attribute = attribute
33
35
  @signatures = signatures
34
36
  @anon_splat = anon_splat
35
- end
36
-
37
- # @param signature_pins [Array<Pin::Signature>]
38
- # @return [Array<Pin::Signature>]
39
- def combine_all_signature_pins(*signature_pins)
40
- # @type [Hash{Array => Array<Pin::Signature>}]
41
- by_arity = {}
42
- signature_pins.each do |signature_pin|
43
- by_arity[signature_pin.arity] ||= []
44
- by_arity[signature_pin.arity] << signature_pin
45
- end
46
- by_arity.transform_values! do |same_arity_pins|
47
- # @param memo [Pin::Signature, nil]
48
- # @param signature [Pin::Signature]
49
- same_arity_pins.reduce(nil) do |memo, signature|
50
- next signature if memo.nil?
51
- memo.combine_with(signature)
52
- end
53
- end
54
- by_arity.values.flatten
37
+ @context = context if context
55
38
  end
56
39
 
57
40
  # @param other [Pin::Method]
58
41
  # @return [::Symbol]
59
- def combine_visibility(other)
42
+ def combine_visibility other
60
43
  if dodgy_visibility_source? && !other.dodgy_visibility_source?
61
44
  other.visibility
62
45
  elsif other.dodgy_visibility_source? && !dodgy_visibility_source?
@@ -66,33 +49,18 @@ module Solargraph
66
49
  end
67
50
  end
68
51
 
69
- # @param other [Pin::Method]
70
- # @return [Array<Pin::Signature>]
71
- def combine_signatures(other)
72
- all_undefined = signatures.all? { |sig| sig.return_type.undefined? }
73
- other_all_undefined = other.signatures.all? { |sig| sig.return_type.undefined? }
74
- if all_undefined && !other_all_undefined
75
- other.signatures
76
- elsif other_all_undefined && !all_undefined
77
- signatures
78
- else
79
- combine_all_signature_pins(*signatures, *other.signatures)
80
- end
81
- end
82
-
83
- def combine_with(other, attrs = {})
52
+ def combine_with other, attrs = {}
84
53
  priority_choice = choose_priority(other)
85
54
  return priority_choice unless priority_choice.nil?
86
55
 
87
56
  sigs = combine_signatures(other)
88
- parameters = if sigs.length > 0
89
- [].freeze
90
- else
91
- choose(other, :parameters).clone.freeze
92
- end
57
+ parameters = if sigs.length.positive?
58
+ [].freeze
59
+ else
60
+ choose(other, :parameters).clone.freeze
61
+ end
93
62
  new_attrs = {
94
63
  visibility: combine_visibility(other),
95
- # @sg-ignore https://github.com/castwide/solargraph/pull/1050
96
64
  explicit: explicit? || other.explicit?,
97
65
  block: combine_blocks(other),
98
66
  node: choose_node(other, :node),
@@ -110,7 +78,7 @@ module Solargraph
110
78
  super && other.node == node
111
79
  end
112
80
 
113
- def transform_types(&transform)
81
+ def transform_types &transform
114
82
  # @todo 'super' alone should work here I think, but doesn't typecheck at level typed
115
83
  m = super(&transform)
116
84
  m.signatures = m.signatures.map do |sig|
@@ -125,14 +93,12 @@ module Solargraph
125
93
  def reset_generated!
126
94
  super
127
95
  unless signatures.empty?
128
- return_type = nil
129
96
  @block = :undefined
130
- parameters = []
97
+ []
131
98
  end
132
99
  block&.reset_generated!
133
100
  @signatures&.each(&:reset_generated!)
134
- signature_help = nil
135
- documentation = nil
101
+ nil
136
102
  end
137
103
 
138
104
  def all_rooted?
@@ -141,7 +107,7 @@ module Solargraph
141
107
 
142
108
  # @param signature [Pin::Signature]
143
109
  # @return [Pin::Method]
144
- def with_single_signature(signature)
110
+ def with_single_signature signature
145
111
  m = proxy signature.return_type
146
112
  m.reset_generated!
147
113
  # @todo populating the single parameters/return_type/block
@@ -160,6 +126,8 @@ module Solargraph
160
126
  !block.nil?
161
127
  end
162
128
 
129
+ # @sg-ignore flow sensitive typing needs to remove literal with
130
+ # this unless block
163
131
  # @return [Pin::Signature, nil]
164
132
  def block
165
133
  return @block unless @block == :undefined
@@ -175,13 +143,14 @@ module Solargraph
175
143
  end
176
144
 
177
145
  def return_type
178
- @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))
179
147
  end
180
148
 
181
149
  # @param parameters [::Array<Parameter>]
182
- # @param return_type [ComplexType]
150
+ # @param return_type [ComplexType, nil]
183
151
  # @return [Signature]
184
- def generate_signature(parameters, return_type)
152
+ def generate_signature parameters, return_type
153
+ # @type [Pin::Signature, nil]
185
154
  block = nil
186
155
  yieldparam_tags = docstring.tags(:yieldparam)
187
156
  yieldreturn_tags = docstring.tags(:yieldreturn)
@@ -202,7 +171,7 @@ module Solargraph
202
171
  comments: p.text,
203
172
  name: name,
204
173
  decl: decl,
205
- presence: location ? location.range : nil,
174
+ presence: location&.range,
206
175
  return_type: ComplexType.try_parse(*p.types),
207
176
  source: source
208
177
  )
@@ -219,14 +188,11 @@ module Solargraph
219
188
 
220
189
  # @return [::Array<Signature>]
221
190
  def signatures
222
- @signatures ||= begin
223
- top_type = generate_complex_type
224
- result = []
225
- result.push generate_signature(parameters, top_type) if top_type.defined?
226
- result.concat(overloads.map { |meth| generate_signature(meth.parameters, meth.return_type) }) unless overloads.empty?
227
- result.push generate_signature(parameters, @return_type || ComplexType::UNDEFINED) if result.empty?
228
- result
229
- end
191
+ @signatures ||= if inline_rbs.empty?
192
+ signatures_from_yard
193
+ else
194
+ signatures_from_inline_rbs
195
+ end
230
196
  end
231
197
 
232
198
  # @param return_type [ComplexType]
@@ -243,11 +209,18 @@ module Solargraph
243
209
  # change when pins get proxied.
244
210
  detail = String.new
245
211
  detail += if signatures.length > 1
246
- "(*) "
247
- else
248
- "(#{signatures.first.parameters.map(&:full).join(', ')}) " unless signatures.first.parameters.empty?
249
- end.to_s
250
- detail += "=#{probed? ? '~' : (proxied? ? '^' : '>')} #{return_type.to_s}" unless return_type.undefined?
212
+ '(*) '
213
+ else
214
+ "(#{signatures.first.parameters.map(&:full).join(', ')}) " unless signatures.first.parameters.empty?
215
+ end.to_s
216
+ # @sg-ignore Need to add nil check here
217
+ unless return_type.undefined?
218
+ detail += "=#{if probed?
219
+ '~'
220
+ else
221
+ (proxied? ? '^' : '>')
222
+ end} #{return_type}"
223
+ end
251
224
  detail.strip!
252
225
  return nil if detail.empty?
253
226
  detail
@@ -257,7 +230,7 @@ module Solargraph
257
230
  def signature_help
258
231
  @signature_help ||= signatures.map do |sig|
259
232
  {
260
- label: name + '(' + sig.parameters.map(&:full).join(', ') + ')',
233
+ label: "#{name}(#{sig.parameters.map(&:full).join(', ')})",
261
234
  documentation: documentation
262
235
  }
263
236
  end
@@ -276,6 +249,7 @@ module Solargraph
276
249
  return nil if signatures.empty?
277
250
 
278
251
  rbs = "def #{name}: #{signatures.first.to_rbs}"
252
+ # @sg-ignore Need to add nil check here
279
253
  signatures[1..].each do |sig|
280
254
  rbs += "\n"
281
255
  rbs += (' ' * (4 + name.length))
@@ -285,7 +259,7 @@ module Solargraph
285
259
  end
286
260
 
287
261
  def path
288
- @path ||= "#{namespace}#{(scope == :instance ? '#' : '.')}#{name}"
262
+ @path ||= "#{namespace}#{scope == :instance ? '#' : '.'}#{name}"
289
263
  end
290
264
 
291
265
  # @return [String]
@@ -294,15 +268,33 @@ module Solargraph
294
268
  end
295
269
 
296
270
  def typify api_map
297
- logger.debug { "Method#typify(self=#{self}, binder=#{binder}, closure=#{closure}, context=#{context.rooted_tags}, return_type=#{return_type.rooted_tags}) - starting" }
298
- decl = super
271
+ logger.debug do
272
+ # @sg-ignore Need to add nil check here
273
+ "Method#typify(self=#{self}, binder=#{binder}, closure=#{closure}, context=#{context.rooted_tags}, return_type=#{return_type.rooted_tags}) - starting"
274
+ end
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
299
288
  unless decl.undefined?
300
- logger.debug { "Method#typify(self=#{self}, binder=#{binder}, closure=#{closure}, context=#{context}) => #{decl.rooted_tags.inspect} - decl found" }
289
+ logger.debug do
290
+ "Method#typify(self=#{self}, binder=#{binder}, closure=#{closure}, context=#{context}) => #{decl.rooted_tags.inspect} - decl found"
291
+ end
301
292
  return decl
302
293
  end
303
294
  type = see_reference(api_map) || typify_from_super(api_map)
304
295
  logger.debug { "Method#typify(self=#{self}) - type=#{type&.rooted_tags.inspect}" }
305
296
  unless type.nil?
297
+ # @sg-ignore Need to add nil check here
306
298
  qualified = type.qualify(api_map, *closure.gates)
307
299
  logger.debug { "Method#typify(self=#{self}) => #{qualified.rooted_tags.inspect}" }
308
300
  return qualified
@@ -314,26 +306,26 @@ module Solargraph
314
306
  if @documentation.nil?
315
307
  method_docs ||= super || ''
316
308
  param_tags = docstring.tags(:param)
317
- unless param_tags.nil? or param_tags.empty?
309
+ unless param_tags.nil? || param_tags.empty?
318
310
  method_docs += "\n\n" unless method_docs.empty?
319
311
  method_docs += "Params:\n"
320
312
  lines = []
321
313
  param_tags.each do |p|
322
314
  l = "* #{p.name}"
323
- l += " [#{escape_brackets(p.types.join(', '))}]" unless p.types.nil? or p.types.empty?
315
+ l += " [#{escape_brackets(p.types.join(', '))}]" unless p.types.nil? || p.types.empty?
324
316
  l += " #{p.text}"
325
317
  lines.push l
326
318
  end
327
319
  method_docs += lines.join("\n")
328
320
  end
329
321
  yieldparam_tags = docstring.tags(:yieldparam)
330
- unless yieldparam_tags.nil? or yieldparam_tags.empty?
322
+ unless yieldparam_tags.nil? || yieldparam_tags.empty?
331
323
  method_docs += "\n\n" unless method_docs.empty?
332
324
  method_docs += "Block Params:\n"
333
325
  lines = []
334
326
  yieldparam_tags.each do |p|
335
327
  l = "* #{p.name}"
336
- l += " [#{escape_brackets(p.types.join(', '))}]" unless p.types.nil? or p.types.empty?
328
+ l += " [#{escape_brackets(p.types.join(', '))}]" unless p.types.nil? || p.types.empty?
337
329
  l += " #{p.text}"
338
330
  lines.push l
339
331
  end
@@ -345,8 +337,8 @@ module Solargraph
345
337
  method_docs += "Block Returns:\n"
346
338
  lines = []
347
339
  yieldreturn_tags.each do |r|
348
- l = "*"
349
- l += " [#{escape_brackets(r.types.join(', '))}]" unless r.types.nil? or r.types.empty?
340
+ l = '*'
341
+ l += " [#{escape_brackets(r.types.join(', '))}]" unless r.types.nil? || r.types.empty?
350
342
  l += " #{r.text}"
351
343
  lines.push l
352
344
  end
@@ -358,8 +350,8 @@ module Solargraph
358
350
  method_docs += "Returns:\n"
359
351
  lines = []
360
352
  return_tags.each do |r|
361
- l = "*"
362
- l += " [#{escape_brackets(r.types.join(', '))}]" unless r.types.nil? or r.types.empty?
353
+ l = '*'
354
+ l += " [#{escape_brackets(r.types.join(', '))}]" unless r.types.nil? || r.types.empty?
363
355
  l += " #{r.text}"
364
356
  lines.push l
365
357
  end
@@ -396,7 +388,7 @@ module Solargraph
396
388
  attribute? ? infer_from_iv(api_map) : infer_from_return_nodes(api_map)
397
389
  end
398
390
 
399
- # @return [::Array<Pin::Method>]
391
+ # @return [::Array<Pin::Signature>]
400
392
  def overloads
401
393
  # Ignore overload tags with nil parameters. If it's not an array, the
402
394
  # tag's source is likely malformed.
@@ -414,14 +406,14 @@ module Solargraph
414
406
  comments: tag.docstring.all.to_s,
415
407
  name: name,
416
408
  decl: decl,
417
- presence: location ? location.range : nil,
409
+ presence: location&.range,
418
410
  return_type: param_type_from_name(tag, src.first),
419
411
  source: :overloads
420
412
  )
421
413
  end,
422
414
  closure: self,
423
415
  return_type: ComplexType.try_parse(*tag.docstring.tags(:return).flat_map(&:types)),
424
- source: :overloads,
416
+ source: :overloads
425
417
  )
426
418
  end
427
419
  @overloads
@@ -440,13 +432,13 @@ module Solargraph
440
432
  return self unless docstring.ref_tags.any?
441
433
  docstring.ref_tags.each do |tag|
442
434
  ref = if tag.owner.to_s.start_with?(/[#.]/)
443
- api_map.get_methods(namespace)
444
- .select { |pin| pin.path.end_with?(tag.owner.to_s) }
445
- .first
446
- else
447
- # @todo Resolve relative namespaces
448
- api_map.get_path_pins(tag.owner.to_s).first
449
- end
435
+ api_map.get_methods(namespace)
436
+ .select { |pin| pin.path.end_with?(tag.owner.to_s) }
437
+ .first
438
+ else
439
+ # @todo Resolve relative namespaces
440
+ api_map.get_path_pins(tag.owner.to_s).first
441
+ end
450
442
  next unless ref
451
443
 
452
444
  docstring.add_tag(*ref.docstring.tags(:param))
@@ -462,29 +454,95 @@ module Solargraph
462
454
 
463
455
  protected
464
456
 
465
- attr_writer :block
466
-
467
- attr_writer :signature_help
468
-
469
- attr_writer :documentation
457
+ attr_writer :block, :signature_help, :documentation, :return_type
470
458
 
471
459
  def dodgy_visibility_source?
472
460
  # as of 2025-03-12, the RBS generator used for
473
461
  # e.g. activesupport did not understand 'private' markings
474
462
  # inside 'class << self' blocks, but YARD did OK at it
475
- source == :rbs && scope == :class && type_location&.filename&.include?('generated') && return_type.undefined? ||
463
+ # @sg-ignore Need to add nil check here
464
+ (source == :rbs && scope == :class && type_location&.filename&.include?('generated') && return_type.undefined?) ||
476
465
  # YARD's RBS generator seems to miss a lot of should-be protected instance methods
477
- source == :rbs && scope == :instance && namespace.start_with?('YARD::') ||
466
+ (source == :rbs && scope == :instance && namespace.start_with?('YARD::')) ||
478
467
  # private on attr_readers seems to be broken in Prism's auto-generator script
479
- source == :rbs && scope == :instance && namespace.start_with?('Prism::') ||
468
+ (source == :rbs && scope == :instance && namespace.start_with?('Prism::')) ||
480
469
  # The RBS for the RBS gem itself seems to use private as a
481
470
  # 'is this a public API' concept, more aggressively than the
482
471
  # actual code. Let's respect that and ignore the actual .rb file.
483
- source == :yardoc && scope == :instance && namespace.start_with?('RBS::')
472
+ (source == :yardoc && scope == :instance && namespace.start_with?('RBS::'))
484
473
  end
485
474
 
486
475
  private
487
476
 
477
+ # @param other [Pin::Method]
478
+ # @return [Array<Pin::Signature>]
479
+ def combine_signatures other
480
+ all_undefined = signatures.all? { |sig| !sig.return_type&.defined? }
481
+ other_all_undefined = other.signatures.all? { |sig| !sig.return_type&.defined? }
482
+ if all_undefined && !other_all_undefined
483
+ other.signatures
484
+ elsif other_all_undefined && !all_undefined
485
+ signatures
486
+ else
487
+ combine_signatures_by_type_arity(*signatures, *other.signatures)
488
+ end
489
+ end
490
+
491
+ # @param signature_pins [Array<Pin::Signature>]
492
+ #
493
+ # @return [Array<Pin::Signature>]
494
+ def combine_signatures_by_type_arity(*signature_pins)
495
+ # @type [Hash{Array => Array<Pin::Signature>}]
496
+ by_type_arity = {}
497
+ signature_pins.each do |signature_pin|
498
+ by_type_arity[signature_pin.type_arity] ||= []
499
+ by_type_arity[signature_pin.type_arity] << signature_pin
500
+ end
501
+
502
+ by_type_arity.transform_values! do |same_type_arity_signatures|
503
+ combine_same_type_arity_signatures same_type_arity_signatures
504
+ end
505
+ by_type_arity.values.flatten
506
+ end
507
+
508
+ # @param same_type_arity_signatures [Array<Pin::Signature>]
509
+ #
510
+ # @return [Array<Pin::Signature>]
511
+ def combine_same_type_arity_signatures same_type_arity_signatures
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.
514
+ return same_type_arity_signatures
515
+
516
+ # rubocop:disable Lint/UnreachableCode
517
+ # This is an O(n^2) operation, so bail out if n is not small
518
+ return same_type_arity_signatures if same_type_arity_signatures.length > 10
519
+
520
+ # @param old_signatures [Array<Pin::Signature>]
521
+ # @param new_signature [Pin::Signature]
522
+ same_type_arity_signatures.reduce([]) do |old_signatures, new_signature|
523
+ next old_signatures + [new_signature] if old_signatures.empty?
524
+ old_signatures.flat_map do |old_signature|
525
+ potential_new_signature = old_signature.combine_with(new_signature)
526
+
527
+ if potential_new_signature.type_arity == old_signature.type_arity
528
+ # the number of types in each parameter and return type
529
+ # match, so we found compatible signatures to merge. If
530
+ # we increased the number of types, we'd potentially
531
+ # have taken away the ability to use parameter types to
532
+ # choose the correct return type (while Ruby doesn't
533
+ # dispatch based on type, RBS does distinguish overloads
534
+ # based on types, not just arity, allowing for type
535
+ # information describing how methods behave based on
536
+ # their input types)
537
+ old_signatures - [old_signature] + [potential_new_signature]
538
+ else
539
+ old_signatures + [new_signature]
540
+ end
541
+ end
542
+ end
543
+ # rubocop:enable Lint/UnreachableCode
544
+ end
545
+
488
546
  # @param name [String]
489
547
  # @param asgn [Boolean]
490
548
  #
@@ -517,7 +575,7 @@ module Solargraph
517
575
  # @param name [String]
518
576
  #
519
577
  # @return [ComplexType]
520
- def param_type_from_name(tag, name)
578
+ def param_type_from_name tag, name
521
579
  # @param t [YARD::Tags::Tag]
522
580
  param = tag.tags(:param).select { |t| t.name == name }.first
523
581
  return ComplexType::UNDEFINED unless param
@@ -528,23 +586,24 @@ module Solargraph
528
586
  def generate_complex_type
529
587
  tags = docstring.tags(:return).map(&:types).flatten.compact
530
588
  return ComplexType::UNDEFINED if tags.empty?
531
- ComplexType.try_parse *tags
589
+ ComplexType.try_parse(*tags)
532
590
  end
533
591
 
534
592
  # @param api_map [ApiMap]
535
- # @return [ComplexType, nil]
593
+ # @return [ComplexType, ComplexType::UniqueType, nil]
536
594
  def see_reference api_map
537
595
  # This should actually be an intersection type
538
- # @param ref [YARD::Tags::Tag, Solargraph::Yard::Tags::RefTag]
596
+ # @param ref [YARD::Tags::Tag, YARD::Tags::RefTag]
539
597
  docstring.ref_tags.each do |ref|
540
598
  # @sg-ignore ref should actually be an intersection type
541
599
  next unless ref.tag_name == 'return' && ref.owner
542
- # @sg-ignore ref should actually be an intersection type
600
+ # @sg-ignore should actually be an intersection type
543
601
  result = resolve_reference(ref.owner.to_s, api_map)
544
602
  return result unless result.nil?
545
603
  end
546
604
  match = comments.match(/^[ \t]*\(see (.*)\)/m)
547
605
  return nil if match.nil?
606
+ # @sg-ignore Need to add nil check here
548
607
  resolve_reference match[1], api_map
549
608
  end
550
609
 
@@ -559,6 +618,7 @@ module Solargraph
559
618
  stack = rest_of_stack api_map
560
619
  return nil if stack.empty?
561
620
  stack.each do |pin|
621
+ # @sg-ignore Need to add nil check here
562
622
  return pin.return_type unless pin.return_type.undefined?
563
623
  end
564
624
  nil
@@ -566,7 +626,7 @@ module Solargraph
566
626
 
567
627
  # @param ref [String]
568
628
  # @param api_map [ApiMap]
569
- # @return [ComplexType, nil]
629
+ # @return [ComplexType, ComplexType::UniqueType, nil]
570
630
  def resolve_reference ref, api_map
571
631
  parts = ref.split(/[.#]/)
572
632
  if parts.first.empty? || parts.one?
@@ -574,6 +634,7 @@ module Solargraph
574
634
  else
575
635
  fqns = api_map.qualify(parts.first, *gates)
576
636
  return ComplexType::UNDEFINED if fqns.nil?
637
+ # @sg-ignore Need to add nil check here
577
638
  path = fqns + ref[parts.first.length] + parts.last
578
639
  end
579
640
  pins = api_map.get_path_pins(path)
@@ -589,7 +650,7 @@ module Solargraph
589
650
  return nil if node.nil?
590
651
  return node.children[1].children.last if node.type == :DEFN
591
652
  return node.children[2].children.last if node.type == :DEFS
592
- return node.children[2] if node.type == :def || node.type == :DEFS
653
+ return node.children[2] if %i[def DEFS].include?(node.type)
593
654
  return node.children[3] if node.type == :defs
594
655
  nil
595
656
  end
@@ -602,16 +663,18 @@ module Solargraph
602
663
  has_nil = false
603
664
  return ComplexType::NIL if method_body_node.nil?
604
665
  returns_from_method_body(method_body_node).each do |n|
605
- if n.nil? || [:NIL, :nil].include?(n.type)
666
+ if n.nil? || %i[NIL nil].include?(n.type)
606
667
  has_nil = true
607
668
  next
608
669
  end
609
670
  rng = Range.from_node(n)
610
671
  next unless rng
611
672
  clip = api_map.clip_at(
673
+ # @sg-ignore Need to add nil check here
612
674
  location.filename,
613
675
  rng.ending
614
676
  )
677
+ # @sg-ignore Need to add nil check here
615
678
  chain = Solargraph::Parser.chain(n, location.filename)
616
679
  type = chain.infer(api_map, self, clip.locals)
617
680
  result.push type unless type.undefined?
@@ -640,12 +703,12 @@ module Solargraph
640
703
  #
641
704
  # @param name [String]
642
705
  # @return [::Array(String, ::Symbol)]
643
- def parse_overload_param(name)
706
+ def parse_overload_param name
644
707
  # @todo this needs to handle mandatory vs not args, kwargs, blocks, etc
645
708
  if name.start_with?('**')
646
- [name[2..-1], :kwrestarg]
709
+ [name[2..], :kwrestarg]
647
710
  elsif name.start_with?('*')
648
- [name[1..-1], :restarg]
711
+ [name[1..], :restarg]
649
712
  else
650
713
  [name, :arg]
651
714
  end
@@ -664,9 +727,40 @@ module Solargraph
664
727
  .concat("```\n")
665
728
  end
666
729
 
667
- protected
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
668
738
 
669
- attr_writer :return_type
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
670
764
  end
671
765
  end
672
766
  end
@@ -26,6 +26,14 @@ module Solargraph
26
26
  :public
27
27
  end
28
28
 
29
+ def to_rbs
30
+ if scope == :class
31
+ "alias self.#{name} self.#{original}"
32
+ else
33
+ "alias #{name} #{original}"
34
+ end
35
+ end
36
+
29
37
  def path
30
38
  @path ||= namespace + (scope == :instance ? '#' : '.') + name
31
39
  end