solargraph 0.54.0 → 0.58.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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +127 -0
  3. data/.github/workflows/plugins.yml +184 -6
  4. data/.github/workflows/rspec.yml +55 -5
  5. data/.github/workflows/typecheck.yml +8 -3
  6. data/.gitignore +7 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +1279 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +171 -0
  13. data/README.md +20 -6
  14. data/Rakefile +125 -13
  15. data/bin/solargraph +8 -5
  16. data/lib/solargraph/api_map/cache.rb +13 -3
  17. data/lib/solargraph/api_map/constants.rb +279 -0
  18. data/lib/solargraph/api_map/index.rb +193 -0
  19. data/lib/solargraph/api_map/source_to_yard.rb +13 -4
  20. data/lib/solargraph/api_map/store.rb +207 -132
  21. data/lib/solargraph/api_map.rb +394 -261
  22. data/lib/solargraph/bench.rb +18 -1
  23. data/lib/solargraph/complex_type/type_methods.rb +29 -12
  24. data/lib/solargraph/complex_type/unique_type.rb +205 -26
  25. data/lib/solargraph/complex_type.rb +126 -26
  26. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  27. data/lib/solargraph/convention/base.rb +20 -3
  28. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  29. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  30. data/lib/solargraph/convention/data_definition.rb +105 -0
  31. data/lib/solargraph/convention/gemspec.rb +3 -2
  32. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
  33. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
  34. data/lib/solargraph/convention/struct_definition.rb +164 -0
  35. data/lib/solargraph/convention.rb +36 -4
  36. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  37. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  38. data/lib/solargraph/doc_map.rb +316 -64
  39. data/lib/solargraph/environ.rb +9 -2
  40. data/lib/solargraph/equality.rb +34 -0
  41. data/lib/solargraph/gem_pins.rb +64 -38
  42. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  43. data/lib/solargraph/language_server/host/message_worker.rb +54 -5
  44. data/lib/solargraph/language_server/host.rb +36 -18
  45. data/lib/solargraph/language_server/message/base.rb +20 -12
  46. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  47. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  48. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  49. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  50. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  51. data/lib/solargraph/language_server/message/text_document/definition.rb +5 -3
  52. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  53. data/lib/solargraph/language_server/message/text_document/formatting.rb +23 -2
  54. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  55. data/lib/solargraph/language_server/message/text_document/type_definition.rb +4 -3
  56. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  57. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  58. data/lib/solargraph/language_server/progress.rb +27 -2
  59. data/lib/solargraph/language_server/request.rb +4 -1
  60. data/lib/solargraph/library.rb +83 -73
  61. data/lib/solargraph/location.rb +45 -1
  62. data/lib/solargraph/logging.rb +12 -2
  63. data/lib/solargraph/page.rb +3 -0
  64. data/lib/solargraph/parser/comment_ripper.rb +20 -7
  65. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
  66. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  67. data/lib/solargraph/parser/node_processor.rb +26 -8
  68. data/lib/solargraph/parser/parser_gem/class_methods.rb +10 -18
  69. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  70. data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
  71. data/lib/solargraph/parser/parser_gem/node_methods.rb +10 -19
  72. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  73. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -0
  74. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +26 -20
  75. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
  76. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  77. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  78. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  79. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  80. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  81. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
  82. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  83. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  84. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +14 -2
  85. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  86. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -0
  87. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  88. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
  89. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +16 -6
  90. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +64 -32
  91. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  92. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  93. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  94. data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
  95. data/lib/solargraph/parser/region.rb +4 -1
  96. data/lib/solargraph/parser/snippet.rb +2 -0
  97. data/lib/solargraph/parser.rb +3 -5
  98. data/lib/solargraph/pin/base.rb +417 -42
  99. data/lib/solargraph/pin/base_variable.rb +21 -12
  100. data/lib/solargraph/pin/block.rb +9 -26
  101. data/lib/solargraph/pin/breakable.rb +9 -0
  102. data/lib/solargraph/pin/callable.rb +231 -0
  103. data/lib/solargraph/pin/closure.rb +30 -10
  104. data/lib/solargraph/pin/common.rb +12 -7
  105. data/lib/solargraph/pin/constant.rb +2 -0
  106. data/lib/solargraph/pin/conversions.rb +3 -2
  107. data/lib/solargraph/pin/delegated_method.rb +20 -1
  108. data/lib/solargraph/pin/documenting.rb +16 -0
  109. data/lib/solargraph/pin/instance_variable.rb +2 -2
  110. data/lib/solargraph/pin/keyword.rb +7 -2
  111. data/lib/solargraph/pin/local_variable.rb +15 -7
  112. data/lib/solargraph/pin/method.rb +241 -70
  113. data/lib/solargraph/pin/method_alias.rb +3 -0
  114. data/lib/solargraph/pin/namespace.rb +21 -13
  115. data/lib/solargraph/pin/parameter.rb +94 -32
  116. data/lib/solargraph/pin/proxy_type.rb +17 -7
  117. data/lib/solargraph/pin/reference/override.rb +24 -6
  118. data/lib/solargraph/pin/reference/require.rb +2 -2
  119. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  120. data/lib/solargraph/pin/reference.rb +17 -0
  121. data/lib/solargraph/pin/search.rb +6 -1
  122. data/lib/solargraph/pin/signature.rb +39 -121
  123. data/lib/solargraph/pin/singleton.rb +1 -1
  124. data/lib/solargraph/pin/symbol.rb +8 -2
  125. data/lib/solargraph/pin/until.rb +18 -0
  126. data/lib/solargraph/pin/while.rb +18 -0
  127. data/lib/solargraph/pin.rb +8 -2
  128. data/lib/solargraph/pin_cache.rb +245 -0
  129. data/lib/solargraph/position.rb +19 -0
  130. data/lib/solargraph/range.rb +23 -4
  131. data/lib/solargraph/rbs_map/conversions.rb +315 -99
  132. data/lib/solargraph/rbs_map/core_fills.rb +50 -16
  133. data/lib/solargraph/rbs_map/core_map.rb +41 -11
  134. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  135. data/lib/solargraph/rbs_map.rb +87 -16
  136. data/lib/solargraph/shell.rb +117 -17
  137. data/lib/solargraph/source/chain/array.rb +13 -8
  138. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  139. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  140. data/lib/solargraph/source/chain/call.rb +135 -66
  141. data/lib/solargraph/source/chain/constant.rb +3 -66
  142. data/lib/solargraph/source/chain/hash.rb +9 -3
  143. data/lib/solargraph/source/chain/head.rb +1 -1
  144. data/lib/solargraph/source/chain/if.rb +7 -2
  145. data/lib/solargraph/source/chain/link.rb +38 -6
  146. data/lib/solargraph/source/chain/literal.rb +27 -2
  147. data/lib/solargraph/source/chain/or.rb +2 -2
  148. data/lib/solargraph/source/chain/z_super.rb +1 -1
  149. data/lib/solargraph/source/chain.rb +140 -63
  150. data/lib/solargraph/source/change.rb +2 -2
  151. data/lib/solargraph/source/cursor.rb +4 -4
  152. data/lib/solargraph/source/source_chainer.rb +3 -3
  153. data/lib/solargraph/source.rb +110 -89
  154. data/lib/solargraph/source_map/clip.rb +22 -28
  155. data/lib/solargraph/source_map/data.rb +34 -0
  156. data/lib/solargraph/source_map/mapper.rb +11 -7
  157. data/lib/solargraph/source_map.rb +50 -43
  158. data/lib/solargraph/type_checker/checks.rb +4 -0
  159. data/lib/solargraph/type_checker/param_def.rb +2 -0
  160. data/lib/solargraph/type_checker/rules.rb +35 -8
  161. data/lib/solargraph/type_checker.rb +331 -189
  162. data/lib/solargraph/version.rb +1 -1
  163. data/lib/solargraph/views/_method.erb +10 -10
  164. data/lib/solargraph/views/_namespace.erb +3 -3
  165. data/lib/solargraph/views/document.erb +10 -10
  166. data/lib/solargraph/views/environment.erb +3 -5
  167. data/lib/solargraph/workspace/config.rb +25 -5
  168. data/lib/solargraph/workspace/require_paths.rb +97 -0
  169. data/lib/solargraph/workspace.rb +53 -72
  170. data/lib/solargraph/yard_map/helpers.rb +29 -1
  171. data/lib/solargraph/yard_map/mapper/to_constant.rb +8 -5
  172. data/lib/solargraph/yard_map/mapper/to_method.rb +55 -19
  173. data/lib/solargraph/yard_map/mapper/to_namespace.rb +11 -7
  174. data/lib/solargraph/yard_map/mapper.rb +5 -3
  175. data/lib/solargraph/yard_map/to_method.rb +6 -3
  176. data/lib/solargraph/yardoc.rb +45 -10
  177. data/lib/solargraph.rb +35 -1
  178. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  179. data/rbs/fills/open3/0/open3.rbs +172 -0
  180. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  181. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  182. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  183. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  184. data/rbs/fills/tuple/tuple.rbs +149 -0
  185. data/rbs_collection.yaml +19 -0
  186. data/sig/shims/ast/0/node.rbs +5 -0
  187. data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
  188. data/sig/shims/ast/2.4/ast.rbs +73 -0
  189. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  190. data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
  191. data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
  192. data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  193. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  194. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  195. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  196. data/solargraph.gemspec +32 -10
  197. metadata +237 -37
  198. data/lib/.rubocop.yml +0 -22
  199. data/lib/solargraph/cache.rb +0 -77
  200. data/lib/solargraph/parser/node_methods.rb +0 -83
@@ -3,10 +3,20 @@
3
3
  module Solargraph
4
4
  class Source
5
5
  class Chain
6
- class Call < Link
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
+
7
14
  # @return [String]
8
15
  attr_reader :word
9
16
 
17
+ # @return [Location]
18
+ attr_reader :location
19
+
10
20
  # @return [::Array<Chain>]
11
21
  attr_reader :arguments
12
22
 
@@ -14,47 +24,55 @@ module Solargraph
14
24
  attr_reader :block
15
25
 
16
26
  # @param word [String]
27
+ # @param location [Location, nil]
17
28
  # @param arguments [::Array<Chain>]
18
29
  # @param block [Chain, nil]
19
- def initialize word, arguments = [], block = nil
30
+ def initialize word, location = nil, arguments = [], block = nil
20
31
  @word = word
32
+ @location = location
21
33
  @arguments = arguments
22
34
  @block = block
23
35
  fix_block_pass
24
36
  end
25
37
 
38
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
39
+ protected def equality_fields
40
+ super + [arguments, block]
41
+ end
42
+
26
43
  def with_block?
27
44
  !!@block
28
45
  end
29
46
 
30
47
  # @param api_map [ApiMap]
31
- # @param name_pin [Pin::Base]
48
+ # @param name_pin [Pin::Closure] name_pin.binder should give us the type of the object on which 'word' will be invoked
32
49
  # @param locals [::Array<Pin::LocalVariable>]
33
50
  def resolve api_map, name_pin, locals
34
51
  return super_pins(api_map, name_pin) if word == 'super'
35
52
  return yield_pins(api_map, name_pin) if word == 'yield'
36
53
  found = if head?
37
- locals.select { |p| p.name == word }
54
+ api_map.visible_pins(locals, word, name_pin, location)
38
55
  else
39
56
  []
40
57
  end
41
- return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
42
- # @param [ComplexType::UniqueType]
58
+ return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
43
59
  pins = name_pin.binder.each_unique_type.flat_map do |context|
44
- api_map.get_method_stack(context.namespace == '' ? '' : context.tag, word, scope: context.scope)
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
45
63
  end
46
64
  return [] if pins.empty?
47
- inferred_pins(pins, api_map, name_pin.context, locals)
65
+ inferred_pins(pins, api_map, name_pin, locals)
48
66
  end
49
67
 
50
68
  private
51
69
 
52
70
  # @param pins [::Enumerable<Pin::Method>]
53
71
  # @param api_map [ApiMap]
54
- # @param context [ComplexType]
55
- # @param locals [::Array<Pin::LocalVariable>]
72
+ # @param name_pin [Pin::Base]
73
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
56
74
  # @return [::Array<Pin::Base>]
57
- def inferred_pins pins, api_map, context, locals
75
+ def inferred_pins pins, api_map, name_pin, locals
58
76
  result = pins.map do |p|
59
77
  next p unless p.is_a?(Pin::Method)
60
78
  overloads = p.signatures
@@ -65,10 +83,12 @@ module Solargraph
65
83
  # use it. If we didn't pass a block, the logic below will
66
84
  # reject it regardless
67
85
 
68
- sorted_overloads = overloads.sort { |ol| ol.block? ? -1 : 1 }
86
+ with_block, without_block = overloads.partition(&:block?)
87
+ sorted_overloads = with_block + without_block
88
+ # @type [Pin::Signature, nil]
69
89
  new_signature_pin = nil
70
90
  sorted_overloads.each do |ol|
71
- next unless arity_matches?(arguments, ol)
91
+ next unless ol.arity_matches?(arguments, with_block?)
72
92
  match = true
73
93
 
74
94
  atypes = []
@@ -78,10 +98,11 @@ module Solargraph
78
98
  match = ol.parameters.any?(&:restarg?)
79
99
  break
80
100
  end
81
- atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
82
- # @todo Weak type comparison
83
- # unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
84
- unless param.return_type.undefined? || atype.name == param.return_type.name || api_map.super_and_sub?(param.return_type.name, atype.name) || param.return_type.generic?
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?
85
106
  match = false
86
107
  break
87
108
  end
@@ -89,11 +110,37 @@ module Solargraph
89
110
  if match
90
111
  if ol.block && with_block?
91
112
  block_atypes = ol.block.parameters.map(&:return_type)
92
- blocktype = block_call_type(api_map, context, block_atypes, locals)
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
93
119
  end
120
+ # @type new_signature_pin [Pin::Signature]
94
121
  new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
95
122
  new_return_type = new_signature_pin.return_type
96
- type = with_params(new_return_type.self_to(context.to_s), context).qualify(api_map, context.namespace) if new_return_type.defined?
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?
97
144
  type ||= ComplexType::UNDEFINED
98
145
  end
99
146
  break if type.defined?
@@ -101,20 +148,22 @@ module Solargraph
101
148
  p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
102
149
  next p.proxy(type) if type.defined?
103
150
  if !p.macros.empty?
104
- result = process_macro(p, api_map, context, locals)
151
+ result = process_macro(p, api_map, name_pin.context, locals)
105
152
  next result unless result.return_type.undefined?
106
153
  elsif !p.directives.empty?
107
- result = process_directive(p, api_map, context, locals)
154
+ result = process_directive(p, api_map, name_pin.context, locals)
108
155
  next result unless result.return_type.undefined?
109
156
  end
110
157
  p
111
158
  end
112
- result.map do |pin|
113
- if pin.path == 'Class#new' && context.tag != 'Class'
114
- pin.proxy(ComplexType.try_parse(context.namespace))
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)
115
164
  else
116
165
  next pin if pin.return_type.undefined?
117
- selfy = pin.return_type.self_to(context.tag)
166
+ selfy = pin.return_type.self_to_type(name_pin.binder)
118
167
  selfy == pin.return_type ? pin : pin.proxy(selfy)
119
168
  end
120
169
  end
@@ -123,7 +172,7 @@ module Solargraph
123
172
  # @param pin [Pin::Base]
124
173
  # @param api_map [ApiMap]
125
174
  # @param context [ComplexType]
126
- # @param locals [Enumerable<Pin::Base>]
175
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
127
176
  # @return [Pin::Base]
128
177
  def process_macro pin, api_map, context, locals
129
178
  pin.macros.each do |macro|
@@ -136,13 +185,13 @@ module Solargraph
136
185
  result = inner_process_macro(pin, macro, api_map, context, locals)
137
186
  return result unless result.return_type.undefined?
138
187
  end
139
- Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
188
+ Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
140
189
  end
141
190
 
142
191
  # @param pin [Pin::Method]
143
192
  # @param api_map [ApiMap]
144
193
  # @param context [ComplexType]
145
- # @param locals [Enumerable<Pin::Base>]
194
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
146
195
  # @return [Pin::ProxyType]
147
196
  def process_directive pin, api_map, context, locals
148
197
  pin.directives.each do |dir|
@@ -151,17 +200,17 @@ module Solargraph
151
200
  result = inner_process_macro(pin, macro, api_map, context, locals)
152
201
  return result unless result.return_type.undefined?
153
202
  end
154
- Pin::ProxyType.anonymous ComplexType::UNDEFINED
203
+ Pin::ProxyType.anonymous ComplexType::UNDEFINED, source: :chain
155
204
  end
156
205
 
157
206
  # @param pin [Pin::Base]
158
207
  # @param macro [YARD::Tags::MacroDirective]
159
208
  # @param api_map [ApiMap]
160
209
  # @param context [ComplexType]
161
- # @param locals [Enumerable<Pin::Base>]
210
+ # @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
162
211
  # @return [Pin::ProxyType]
163
212
  def inner_process_macro pin, macro, api_map, context, locals
164
- vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
213
+ vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals), source: :chain) }
165
214
  txt = macro.tag.text.clone
166
215
  if txt.empty? && macro.tag.name
167
216
  named = api_map.named_macro(macro.tag.name)
@@ -175,9 +224,9 @@ module Solargraph
175
224
  docstring = Solargraph::Source.parse_docstring(txt).to_docstring
176
225
  tag = docstring.tag(:return)
177
226
  unless tag.nil? || tag.types.nil?
178
- return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types))
227
+ return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types), source: :chain)
179
228
  end
180
- Pin::ProxyType.anonymous(ComplexType::UNDEFINED)
229
+ Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
181
230
  end
182
231
 
183
232
  # @param docstring [YARD::Docstring]
@@ -192,24 +241,24 @@ module Solargraph
192
241
  nil
193
242
  end
194
243
 
195
- # @param arguments [::Array<Chain>]
196
- # @param signature [Pin::Signature]
197
- # @return [Boolean]
198
- def arity_matches? arguments, signature
199
- parameters = signature.parameters
200
- argcount = arguments.length
201
- parcount = parameters.length
202
- parcount -= 1 if !parameters.empty? && parameters.last.block?
203
- return false if signature.block? && !with_block?
204
- return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
205
- true
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
206
253
  end
207
254
 
208
255
  # @param api_map [ApiMap]
209
256
  # @param name_pin [Pin::Base]
210
257
  # @return [::Array<Pin::Base>]
211
258
  def super_pins api_map, name_pin
212
- pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope)
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)
213
262
  pins.reject{|p| p.path == name_pin.path}
214
263
  end
215
264
 
@@ -217,10 +266,14 @@ module Solargraph
217
266
  # @param name_pin [Pin::Base]
218
267
  # @return [::Array<Pin::Base>]
219
268
  def yield_pins api_map, name_pin
220
- method_pin = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope).first
221
- return [] if method_pin.nil?
269
+ method_pin = find_method_pin(name_pin)
270
+ return [] unless method_pin
222
271
 
223
- method_pin.signatures.map(&:block).compact
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
224
277
  end
225
278
 
226
279
  # @param type [ComplexType]
@@ -228,7 +281,7 @@ module Solargraph
228
281
  # @return [ComplexType]
229
282
  def with_params type, context
230
283
  return type unless type.to_s.include?('$')
231
- ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
284
+ ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:rooted_tag).join(', ')).gsub('<>', ''))
232
285
  end
233
286
 
234
287
  # @return [void]
@@ -242,25 +295,41 @@ module Solargraph
242
295
  # @param block_parameter_types [::Array<ComplexType>]
243
296
  # @param locals [::Array<Pin::LocalVariable>]
244
297
  # @return [ComplexType, nil]
245
- def block_call_type(api_map, context, block_parameter_types, locals)
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)
246
327
  return nil unless with_block?
247
328
 
248
- # @todo Handle BlockVariable
249
- if block.links.map(&:class) == [BlockSymbol]
250
- # Ruby's shorthand for sending the passed in method name
251
- # to the first yield parameter with no arguments
252
- block_symbol_name = block.links.first.word
253
- block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
254
- callee = api_map.get_path_pins(block_symbol_call_path).first
255
- return_type = callee&.return_type
256
- # @todo: Figure out why we get unresolved generics at
257
- # this point and need to assume method return types
258
- # based on the generic type
259
- return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
260
- return_type || ComplexType::UNDEFINED
261
- else
262
- block.infer(api_map, Pin::ProxyType.anonymous(context), locals)
263
- end
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)
264
333
  end
265
334
  end
266
335
  end
@@ -15,73 +15,10 @@ module Solargraph
15
15
  gates = ['']
16
16
  else
17
17
  base = word
18
- gates = crawl_gates(name_pin)
18
+ gates = name_pin.gates
19
19
  end
20
- parts = base.split('::')
21
- gates.each do |gate|
22
- # @todo 'Wrong argument type for
23
- # Solargraph::Source::Chain::Constant#deep_constant_type:
24
- # gate expected String, received generic<Elem>' is because
25
- # we lose 'rooted' information in the 'Chain::Array' class
26
- # internally, leaving ::Array#each shadowed when it
27
- # shouldn't be.
28
- type = deep_constant_type(gate, api_map)
29
- # Use deep inference to resolve root
30
- parts[0..-2].each do |sym|
31
- pins = api_map.get_constants('', type.namespace).select{ |pin| pin.name == sym }
32
- type = first_pin_type(pins, api_map)
33
- break if type.undefined?
34
- end
35
- next if type.undefined?
36
- result = api_map.get_constants('', type.namespace).select { |pin| pin.name == parts.last }
37
- return result unless result.empty?
38
- end
39
- []
40
- end
41
-
42
- private
43
-
44
- # @param pin [Pin::Base]
45
- # @return [::Array<String>]
46
- def crawl_gates pin
47
- clos = pin
48
- until clos.nil?
49
- if clos.is_a?(Pin::Namespace)
50
- gates = clos.gates
51
- gates.push('') if gates.empty?
52
- return gates
53
- end
54
- clos = clos.closure
55
- end
56
- ['']
57
- end
58
-
59
- # @param pins [::Array<Pin::Base>]
60
- # @param api_map [ApiMap]
61
- # @return [ComplexType]
62
- def first_pin_type(pins, api_map)
63
- type = ComplexType::UNDEFINED
64
- pins.each do |pin|
65
- type = pin.typify(api_map)
66
- break if type.defined?
67
- type = pin.probe(api_map)
68
- break if type.defined?
69
- end
70
- type
71
- end
72
-
73
- # @param gate [String]
74
- # @param api_map [ApiMap]
75
- # @return [ComplexType]
76
- def deep_constant_type(gate, api_map)
77
- type = ComplexType::ROOT
78
- return type if gate == ''
79
- gate.split('::').each do |word|
80
- pins = api_map.get_constants('', type.namespace).select { |pin| pin.name == word }
81
- type = first_pin_type(pins, api_map)
82
- break if type.undefined?
83
- end
84
- type
20
+ fqns = api_map.resolve(base, gates)
21
+ api_map.get_path_pins(fqns)
85
22
  end
86
23
  end
87
24
  end
@@ -5,18 +5,24 @@ module Solargraph
5
5
  class Chain
6
6
  class Hash < Literal
7
7
  # @param type [String]
8
+ # @param node [Parser::AST::Node]
8
9
  # @param splatted [Boolean]
9
- def initialize type, splatted = false
10
- super(type)
10
+ def initialize type, node, splatted = false
11
+ super(type, node)
11
12
  @splatted = splatted
12
13
  end
13
14
 
15
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
16
+ protected def equality_fields
17
+ super + [@splatted]
18
+ end
19
+
14
20
  def word
15
21
  @word ||= "<#{@type}>"
16
22
  end
17
23
 
18
24
  def resolve api_map, name_pin, locals
19
- [Pin::ProxyType.anonymous(@complex_type)]
25
+ [Pin::ProxyType.anonymous(@complex_type, source: :chain)]
20
26
  end
21
27
 
22
28
  def splatted?
@@ -9,7 +9,7 @@ module Solargraph
9
9
  # @note Chain::Head is only intended to handle `self` and `super`.
10
10
  class Head < Link
11
11
  def resolve api_map, name_pin, locals
12
- return [Pin::ProxyType.anonymous(name_pin.binder)] if word == 'self'
12
+ return [Pin::ProxyType.anonymous(name_pin.binder, source: :chain)] if word == 'self'
13
13
  # return super_pins(api_map, name_pin) if word == 'super'
14
14
  []
15
15
  end
@@ -8,14 +8,19 @@ module Solargraph
8
8
  '<if>'
9
9
  end
10
10
 
11
- # @param links [::Array<Link>]
11
+ # @param links [::Array<Chain>]
12
12
  def initialize links
13
13
  @links = links
14
14
  end
15
15
 
16
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
17
+ protected def equality_fields
18
+ super + [@links]
19
+ end
20
+
16
21
  def resolve api_map, name_pin, locals
17
22
  types = @links.map { |link| link.infer(api_map, name_pin, locals) }
18
- [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')))]
23
+ [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')), source: :chain)]
19
24
  end
20
25
  end
21
26
  end
@@ -4,6 +4,8 @@ module Solargraph
4
4
  class Source
5
5
  class Chain
6
6
  class Link
7
+ include Equality
8
+
7
9
  # @return [String]
8
10
  attr_reader :word
9
11
 
@@ -15,6 +17,17 @@ module Solargraph
15
17
  @word = word
16
18
  end
17
19
 
20
+ # @sg-ignore two problems - Declared return type
21
+ # ::Solargraph::Source::Chain::Array does not match inferred
22
+ # type ::Array(::Class<::Solargraph::Source::Chain::Link>,
23
+ # ::String) for
24
+ # Solargraph::Source::Chain::Link#equality_fields
25
+ # and
26
+ # Not enough arguments to Module#protected
27
+ protected def equality_fields
28
+ [self.class, word]
29
+ end
30
+
18
31
  def undefined?
19
32
  word == '<undefined>'
20
33
  end
@@ -25,24 +38,30 @@ module Solargraph
25
38
 
26
39
  # @param api_map [ApiMap]
27
40
  # @param name_pin [Pin::Base]
28
- # @param locals [::Enumerable<Pin::Base>]
41
+ # @param locals [::Array<Pin::Base>]
29
42
  # @return [::Array<Pin::Base>]
30
43
  def resolve api_map, name_pin, locals
31
44
  []
32
45
  end
33
46
 
47
+ # debugging description of contents; not for machine use
48
+ # @return [String]
49
+ def desc
50
+ word
51
+ end
52
+
53
+ def to_s
54
+ desc
55
+ end
56
+
34
57
  def inspect
35
- "#{self.class} #{word}"
58
+ "#<#{self.class} - `#{self.desc}`>"
36
59
  end
37
60
 
38
61
  def head?
39
62
  @head ||= false
40
63
  end
41
64
 
42
- def == other
43
- self.class == other.class and word == other.word
44
- end
45
-
46
65
  # Make a copy of this link marked as the head of a chain
47
66
  #
48
67
  # @return [self]
@@ -61,6 +80,19 @@ module Solargraph
61
80
  false
62
81
  end
63
82
 
83
+ # debugging description of contents; not for machine use
84
+ #
85
+ # @return [String]
86
+ def desc
87
+ word
88
+ end
89
+
90
+ def inspect
91
+ "#<#{self.class} - `#{self.desc}`>"
92
+ end
93
+
94
+ include Logging
95
+
64
96
  protected
65
97
 
66
98
  # Mark whether this link is the head of a chain
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'parser'
4
+
3
5
  module Solargraph
4
6
  class Source
5
7
  class Chain
@@ -8,14 +10,37 @@ module Solargraph
8
10
  @word ||= "<#{@type}>"
9
11
  end
10
12
 
13
+ attr_reader :value
14
+
11
15
  # @param type [String]
12
- def initialize type
16
+ # @param node [Parser::AST::Node, Object]
17
+ def initialize type, node
18
+ if node.is_a?(::Parser::AST::Node)
19
+ if node.type == :true
20
+ @value = true
21
+ elsif node.type == :false
22
+ @value = false
23
+ elsif [:int, :sym].include?(node.type)
24
+ @value = node.children.first
25
+ end
26
+ end
13
27
  @type = type
28
+ @literal_type = ComplexType.try_parse(@value.inspect)
14
29
  @complex_type = ComplexType.try_parse(type)
15
30
  end
16
31
 
32
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
33
+ protected def equality_fields
34
+ super + [@value, @type, @literal_type, @complex_type]
35
+ end
36
+
17
37
  def resolve api_map, name_pin, locals
18
- [Pin::ProxyType.anonymous(@complex_type)]
38
+ if api_map.super_and_sub?(@complex_type.name, @literal_type.name)
39
+ [Pin::ProxyType.anonymous(@literal_type, source: :chain)]
40
+ else
41
+ # we don't support this value as a literal type
42
+ [Pin::ProxyType.anonymous(@complex_type, source: :chain)]
43
+ end
19
44
  end
20
45
  end
21
46
  end
@@ -8,14 +8,14 @@ module Solargraph
8
8
  '<or>'
9
9
  end
10
10
 
11
- # @param links [::Array<Link>]
11
+ # @param links [::Array<Chain>]
12
12
  def initialize links
13
13
  @links = links
14
14
  end
15
15
 
16
16
  def resolve api_map, name_pin, locals
17
17
  types = @links.map { |link| link.infer(api_map, name_pin, locals) }
18
- [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')))]
18
+ [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.new(types.uniq), source: :chain)]
19
19
  end
20
20
  end
21
21
  end
@@ -15,7 +15,7 @@ module Solargraph
15
15
  # @param with_block [Boolean] True if the chain is inside a block
16
16
  # @param head [Boolean] True if the call is the start of its chain
17
17
  def initialize word, with_block = false
18
- super(word, [], with_block)
18
+ super(word, nil, [], with_block)
19
19
  end
20
20
 
21
21
  # @param api_map [ApiMap]