solargraph 0.58.0 → 0.59.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 (219) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.gitattributes +2 -0
  4. data/.github/workflows/linting.yml +6 -5
  5. data/.github/workflows/plugins.yml +48 -35
  6. data/.github/workflows/rspec.yml +15 -28
  7. data/.github/workflows/typecheck.yml +3 -2
  8. data/.gitignore +1 -0
  9. data/.rubocop.yml +38 -6
  10. data/.rubocop_todo.yml +53 -966
  11. data/CHANGELOG.md +24 -0
  12. data/Gemfile +3 -1
  13. data/README.md +3 -3
  14. data/Rakefile +26 -23
  15. data/bin/solargraph +9 -8
  16. data/lib/solargraph/api_map/cache.rb +110 -110
  17. data/lib/solargraph/api_map/constants.rb +288 -279
  18. data/lib/solargraph/api_map/index.rb +204 -193
  19. data/lib/solargraph/api_map/source_to_yard.rb +110 -97
  20. data/lib/solargraph/api_map/store.rb +395 -384
  21. data/lib/solargraph/api_map.rb +1029 -945
  22. data/lib/solargraph/bench.rb +44 -45
  23. data/lib/solargraph/complex_type/conformance.rb +176 -0
  24. data/lib/solargraph/complex_type/type_methods.rb +240 -228
  25. data/lib/solargraph/complex_type/unique_type.rb +641 -482
  26. data/lib/solargraph/complex_type.rb +557 -444
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
  29. data/lib/solargraph/convention/data_definition.rb +108 -105
  30. data/lib/solargraph/convention/gemfile.rb +15 -15
  31. data/lib/solargraph/convention/gemspec.rb +23 -23
  32. data/lib/solargraph/convention/rakefile.rb +17 -17
  33. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
  34. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
  35. data/lib/solargraph/convention/struct_definition.rb +168 -164
  36. data/lib/solargraph/convention.rb +78 -78
  37. data/lib/solargraph/converters/dd.rb +19 -17
  38. data/lib/solargraph/converters/dl.rb +17 -15
  39. data/lib/solargraph/converters/dt.rb +17 -15
  40. data/lib/solargraph/converters/misc.rb +3 -1
  41. data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
  42. data/lib/solargraph/diagnostics/rubocop.rb +119 -118
  43. data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
  44. data/lib/solargraph/diagnostics/type_check.rb +56 -55
  45. data/lib/solargraph/diagnostics/update_errors.rb +37 -41
  46. data/lib/solargraph/doc_map.rb +438 -439
  47. data/lib/solargraph/equality.rb +34 -34
  48. data/lib/solargraph/gem_pins.rb +98 -98
  49. data/lib/solargraph/language_server/error_codes.rb +20 -20
  50. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  51. data/lib/solargraph/language_server/host/dispatch.rb +130 -130
  52. data/lib/solargraph/language_server/host/message_worker.rb +113 -112
  53. data/lib/solargraph/language_server/host/sources.rb +100 -99
  54. data/lib/solargraph/language_server/host.rb +886 -878
  55. data/lib/solargraph/language_server/message/base.rb +97 -97
  56. data/lib/solargraph/language_server/message/client/register_capability.rb +13 -15
  57. data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -60
  58. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +108 -114
  59. data/lib/solargraph/language_server/message/extended/document.rb +24 -23
  60. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
  61. data/lib/solargraph/language_server/message/extended/download_core.rb +20 -19
  62. data/lib/solargraph/language_server/message/extended/search.rb +20 -20
  63. data/lib/solargraph/language_server/message/initialize.rb +197 -191
  64. data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
  65. data/lib/solargraph/language_server/message/text_document/definition.rb +49 -40
  66. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +23 -16
  67. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +36 -26
  68. data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
  69. data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
  70. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +18 -11
  71. data/lib/solargraph/language_server/message/text_document/references.rb +23 -16
  72. data/lib/solargraph/language_server/message/text_document/rename.rb +26 -19
  73. data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
  74. data/lib/solargraph/language_server/message/text_document/type_definition.rb +33 -25
  75. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +41 -35
  76. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +48 -40
  77. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +32 -26
  78. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +33 -23
  79. data/lib/solargraph/language_server/message.rb +94 -94
  80. data/lib/solargraph/language_server/request.rb +29 -27
  81. data/lib/solargraph/language_server/transport/data_reader.rb +72 -74
  82. data/lib/solargraph/language_server/uri_helpers.rb +49 -49
  83. data/lib/solargraph/library.rb +702 -683
  84. data/lib/solargraph/location.rb +85 -82
  85. data/lib/solargraph/logging.rb +55 -37
  86. data/lib/solargraph/page.rb +92 -92
  87. data/lib/solargraph/parser/comment_ripper.rb +84 -69
  88. data/lib/solargraph/parser/flow_sensitive_typing.rb +471 -255
  89. data/lib/solargraph/parser/node_processor/base.rb +122 -92
  90. data/lib/solargraph/parser/node_processor.rb +63 -62
  91. data/lib/solargraph/parser/parser_gem/class_methods.rb +165 -149
  92. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
  93. data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
  94. data/lib/solargraph/parser/parser_gem/node_methods.rb +507 -486
  95. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
  96. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
  97. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
  98. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +45 -46
  99. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
  100. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +38 -37
  101. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
  102. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +42 -40
  103. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
  104. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
  105. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
  106. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  107. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  108. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
  109. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +51 -52
  110. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +302 -291
  111. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
  112. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  113. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
  114. data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
  115. data/lib/solargraph/parser/parser_gem.rb +14 -12
  116. data/lib/solargraph/parser/region.rb +75 -69
  117. data/lib/solargraph/parser/snippet.rb +19 -17
  118. data/lib/solargraph/parser.rb +25 -23
  119. data/lib/solargraph/pin/base.rb +773 -729
  120. data/lib/solargraph/pin/base_variable.rb +375 -126
  121. data/lib/solargraph/pin/block.rb +127 -104
  122. data/lib/solargraph/pin/breakable.rb +15 -9
  123. data/lib/solargraph/pin/callable.rb +275 -231
  124. data/lib/solargraph/pin/closure.rb +69 -72
  125. data/lib/solargraph/pin/common.rb +97 -79
  126. data/lib/solargraph/pin/compound_statement.rb +55 -0
  127. data/lib/solargraph/pin/constant.rb +43 -45
  128. data/lib/solargraph/pin/conversions.rb +129 -123
  129. data/lib/solargraph/pin/delegated_method.rb +131 -120
  130. data/lib/solargraph/pin/documenting.rb +116 -114
  131. data/lib/solargraph/pin/instance_variable.rb +38 -34
  132. data/lib/solargraph/pin/keyword.rb +16 -20
  133. data/lib/solargraph/pin/local_variable.rb +31 -75
  134. data/lib/solargraph/pin/method.rb +724 -672
  135. data/lib/solargraph/pin/method_alias.rb +42 -34
  136. data/lib/solargraph/pin/namespace.rb +122 -115
  137. data/lib/solargraph/pin/parameter.rb +339 -275
  138. data/lib/solargraph/pin/proxy_type.rb +42 -39
  139. data/lib/solargraph/pin/reference/override.rb +47 -47
  140. data/lib/solargraph/pin/reference/superclass.rb +17 -15
  141. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  142. data/lib/solargraph/pin/reference.rb +59 -39
  143. data/lib/solargraph/pin/search.rb +62 -61
  144. data/lib/solargraph/pin/signature.rb +64 -61
  145. data/lib/solargraph/pin/symbol.rb +54 -53
  146. data/lib/solargraph/pin/until.rb +16 -18
  147. data/lib/solargraph/pin/while.rb +16 -18
  148. data/lib/solargraph/pin.rb +46 -44
  149. data/lib/solargraph/pin_cache.rb +248 -245
  150. data/lib/solargraph/position.rb +139 -119
  151. data/lib/solargraph/range.rb +113 -112
  152. data/lib/solargraph/rbs_map/conversions.rb +952 -823
  153. data/lib/solargraph/rbs_map/core_fills.rb +91 -84
  154. data/lib/solargraph/rbs_map/core_map.rb +65 -58
  155. data/lib/solargraph/rbs_map/stdlib_map.rb +71 -43
  156. data/lib/solargraph/rbs_map.rb +207 -163
  157. data/lib/solargraph/server_methods.rb +16 -16
  158. data/lib/solargraph/shell.rb +555 -352
  159. data/lib/solargraph/source/chain/array.rb +39 -37
  160. data/lib/solargraph/source/chain/call.rb +377 -337
  161. data/lib/solargraph/source/chain/class_variable.rb +13 -13
  162. data/lib/solargraph/source/chain/constant.rb +30 -26
  163. data/lib/solargraph/source/chain/global_variable.rb +13 -13
  164. data/lib/solargraph/source/chain/hash.rb +37 -34
  165. data/lib/solargraph/source/chain/if.rb +30 -28
  166. data/lib/solargraph/source/chain/instance_variable.rb +36 -13
  167. data/lib/solargraph/source/chain/link.rb +99 -109
  168. data/lib/solargraph/source/chain/literal.rb +51 -48
  169. data/lib/solargraph/source/chain/or.rb +29 -23
  170. data/lib/solargraph/source/chain/q_call.rb +13 -11
  171. data/lib/solargraph/source/chain/variable.rb +15 -13
  172. data/lib/solargraph/source/chain/z_super.rb +28 -30
  173. data/lib/solargraph/source/chain.rb +304 -291
  174. data/lib/solargraph/source/change.rb +89 -82
  175. data/lib/solargraph/source/cursor.rb +172 -166
  176. data/lib/solargraph/source/encoding_fixes.rb +22 -23
  177. data/lib/solargraph/source/source_chainer.rb +218 -194
  178. data/lib/solargraph/source/updater.rb +59 -55
  179. data/lib/solargraph/source.rb +522 -498
  180. data/lib/solargraph/source_map/clip.rb +245 -226
  181. data/lib/solargraph/source_map/data.rb +37 -34
  182. data/lib/solargraph/source_map/mapper.rb +286 -259
  183. data/lib/solargraph/source_map.rb +224 -212
  184. data/lib/solargraph/type_checker/problem.rb +34 -32
  185. data/lib/solargraph/type_checker/rules.rb +157 -84
  186. data/lib/solargraph/type_checker.rb +888 -814
  187. data/lib/solargraph/version.rb +5 -5
  188. data/lib/solargraph/workspace/config.rb +258 -255
  189. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  190. data/lib/solargraph/workspace/require_paths.rb +98 -97
  191. data/lib/solargraph/workspace.rb +242 -220
  192. data/lib/solargraph/yard_map/helpers.rb +49 -44
  193. data/lib/solargraph/yard_map/mapper/to_method.rb +136 -130
  194. data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
  195. data/lib/solargraph/yard_map/mapper.rb +84 -79
  196. data/lib/solargraph/yard_map.rb +17 -18
  197. data/lib/solargraph/yard_tags.rb +20 -20
  198. data/lib/solargraph/yardoc.rb +90 -87
  199. data/lib/solargraph.rb +128 -105
  200. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  201. data/rbs/fills/tuple/tuple.rbs +28 -0
  202. data/rbs/shims/ast/0/node.rbs +5 -0
  203. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  204. data/rbs_collection.yaml +1 -1
  205. data/solargraph.gemspec +37 -35
  206. metadata +52 -51
  207. data/lib/solargraph/type_checker/checks.rb +0 -124
  208. data/lib/solargraph/type_checker/param_def.rb +0 -37
  209. data/lib/solargraph/yard_map/to_method.rb +0 -89
  210. data/sig/shims/ast/0/node.rbs +0 -5
  211. /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
  212. /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
  213. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  214. /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
  215. /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
  216. /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
  217. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  218. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  219. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,337 +1,377 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class Source
5
- class Chain
6
- #
7
- # Handles both method calls and local variable references by
8
- # first looking for a variable with the name 'word', then
9
- # proceeding to method signature resolution if not found.
10
- #
11
- class Call < Chain::Link
12
- include Solargraph::Parser::NodeMethods
13
-
14
- # @return [String]
15
- attr_reader :word
16
-
17
- # @return [Location]
18
- attr_reader :location
19
-
20
- # @return [::Array<Chain>]
21
- attr_reader :arguments
22
-
23
- # @return [Chain, nil]
24
- attr_reader :block
25
-
26
- # @param word [String]
27
- # @param location [Location, nil]
28
- # @param arguments [::Array<Chain>]
29
- # @param block [Chain, nil]
30
- def initialize word, location = nil, arguments = [], block = nil
31
- @word = word
32
- @location = location
33
- @arguments = arguments
34
- @block = block
35
- fix_block_pass
36
- end
37
-
38
- # @sg-ignore Fix "Not enough arguments to Module#protected"
39
- protected def equality_fields
40
- super + [arguments, block]
41
- end
42
-
43
- def with_block?
44
- !!@block
45
- end
46
-
47
- # @param api_map [ApiMap]
48
- # @param name_pin [Pin::Closure] name_pin.binder should give us the type of the object on which 'word' will be invoked
49
- # @param locals [::Array<Pin::LocalVariable>]
50
- def resolve api_map, name_pin, locals
51
- return super_pins(api_map, name_pin) if word == 'super'
52
- return yield_pins(api_map, name_pin) if word == 'yield'
53
- found = if head?
54
- api_map.visible_pins(locals, word, name_pin, location)
55
- else
56
- []
57
- end
58
- return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
59
- pins = name_pin.binder.each_unique_type.flat_map do |context|
60
- ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
61
- stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
62
- [stack.first].compact
63
- end
64
- return [] if pins.empty?
65
- inferred_pins(pins, api_map, name_pin, locals)
66
- end
67
-
68
- private
69
-
70
- # @param pins [::Enumerable<Pin::Method>]
71
- # @param api_map [ApiMap]
72
- # @param name_pin [Pin::Base]
73
- # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
74
- # @return [::Array<Pin::Base>]
75
- def inferred_pins pins, api_map, name_pin, locals
76
- result = pins.map do |p|
77
- next p unless p.is_a?(Pin::Method)
78
- overloads = p.signatures
79
- # next p if overloads.empty?
80
- type = ComplexType::UNDEFINED
81
- # start with overloads that require blocks; if we are
82
- # passing a block, we want to find a signature that will
83
- # use it. If we didn't pass a block, the logic below will
84
- # reject it regardless
85
-
86
- with_block, without_block = overloads.partition(&:block?)
87
- sorted_overloads = with_block + without_block
88
- # @type [Pin::Signature, nil]
89
- new_signature_pin = nil
90
- sorted_overloads.each do |ol|
91
- next unless ol.arity_matches?(arguments, with_block?)
92
- match = true
93
-
94
- atypes = []
95
- arguments.each_with_index do |arg, idx|
96
- param = ol.parameters[idx]
97
- if param.nil?
98
- match = ol.parameters.any?(&:restarg?)
99
- break
100
- end
101
- arg_name_pin = Pin::ProxyType.anonymous(name_pin.context,
102
- gates: name_pin.gates,
103
- source: :chain)
104
- atype = atypes[idx] ||= arg.infer(api_map, arg_name_pin, locals)
105
- unless param.compatible_arg?(atype, api_map) || param.restarg?
106
- match = false
107
- break
108
- end
109
- end
110
- if match
111
- if ol.block && with_block?
112
- block_atypes = ol.block.parameters.map(&:return_type)
113
- if block.links.map(&:class) == [BlockSymbol]
114
- # like the bar in foo(&:bar)
115
- blocktype = block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
116
- else
117
- blocktype = block_call_type(api_map, name_pin, locals)
118
- end
119
- end
120
- # @type new_signature_pin [Pin::Signature]
121
- new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
122
- new_return_type = new_signature_pin.return_type
123
- if head?
124
- # If we're at the head of the chain, we called a
125
- # method somewhere that marked itself as returning
126
- # self. Given we didn't invoke this on an object,
127
- # this must be a method in this same class - so we
128
- # use our own self type
129
- self_type = name_pin.context
130
- else
131
- # if we're past the head in the chain, whatever the
132
- # type of the lhs side is what 'self' will be in its
133
- # declaration - we can't just use the type of the
134
- # method pin, as this might be a subclass of the
135
- # place where the method is defined
136
- self_type = name_pin.binder
137
- end
138
- # This same logic applies to the YARD work done by
139
- # 'with_params()'.
140
- #
141
- # qualify(), however, happens in the namespace where
142
- # the docs were written - from the method pin.
143
- type = with_params(new_return_type.self_to_type(self_type), self_type).qualify(api_map, *p.gates) if new_return_type.defined?
144
- type ||= ComplexType::UNDEFINED
145
- end
146
- break if type.defined?
147
- end
148
- p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
149
- next p.proxy(type) if type.defined?
150
- if !p.macros.empty?
151
- result = process_macro(p, api_map, name_pin.context, locals)
152
- next result unless result.return_type.undefined?
153
- elsif !p.directives.empty?
154
- result = process_directive(p, api_map, name_pin.context, locals)
155
- next result unless result.return_type.undefined?
156
- end
157
- p
158
- end
159
- logger.debug { "Call#inferred_pins(name_pin.binder=#{name_pin.binder}, word=#{word}, pins=#{pins.map(&:desc)}, name_pin=#{name_pin}) - result=#{result}" }
160
- out = result.map do |pin|
161
- if pin.path == 'Class#new' && name_pin.binder.tag != 'Class'
162
- reduced_context = name_pin.binder.reduce_class_type
163
- pin.proxy(reduced_context)
164
- else
165
- next pin if pin.return_type.undefined?
166
- selfy = pin.return_type.self_to_type(name_pin.binder)
167
- selfy == pin.return_type ? pin : pin.proxy(selfy)
168
- end
169
- end
170
- end
171
-
172
- # @param pin [Pin::Base]
173
- # @param api_map [ApiMap]
174
- # @param context [ComplexType]
175
- # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
176
- # @return [Pin::Base]
177
- def process_macro pin, api_map, context, locals
178
- pin.macros.each do |macro|
179
- # @todo 'Wrong argument type for
180
- # Solargraph::Source::Chain::Call#inner_process_macro:
181
- # macro expected YARD::Tags::MacroDirective, received
182
- # generic<Elem>' is because we lose 'rooted' information
183
- # in the 'Chain::Array' class internally, leaving
184
- # ::Array#each shadowed when it shouldn't be.
185
- result = inner_process_macro(pin, macro, api_map, context, locals)
186
- return result unless result.return_type.undefined?
187
- end
188
- Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
189
- end
190
-
191
- # @param pin [Pin::Method]
192
- # @param api_map [ApiMap]
193
- # @param context [ComplexType]
194
- # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
195
- # @return [Pin::ProxyType]
196
- def process_directive pin, api_map, context, locals
197
- pin.directives.each do |dir|
198
- macro = api_map.named_macro(dir.tag.name)
199
- next if macro.nil?
200
- result = inner_process_macro(pin, macro, api_map, context, locals)
201
- return result unless result.return_type.undefined?
202
- end
203
- Pin::ProxyType.anonymous ComplexType::UNDEFINED, source: :chain
204
- end
205
-
206
- # @param pin [Pin::Base]
207
- # @param macro [YARD::Tags::MacroDirective]
208
- # @param api_map [ApiMap]
209
- # @param context [ComplexType]
210
- # @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
211
- # @return [Pin::ProxyType]
212
- def inner_process_macro pin, macro, api_map, context, locals
213
- vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals), source: :chain) }
214
- txt = macro.tag.text.clone
215
- if txt.empty? && macro.tag.name
216
- named = api_map.named_macro(macro.tag.name)
217
- txt = named.tag.text.clone if named
218
- end
219
- i = 1
220
- vals.each do |v|
221
- txt.gsub!(/\$#{i}/, v.context.namespace)
222
- i += 1
223
- end
224
- docstring = Solargraph::Source.parse_docstring(txt).to_docstring
225
- tag = docstring.tag(:return)
226
- unless tag.nil? || tag.types.nil?
227
- return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types), source: :chain)
228
- end
229
- Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
230
- end
231
-
232
- # @param docstring [YARD::Docstring]
233
- # @param context [ComplexType]
234
- # @return [ComplexType, nil]
235
- def extra_return_type docstring, context
236
- if docstring.has_tag?('return_single_parameter') #&& context.subtypes.one?
237
- return context.subtypes.first || ComplexType::UNDEFINED
238
- elsif docstring.has_tag?('return_value_parameter') && context.value_types.one?
239
- return context.value_types.first
240
- end
241
- nil
242
- end
243
-
244
- # @param name_pin [Pin::Base]
245
- # @return [Pin::Method, nil]
246
- def find_method_pin(name_pin)
247
- method_pin = name_pin
248
- until method_pin.is_a?(Pin::Method)
249
- method_pin = method_pin.closure
250
- return if method_pin.nil?
251
- end
252
- method_pin
253
- end
254
-
255
- # @param api_map [ApiMap]
256
- # @param name_pin [Pin::Base]
257
- # @return [::Array<Pin::Base>]
258
- def super_pins api_map, name_pin
259
- method_pin = find_method_pin(name_pin)
260
- return [] if method_pin.nil?
261
- pins = api_map.get_method_stack(method_pin.namespace, method_pin.name, scope: method_pin.context.scope)
262
- pins.reject{|p| p.path == name_pin.path}
263
- end
264
-
265
- # @param api_map [ApiMap]
266
- # @param name_pin [Pin::Base]
267
- # @return [::Array<Pin::Base>]
268
- def yield_pins api_map, name_pin
269
- method_pin = find_method_pin(name_pin)
270
- return [] unless method_pin
271
-
272
- # @param signature_pin [Pin::Signature]
273
- method_pin.signatures.map(&:block).compact.map do |signature_pin|
274
- return_type = signature_pin.return_type.qualify(api_map, *name_pin.gates)
275
- signature_pin.proxy(return_type)
276
- end
277
- end
278
-
279
- # @param type [ComplexType]
280
- # @param context [ComplexType]
281
- # @return [ComplexType]
282
- def with_params type, context
283
- return type unless type.to_s.include?('$')
284
- ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:rooted_tag).join(', ')).gsub('<>', ''))
285
- end
286
-
287
- # @return [void]
288
- def fix_block_pass
289
- argument = @arguments.last&.links&.first
290
- @block = @arguments.pop if argument.is_a?(BlockSymbol) || argument.is_a?(BlockVariable)
291
- end
292
-
293
- # @param api_map [ApiMap]
294
- # @param context [ComplexType]
295
- # @param block_parameter_types [::Array<ComplexType>]
296
- # @param locals [::Array<Pin::LocalVariable>]
297
- # @return [ComplexType, nil]
298
- def block_symbol_call_type(api_map, context, block_parameter_types, locals)
299
- # Ruby's shorthand for sending the passed in method name
300
- # to the first yield parameter with no arguments
301
- block_symbol_name = block.links.first.word
302
- block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
303
- callee = api_map.get_path_pins(block_symbol_call_path).first
304
- return_type = callee&.return_type
305
- # @todo: Figure out why we get unresolved generics at
306
- # this point and need to assume method return types
307
- # based on the generic type
308
- return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
309
- return_type || ComplexType::UNDEFINED
310
- end
311
-
312
- # @param api_map [ApiMap]
313
- # @return [Pin::Block, nil]
314
- def find_block_pin(api_map)
315
- node_location = Solargraph::Location.from_node(block.node)
316
- return if node_location.nil?
317
- block_pins = api_map.get_block_pins
318
- block_pins.find { |pin| pin.location.contain?(node_location) }
319
- end
320
-
321
- # @param api_map [ApiMap]
322
- # @param name_pin [Pin::Base]
323
- # @param block_parameter_types [::Array<ComplexType>]
324
- # @param locals [::Array<Pin::LocalVariable>]
325
- # @return [ComplexType, nil]
326
- def block_call_type(api_map, name_pin, locals)
327
- return nil unless with_block?
328
-
329
- block_context_pin = name_pin
330
- block_pin = find_block_pin(api_map)
331
- block_context_pin = block_pin.closure if block_pin
332
- block.infer(api_map, block_context_pin, locals)
333
- end
334
- end
335
- end
336
- end
337
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ class Chain
6
+ #
7
+ # Handles both method calls and local variable references by
8
+ # first looking for a variable with the name 'word', then
9
+ # proceeding to method signature resolution if not found.
10
+ #
11
+ class Call < Chain::Link
12
+ include Solargraph::Parser::NodeMethods
13
+
14
+ # @return [String]
15
+ attr_reader :word
16
+
17
+ # @return [Location]
18
+ attr_reader :location
19
+
20
+ # @return [::Array<Chain>]
21
+ attr_reader :arguments
22
+
23
+ # @return [Chain, nil]
24
+ attr_reader :block
25
+
26
+ # @param word [String]
27
+ # @param location [Location, nil]
28
+ # @param arguments [::Array<Chain>]
29
+ # @param block [Chain, nil]
30
+ def initialize word, location = nil, arguments = [], block = nil
31
+ super(word)
32
+
33
+ @location = location
34
+ @arguments = arguments
35
+ @block = block
36
+ fix_block_pass
37
+ end
38
+
39
+ def with_block?
40
+ !!@block
41
+ end
42
+
43
+ # @param api_map [ApiMap]
44
+ # @param name_pin [Pin::Closure] name_pin.binder should give us the type of the object on which 'word' will be invoked
45
+ # @param locals [::Array<Pin::LocalVariable>]
46
+ def resolve api_map, name_pin, locals
47
+ return super_pins(api_map, name_pin) if word == 'super'
48
+ return yield_pins(api_map, name_pin) if word == 'yield'
49
+ found = api_map.var_at_location(locals, word, name_pin, location) if head?
50
+
51
+ return inferred_pins([found], api_map, name_pin, locals) unless found.nil?
52
+ binder = name_pin.binder
53
+ # this is a q_call - i.e., foo&.bar - assume result of call
54
+ # will be nil or result as if binder were not nil -
55
+ # chain.rb#maybe_nil will add the nil type later, we just
56
+ # need to worry about the not-nil case
57
+
58
+ # @sg-ignore Need to handle duck-typed method calls on union types
59
+ binder = binder.without_nil if nullable?
60
+ # @sg-ignore Need to handle duck-typed method calls on union types
61
+ pin_groups = binder.each_unique_type.map do |context|
62
+ ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
63
+ stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
64
+ [stack.first].compact
65
+ end
66
+ pin_groups = [] if !api_map.loose_unions && pin_groups.any?(&:empty?)
67
+ pins = pin_groups.flatten.uniq(&:path)
68
+ return [] if pins.empty?
69
+ inferred_pins(pins, api_map, name_pin, locals)
70
+ end
71
+
72
+ private
73
+
74
+ # @param pins [::Enumerable<Pin::Base>]
75
+ # @param api_map [ApiMap]
76
+ # @param name_pin [Pin::Base]
77
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
78
+ # @return [::Array<Pin::Base>]
79
+ def inferred_pins pins, api_map, name_pin, locals
80
+ result = pins.map do |p|
81
+ next p unless p.is_a?(Pin::Method)
82
+ overloads = p.signatures
83
+ # next p if overloads.empty?
84
+ type = ComplexType::UNDEFINED
85
+ # start with overloads that require blocks; if we are
86
+ # passing a block, we want to find a signature that will
87
+ # use it. If we didn't pass a block, the logic below will
88
+ # reject it regardless
89
+
90
+ with_block, without_block = overloads.partition(&:block?)
91
+ # @sg-ignore flow sensitive typing should handle is_a? and next
92
+ # @type Array<Pin::Signature>
93
+ sorted_overloads = with_block + without_block
94
+ # @type [Pin::Signature, nil]
95
+ new_signature_pin = nil
96
+ # @sg-ignore flow sensitive typing should handle is_a? and next
97
+ # @param ol [Pin::Signature]
98
+ sorted_overloads.each do |ol|
99
+ next unless ol.arity_matches?(arguments, with_block?)
100
+ match = true
101
+
102
+ atypes = []
103
+ arguments.each_with_index do |arg, idx|
104
+ param = ol.parameters[idx]
105
+ if param.nil?
106
+ match = ol.parameters.any?(&:restarg?)
107
+ break
108
+ end
109
+ arg_name_pin = Pin::ProxyType.anonymous(name_pin.context,
110
+ closure: name_pin.closure,
111
+ gates: name_pin.gates,
112
+ source: :chain)
113
+ atype = atypes[idx] ||= arg.infer(api_map, arg_name_pin, locals)
114
+ unless param.compatible_arg?(atype, api_map) || param.restarg?
115
+ match = false
116
+ break
117
+ end
118
+ end
119
+ if match
120
+ if ol.block && with_block?
121
+ block_atypes = ol.block.parameters.map(&:return_type)
122
+ # @todo Need to add nil check here
123
+ blocktype = if block.links.map(&:class) == [BlockSymbol]
124
+ # like the bar in foo(&:bar)
125
+ block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
126
+ else
127
+ block_call_type(api_map, name_pin, locals)
128
+ end
129
+ end
130
+ # @type new_signature_pin [Pin::Signature]
131
+ new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil,
132
+ blocktype)
133
+ new_return_type = new_signature_pin.return_type
134
+ self_type = if head?
135
+ # If we're at the head of the chain, we called a
136
+ # method somewhere that marked itself as returning
137
+ # self. Given we didn't invoke this on an object,
138
+ # this must be a method in this same class - so we
139
+ # use our own self type
140
+ name_pin.context
141
+ else
142
+ # if we're past the head in the chain, whatever the
143
+ # type of the lhs side is what 'self' will be in its
144
+ # declaration - we can't just use the type of the
145
+ # method pin, as this might be a subclass of the
146
+ # place where the method is defined
147
+ name_pin.binder
148
+ end
149
+ # This same logic applies to the YARD work done by
150
+ # 'with_params()'.
151
+ #
152
+ # qualify(), however, happens in the namespace where
153
+ # the docs were written - from the method pin.
154
+ # @todo Need to add nil check here
155
+ if new_return_type.defined?
156
+ type = with_params(new_return_type.self_to_type(self_type), self_type).qualify(api_map,
157
+ *p.gates)
158
+ end
159
+ type ||= ComplexType::UNDEFINED
160
+ end
161
+ break if type.defined?
162
+ end
163
+ p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
164
+ next p.proxy(type) if type.defined?
165
+ if !p.macros.empty?
166
+ result = process_macro(p, api_map, name_pin.context, locals)
167
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
168
+ next result unless result.return_type.undefined?
169
+ elsif !p.directives.empty?
170
+ result = process_directive(p, api_map, name_pin.context, locals)
171
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
172
+ next result unless result.return_type.undefined?
173
+ end
174
+ p
175
+ end
176
+ logger.debug do
177
+ "Call#inferred_pins(name_pin.binder=#{name_pin.binder}, word=#{word}, pins=#{pins.map(&:desc)}, name_pin=#{name_pin}) - result=#{result}"
178
+ end
179
+ result.map do |pin|
180
+ if pin.path == 'Class#new' && name_pin.binder.tag != 'Class'
181
+ reduced_context = name_pin.binder.reduce_class_type
182
+ pin.proxy(reduced_context)
183
+ else
184
+ # @sg-ignore Need to add nil check here
185
+ next pin if pin.return_type.undefined?
186
+ # @sg-ignore Need to add nil check here
187
+ selfy = pin.return_type.self_to_type(name_pin.binder)
188
+ # @sg-ignore Need to add nil check here
189
+ selfy == pin.return_type ? pin : pin.proxy(selfy)
190
+ end
191
+ end
192
+ end
193
+
194
+ # @param pin [Pin::Base]
195
+ # @param api_map [ApiMap]
196
+ # @param context [ComplexType, ComplexType::UniqueType]
197
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
198
+ # @return [Pin::Base]
199
+ def process_macro pin, api_map, context, locals
200
+ pin.macros.each do |macro|
201
+ # @todo 'Wrong argument type for
202
+ # Solargraph::Source::Chain::Call#inner_process_macro:
203
+ # macro expected YARD::Tags::MacroDirective, received
204
+ # generic<Elem>' is because we lose 'rooted' information
205
+ # in the 'Chain::Array' class internally, leaving
206
+ # ::Array#each shadowed when it shouldn't be.
207
+ result = inner_process_macro(pin, macro, api_map, context, locals)
208
+ return result unless result.return_type.undefined?
209
+ end
210
+ Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
211
+ end
212
+
213
+ # @param pin [Pin::Method]
214
+ # @param api_map [ApiMap]
215
+ # @param context [ComplexType, ComplexType::UniqueType]
216
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
217
+ # @return [Pin::ProxyType]
218
+ def process_directive pin, api_map, context, locals
219
+ pin.directives.each do |dir|
220
+ macro = api_map.named_macro(dir.tag.name)
221
+ next if macro.nil?
222
+ result = inner_process_macro(pin, macro, api_map, context, locals)
223
+ return result unless result.return_type.undefined?
224
+ end
225
+ Pin::ProxyType.anonymous ComplexType::UNDEFINED, source: :chain
226
+ end
227
+
228
+ # @param pin [Pin::Base]
229
+ # @param macro [YARD::Tags::MacroDirective]
230
+ # @param api_map [ApiMap]
231
+ # @param context [ComplexType, ComplexType::UniqueType]
232
+ # @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
233
+ # @return [Pin::ProxyType]
234
+ def inner_process_macro pin, macro, api_map, context, locals
235
+ vals = arguments.map { |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals), source: :chain) }
236
+ txt = macro.tag.text.clone
237
+ # @sg-ignore Need to add nil check here
238
+ if txt.empty? && macro.tag.name
239
+ named = api_map.named_macro(macro.tag.name)
240
+ txt = named.tag.text.clone if named
241
+ end
242
+ i = 1
243
+ vals.each do |v|
244
+ # @sg-ignore Need to add nil check here
245
+ txt.gsub!(/\$#{i}/, v.context.namespace)
246
+ i += 1
247
+ end
248
+ # @sg-ignore Need to add nil check here
249
+ docstring = Solargraph::Source.parse_docstring(txt).to_docstring
250
+ tag = docstring.tag(:return)
251
+ unless tag.nil? || tag.types.nil?
252
+ return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types), source: :chain)
253
+ end
254
+ Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
255
+ end
256
+
257
+ # @param docstring [YARD::Docstring]
258
+ # @param context [ComplexType]
259
+ # @return [ComplexType, nil]
260
+ def extra_return_type docstring, context
261
+ if docstring.has_tag?('return_single_parameter') # && context.subtypes.one?
262
+ return context.subtypes.first || ComplexType::UNDEFINED
263
+ elsif docstring.has_tag?('return_value_parameter') && context.value_types.one?
264
+ return context.value_types.first
265
+ end
266
+ nil
267
+ end
268
+
269
+ # @param name_pin [Pin::Base]
270
+ # @return [Pin::Method, nil]
271
+ def find_method_pin name_pin
272
+ method_pin = name_pin
273
+ until method_pin.is_a?(Pin::Method)
274
+ # @sg-ignore Need to support this in flow sensitive typing
275
+ method_pin = method_pin.closure
276
+ return if method_pin.nil?
277
+ end
278
+ method_pin
279
+ end
280
+
281
+ # @param api_map [ApiMap]
282
+ # @param name_pin [Pin::Base]
283
+ # @return [::Array<Pin::Base>]
284
+ def super_pins api_map, name_pin
285
+ method_pin = find_method_pin(name_pin)
286
+ return [] if method_pin.nil?
287
+ pins = api_map.get_method_stack(method_pin.namespace, method_pin.name, scope: method_pin.context.scope)
288
+ pins.reject { |p| p.path == name_pin.path }
289
+ end
290
+
291
+ # @param api_map [ApiMap]
292
+ # @param name_pin [Pin::Base]
293
+ # @return [::Array<Pin::Base>]
294
+ def yield_pins api_map, name_pin
295
+ method_pin = find_method_pin(name_pin)
296
+ return [] unless method_pin
297
+
298
+ # @param signature_pin [Pin::Signature]
299
+ method_pin.signatures.map(&:block).compact.map do |signature_pin|
300
+ # @sg-ignore Need to add nil check here
301
+ return_type = signature_pin.return_type.qualify(api_map, *name_pin.gates)
302
+ signature_pin.proxy(return_type)
303
+ end
304
+ end
305
+
306
+ # @param type [ComplexType]
307
+ # @param context [ComplexType, ComplexType::UniqueType]
308
+ # @return [ComplexType]
309
+ def with_params type, context
310
+ return type unless type.to_s.include?('$')
311
+ ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:rooted_tag).join(', ')).gsub('<>', ''))
312
+ end
313
+
314
+ # @return [void]
315
+ def fix_block_pass
316
+ argument = @arguments.last&.links&.first
317
+ @block = @arguments.pop if argument.is_a?(BlockSymbol) || argument.is_a?(BlockVariable)
318
+ end
319
+
320
+ # @param api_map [ApiMap]
321
+ # @param context [ComplexType, ComplexType::UniqueType]
322
+ # @param block_parameter_types [::Array<ComplexType>]
323
+ # @param locals [::Array<Pin::LocalVariable>]
324
+ # @return [ComplexType, nil]
325
+ def block_symbol_call_type api_map, context, block_parameter_types, locals
326
+ # Ruby's shorthand for sending the passed in method name
327
+ # to the first yield parameter with no arguments
328
+ # @sg-ignore Need to add nil check here
329
+ block_symbol_name = block.links.first.word
330
+ block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
331
+ callee = api_map.get_path_pins(block_symbol_call_path).first
332
+ return_type = callee&.return_type
333
+ # @todo: Figure out why we get unresolved generics at
334
+ # this point and need to assume method return types
335
+ # based on the generic type
336
+ # @sg-ignore Need to add nil check here
337
+ return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
338
+ return_type || ComplexType::UNDEFINED
339
+ end
340
+
341
+ # @param api_map [ApiMap]
342
+ # @return [Pin::Block, nil]
343
+ def find_block_pin api_map
344
+ # @sg-ignore Need to add nil check here
345
+ node_location = Solargraph::Location.from_node(block.node)
346
+ return if node_location.nil?
347
+ block_pins = api_map.get_block_pins
348
+ # @sg-ignore Need to add nil check here
349
+ block_pins.find { |pin| pin.location.contain?(node_location) }
350
+ end
351
+
352
+ # @param api_map [ApiMap]
353
+ # @param name_pin [Pin::Base]
354
+ # @param locals [::Array<Pin::LocalVariable>]
355
+ # @return [ComplexType, nil]
356
+ def block_call_type api_map, name_pin, locals
357
+ return nil unless with_block?
358
+
359
+ block_pin = find_block_pin(api_map)
360
+ # We use the block pin as the closure, as the parameters
361
+ # here will only be defined inside the block itself and we
362
+ # need to be able to see them
363
+ # @sg-ignore Need to add nil check here
364
+ block.infer(api_map, block_pin, locals)
365
+ end
366
+
367
+ protected
368
+
369
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
370
+ def equality_fields
371
+ # @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
372
+ super + [arguments, block]
373
+ end
374
+ end
375
+ end
376
+ end
377
+ end