solargraph 0.47.2 → 0.54.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 (191) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/plugins.yml +40 -0
  4. data/.github/workflows/rspec.yml +4 -8
  5. data/.github/workflows/typecheck.yml +34 -0
  6. data/.yardopts +2 -2
  7. data/CHANGELOG.md +166 -3
  8. data/LICENSE +1 -1
  9. data/README.md +19 -16
  10. data/SPONSORS.md +2 -9
  11. data/lib/solargraph/api_map/cache.rb +50 -20
  12. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  13. data/lib/solargraph/api_map/store.rb +68 -15
  14. data/lib/solargraph/api_map.rb +238 -112
  15. data/lib/solargraph/bench.rb +3 -2
  16. data/lib/solargraph/cache.rb +77 -0
  17. data/lib/solargraph/complex_type/type_methods.rb +116 -35
  18. data/lib/solargraph/complex_type/unique_type.rb +261 -33
  19. data/lib/solargraph/complex_type.rb +149 -30
  20. data/lib/solargraph/convention/rakefile.rb +17 -0
  21. data/lib/solargraph/convention.rb +2 -3
  22. data/lib/solargraph/converters/dd.rb +5 -0
  23. data/lib/solargraph/converters/dl.rb +3 -0
  24. data/lib/solargraph/converters/dt.rb +3 -0
  25. data/lib/solargraph/diagnostics/rubocop.rb +23 -8
  26. data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
  27. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  28. data/lib/solargraph/diagnostics.rb +2 -2
  29. data/lib/solargraph/doc_map.rb +187 -0
  30. data/lib/solargraph/gem_pins.rb +72 -0
  31. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  32. data/lib/solargraph/language_server/host/dispatch.rb +22 -5
  33. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  34. data/lib/solargraph/language_server/host/sources.rb +8 -65
  35. data/lib/solargraph/language_server/host.rb +88 -93
  36. data/lib/solargraph/language_server/message/base.rb +1 -1
  37. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  38. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  39. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  40. data/lib/solargraph/language_server/message/initialize.rb +27 -0
  41. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  42. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  43. data/lib/solargraph/language_server/message/text_document/formatting.rb +5 -4
  44. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  45. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  46. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  47. data/lib/solargraph/language_server/message/text_document.rb +1 -1
  48. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  49. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  50. data/lib/solargraph/language_server/message.rb +1 -0
  51. data/lib/solargraph/language_server/progress.rb +118 -0
  52. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  53. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  54. data/lib/solargraph/language_server.rb +1 -0
  55. data/lib/solargraph/library.rb +231 -104
  56. data/lib/solargraph/location.rb +1 -0
  57. data/lib/solargraph/page.rb +6 -0
  58. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  59. data/lib/solargraph/parser/node_methods.rb +47 -7
  60. data/lib/solargraph/parser/node_processor/base.rb +11 -1
  61. data/lib/solargraph/parser/node_processor.rb +1 -0
  62. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
  63. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
  65. data/lib/solargraph/parser/parser_gem/node_methods.rb +495 -0
  66. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  67. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
  68. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  69. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +14 -4
  71. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  72. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/def_node.rb +7 -20
  73. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  74. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  75. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  76. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  77. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
  78. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  79. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  80. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  81. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +42 -0
  82. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +7 -5
  83. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sym_node.rb +1 -1
  84. data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -0
  85. data/lib/solargraph/parser/parser_gem.rb +12 -0
  86. data/lib/solargraph/parser/region.rb +1 -1
  87. data/lib/solargraph/parser/snippet.rb +2 -0
  88. data/lib/solargraph/parser.rb +9 -10
  89. data/lib/solargraph/pin/base.rb +69 -11
  90. data/lib/solargraph/pin/base_variable.rb +40 -7
  91. data/lib/solargraph/pin/block.rb +81 -33
  92. data/lib/solargraph/pin/closure.rb +17 -2
  93. data/lib/solargraph/pin/common.rb +7 -3
  94. data/lib/solargraph/pin/conversions.rb +34 -8
  95. data/lib/solargraph/pin/delegated_method.rb +101 -0
  96. data/lib/solargraph/pin/documenting.rb +25 -32
  97. data/lib/solargraph/pin/instance_variable.rb +4 -0
  98. data/lib/solargraph/pin/local_variable.rb +13 -1
  99. data/lib/solargraph/pin/method.rb +273 -17
  100. data/lib/solargraph/pin/namespace.rb +17 -1
  101. data/lib/solargraph/pin/parameter.rb +40 -28
  102. data/lib/solargraph/pin/reference/override.rb +2 -2
  103. data/lib/solargraph/pin/reference.rb +8 -0
  104. data/lib/solargraph/pin/search.rb +4 -4
  105. data/lib/solargraph/pin/signature.rb +143 -0
  106. data/lib/solargraph/pin.rb +2 -1
  107. data/lib/solargraph/range.rb +4 -6
  108. data/lib/solargraph/rbs_map/conversions.rb +607 -0
  109. data/lib/solargraph/rbs_map/core_fills.rb +50 -0
  110. data/lib/solargraph/rbs_map/core_map.rb +28 -0
  111. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -0
  112. data/lib/solargraph/rbs_map.rb +92 -0
  113. data/lib/solargraph/shell.rb +85 -59
  114. data/lib/solargraph/source/chain/array.rb +32 -0
  115. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  116. data/lib/solargraph/source/chain/call.rb +125 -61
  117. data/lib/solargraph/source/chain/constant.rb +15 -1
  118. data/lib/solargraph/source/chain/if.rb +23 -0
  119. data/lib/solargraph/source/chain/link.rb +8 -2
  120. data/lib/solargraph/source/chain/or.rb +1 -1
  121. data/lib/solargraph/source/chain/z_super.rb +3 -3
  122. data/lib/solargraph/source/chain.rb +64 -14
  123. data/lib/solargraph/source/change.rb +3 -0
  124. data/lib/solargraph/source/cursor.rb +2 -0
  125. data/lib/solargraph/source/source_chainer.rb +8 -5
  126. data/lib/solargraph/source/updater.rb +1 -0
  127. data/lib/solargraph/source.rb +18 -63
  128. data/lib/solargraph/source_map/clip.rb +31 -23
  129. data/lib/solargraph/source_map/mapper.rb +23 -7
  130. data/lib/solargraph/source_map.rb +36 -11
  131. data/lib/solargraph/type_checker/checks.rb +10 -2
  132. data/lib/solargraph/type_checker.rb +229 -100
  133. data/lib/solargraph/version.rb +1 -1
  134. data/lib/solargraph/views/environment.erb +2 -2
  135. data/lib/solargraph/workspace/config.rb +15 -11
  136. data/lib/solargraph/workspace.rb +41 -17
  137. data/lib/solargraph/yard_map/cache.rb +6 -0
  138. data/lib/solargraph/yard_map/helpers.rb +1 -1
  139. data/lib/solargraph/yard_map/mapper/to_method.rb +23 -7
  140. data/lib/solargraph/yard_map/mapper.rb +1 -1
  141. data/lib/solargraph/yard_map/to_method.rb +11 -4
  142. data/lib/solargraph/yard_map.rb +1 -443
  143. data/lib/solargraph/yard_tags.rb +20 -0
  144. data/lib/solargraph/yardoc.rb +52 -0
  145. data/lib/solargraph.rb +8 -6
  146. data/solargraph.gemspec +19 -8
  147. metadata +164 -99
  148. data/.travis.yml +0 -19
  149. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  150. data/lib/solargraph/compat.rb +0 -37
  151. data/lib/solargraph/convention/rspec.rb +0 -30
  152. data/lib/solargraph/documentor.rb +0 -76
  153. data/lib/solargraph/language_server/host/cataloger.rb +0 -56
  154. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  155. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  156. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
  157. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  158. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +0 -23
  159. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +0 -63
  160. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +0 -21
  161. data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
  162. data/lib/solargraph/parser/legacy.rb +0 -12
  163. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -144
  164. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  165. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
  166. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  167. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  168. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -22
  169. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -57
  170. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  171. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  172. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  173. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  174. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  175. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  176. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  177. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  178. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
  179. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -21
  180. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  181. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -277
  182. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +0 -18
  183. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
  184. data/lib/solargraph/parser/rubyvm.rb +0 -40
  185. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  186. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  187. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  188. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  189. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  190. data/lib/yard-solargraph.rb +0 -33
  191. data/yardoc/2.2.2.tar.gz +0 -0
@@ -7,97 +7,100 @@ module Solargraph
7
7
  # @return [String]
8
8
  attr_reader :word
9
9
 
10
- # @return [Array<Chain>]
10
+ # @return [::Array<Chain>]
11
11
  attr_reader :arguments
12
12
 
13
+ # @return [Chain, nil]
14
+ attr_reader :block
15
+
13
16
  # @param word [String]
14
- # @param arguments [Array<Chain>]
15
- # @param with_block [Boolean] True if the chain is inside a block
16
- # @param head [Boolean] True if the call is the start of its chain
17
- def initialize word, arguments = [], with_block = false
17
+ # @param arguments [::Array<Chain>]
18
+ # @param block [Chain, nil]
19
+ def initialize word, arguments = [], block = nil
18
20
  @word = word
19
21
  @arguments = arguments
20
- @with_block = with_block
22
+ @block = block
23
+ fix_block_pass
21
24
  end
22
25
 
23
26
  def with_block?
24
- @with_block
27
+ !!@block
25
28
  end
26
29
 
27
30
  # @param api_map [ApiMap]
28
31
  # @param name_pin [Pin::Base]
29
- # @param locals [Array<Pin::Base>]
32
+ # @param locals [::Array<Pin::LocalVariable>]
30
33
  def resolve api_map, name_pin, locals
31
34
  return super_pins(api_map, name_pin) if word == 'super'
35
+ return yield_pins(api_map, name_pin) if word == 'yield'
32
36
  found = if head?
33
37
  locals.select { |p| p.name == word }
34
38
  else
35
39
  []
36
40
  end
37
41
  return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
38
- pins = api_map.get_method_stack(name_pin.binder.namespace, word, scope: name_pin.binder.scope)
42
+ # @param [ComplexType::UniqueType]
43
+ 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)
45
+ end
39
46
  return [] if pins.empty?
40
47
  inferred_pins(pins, api_map, name_pin.context, locals)
41
48
  end
42
49
 
43
50
  private
44
51
 
45
- # @param pins [Array<Pin::Base>]
52
+ # @param pins [::Enumerable<Pin::Method>]
46
53
  # @param api_map [ApiMap]
47
54
  # @param context [ComplexType]
48
- # @param locals [Pin::LocalVariable]
49
- # @return [Array<Pin::Base>]
55
+ # @param locals [::Array<Pin::LocalVariable>]
56
+ # @return [::Array<Pin::Base>]
50
57
  def inferred_pins pins, api_map, context, locals
51
58
  result = pins.map do |p|
52
- overloads = p.docstring.tags(:overload)
59
+ next p unless p.is_a?(Pin::Method)
60
+ overloads = p.signatures
53
61
  # next p if overloads.empty?
54
62
  type = ComplexType::UNDEFINED
55
- # @param [YARD::Tags::OverloadTag]
56
- overloads.each do |ol|
57
- next unless arguments_match(arguments, ol.parameters)
58
- next if ol.parameters.last && ol.parameters.last.first.start_with?('&') && ol.parameters.last.last.nil? && !with_block?
63
+ # start with overloads that require blocks; if we are
64
+ # passing a block, we want to find a signature that will
65
+ # use it. If we didn't pass a block, the logic below will
66
+ # reject it regardless
67
+
68
+ sorted_overloads = overloads.sort { |ol| ol.block? ? -1 : 1 }
69
+ new_signature_pin = nil
70
+ sorted_overloads.each do |ol|
71
+ next unless arity_matches?(arguments, ol)
59
72
  match = true
73
+
74
+ atypes = []
60
75
  arguments.each_with_index do |arg, idx|
61
- achain = arguments[idx]
62
- next if achain.nil?
63
76
  param = ol.parameters[idx]
64
77
  if param.nil?
65
- match = false unless ol.parameters.last && ol.parameters.last.first.start_with?('*')
78
+ match = ol.parameters.any?(&:restarg?)
66
79
  break
67
80
  end
68
- par = ol.tags(:param).select { |pp| pp.name == param.first }.first
69
- next if par.nil? || par.types.nil? || par.types.empty?
70
- atype = achain.infer(api_map, Pin::ProxyType.anonymous(context), locals)
71
- other = ComplexType.try_parse(*par.types)
81
+ atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
72
82
  # @todo Weak type comparison
73
- unless atype.tag == other.tag || api_map.super_and_sub?(other.tag, atype.tag)
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?
74
85
  match = false
75
86
  break
76
87
  end
77
88
  end
78
89
  if match
79
- type = extra_return_type(ol, context)
80
- break if type
81
- type = ComplexType.try_parse(*ol.tag(:return).types).self_to(context.to_s).qualify(api_map, context.namespace) if ol.has_tag?(:return) && ol.tag(:return).types && !ol.tag(:return).types.empty? && (type.nil? || type.undefined?)
90
+ if ol.block && with_block?
91
+ block_atypes = ol.block.parameters.map(&:return_type)
92
+ blocktype = block_call_type(api_map, context, block_atypes, locals)
93
+ end
94
+ new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
95
+ 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?
82
97
  type ||= ComplexType::UNDEFINED
83
98
  end
84
99
  break if type.defined?
85
100
  end
101
+ p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
86
102
  next p.proxy(type) if type.defined?
87
- type = extra_return_type(p.docstring, context)
88
- if type
89
- next Solargraph::Pin::Method.new(
90
- location: p.location,
91
- closure: p.closure,
92
- name: p.name,
93
- comments: "@return [#{context.subtypes.first.to_s}]",
94
- scope: p.scope,
95
- visibility: p.visibility,
96
- parameters: p.parameters,
97
- node: p.node
98
- )
99
- end
100
- if p.is_a?(Pin::Method) && !p.macros.empty?
103
+ if !p.macros.empty?
101
104
  result = process_macro(p, api_map, context, locals)
102
105
  next result unless result.return_type.undefined?
103
106
  elsif !p.directives.empty?
@@ -107,19 +110,29 @@ module Solargraph
107
110
  p
108
111
  end
109
112
  result.map do |pin|
110
- next pin if pin.return_type.undefined?
111
- selfy = pin.return_type.self_to(context.tag)
112
- selfy == pin.return_type ? pin : pin.proxy(selfy)
113
+ if pin.path == 'Class#new' && context.tag != 'Class'
114
+ pin.proxy(ComplexType.try_parse(context.namespace))
115
+ else
116
+ next pin if pin.return_type.undefined?
117
+ selfy = pin.return_type.self_to(context.tag)
118
+ selfy == pin.return_type ? pin : pin.proxy(selfy)
119
+ end
113
120
  end
114
121
  end
115
122
 
116
- # @param pin [Pin::Method]
123
+ # @param pin [Pin::Base]
117
124
  # @param api_map [ApiMap]
118
125
  # @param context [ComplexType]
119
- # @param locals [Pin::Base]
126
+ # @param locals [Enumerable<Pin::Base>]
120
127
  # @return [Pin::Base]
121
128
  def process_macro pin, api_map, context, locals
122
129
  pin.macros.each do |macro|
130
+ # @todo 'Wrong argument type for
131
+ # Solargraph::Source::Chain::Call#inner_process_macro:
132
+ # macro expected YARD::Tags::MacroDirective, received
133
+ # generic<Elem>' is because we lose 'rooted' information
134
+ # in the 'Chain::Array' class internally, leaving
135
+ # ::Array#each shadowed when it shouldn't be.
123
136
  result = inner_process_macro(pin, macro, api_map, context, locals)
124
137
  return result unless result.return_type.undefined?
125
138
  end
@@ -129,7 +142,7 @@ module Solargraph
129
142
  # @param pin [Pin::Method]
130
143
  # @param api_map [ApiMap]
131
144
  # @param context [ComplexType]
132
- # @param locals [Pin::Base]
145
+ # @param locals [Enumerable<Pin::Base>]
133
146
  # @return [Pin::ProxyType]
134
147
  def process_directive pin, api_map, context, locals
135
148
  pin.directives.each do |dir|
@@ -141,11 +154,11 @@ module Solargraph
141
154
  Pin::ProxyType.anonymous ComplexType::UNDEFINED
142
155
  end
143
156
 
144
- # @param pin [Pin]
157
+ # @param pin [Pin::Base]
145
158
  # @param macro [YARD::Tags::MacroDirective]
146
159
  # @param api_map [ApiMap]
147
160
  # @param context [ComplexType]
148
- # @param locals [Array<Pin::Base>]
161
+ # @param locals [Enumerable<Pin::Base>]
149
162
  # @return [Pin::ProxyType]
150
163
  def inner_process_macro pin, macro, api_map, context, locals
151
164
  vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
@@ -169,35 +182,86 @@ module Solargraph
169
182
 
170
183
  # @param docstring [YARD::Docstring]
171
184
  # @param context [ComplexType]
172
- # @return [ComplexType]
185
+ # @return [ComplexType, nil]
173
186
  def extra_return_type docstring, context
174
- if docstring.has_tag?(:return_single_parameter) #&& context.subtypes.one?
187
+ if docstring.has_tag?('return_single_parameter') #&& context.subtypes.one?
175
188
  return context.subtypes.first || ComplexType::UNDEFINED
176
- elsif docstring.has_tag?(:return_value_parameter) && context.value_types.one?
189
+ elsif docstring.has_tag?('return_value_parameter') && context.value_types.one?
177
190
  return context.value_types.first
178
191
  end
179
192
  nil
180
193
  end
181
194
 
182
- # @param arguments [Array<Chain>]
183
- # @param parameters [Array<String>]
195
+ # @param arguments [::Array<Chain>]
196
+ # @param signature [Pin::Signature]
184
197
  # @return [Boolean]
185
- def arguments_match arguments, parameters
198
+ def arity_matches? arguments, signature
199
+ parameters = signature.parameters
186
200
  argcount = arguments.length
187
- # argcount -= 1 if !arguments.empty? && arguments.last.links.first.word.start_with?('&')
188
201
  parcount = parameters.length
189
- parcount -= 1 if !parameters.empty? && parameters.last.first.start_with?('&')
190
- return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.first.start_with?('*'))
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?)
191
205
  true
192
206
  end
193
207
 
194
208
  # @param api_map [ApiMap]
195
209
  # @param name_pin [Pin::Base]
196
- # @return [Array<Pin::Base>]
210
+ # @return [::Array<Pin::Base>]
197
211
  def super_pins api_map, name_pin
198
- pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.scope)
212
+ pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope)
199
213
  pins.reject{|p| p.path == name_pin.path}
200
214
  end
215
+
216
+ # @param api_map [ApiMap]
217
+ # @param name_pin [Pin::Base]
218
+ # @return [::Array<Pin::Base>]
219
+ 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?
222
+
223
+ method_pin.signatures.map(&:block).compact
224
+ end
225
+
226
+ # @param type [ComplexType]
227
+ # @param context [ComplexType]
228
+ # @return [ComplexType]
229
+ def with_params type, context
230
+ return type unless type.to_s.include?('$')
231
+ ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
232
+ end
233
+
234
+ # @return [void]
235
+ def fix_block_pass
236
+ argument = @arguments.last&.links&.first
237
+ @block = @arguments.pop if argument.is_a?(BlockSymbol) || argument.is_a?(BlockVariable)
238
+ end
239
+
240
+ # @param api_map [ApiMap]
241
+ # @param context [ComplexType]
242
+ # @param block_parameter_types [::Array<ComplexType>]
243
+ # @param locals [::Array<Pin::LocalVariable>]
244
+ # @return [ComplexType, nil]
245
+ def block_call_type(api_map, context, block_parameter_types, locals)
246
+ return nil unless with_block?
247
+
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
264
+ end
201
265
  end
202
266
  end
203
267
  end
@@ -19,8 +19,14 @@ module Solargraph
19
19
  end
20
20
  parts = base.split('::')
21
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.
22
28
  type = deep_constant_type(gate, api_map)
23
- # Use deep inference to resolve root
29
+ # Use deep inference to resolve root
24
30
  parts[0..-2].each do |sym|
25
31
  pins = api_map.get_constants('', type.namespace).select{ |pin| pin.name == sym }
26
32
  type = first_pin_type(pins, api_map)
@@ -35,6 +41,8 @@ module Solargraph
35
41
 
36
42
  private
37
43
 
44
+ # @param pin [Pin::Base]
45
+ # @return [::Array<String>]
38
46
  def crawl_gates pin
39
47
  clos = pin
40
48
  until clos.nil?
@@ -48,6 +56,9 @@ module Solargraph
48
56
  ['']
49
57
  end
50
58
 
59
+ # @param pins [::Array<Pin::Base>]
60
+ # @param api_map [ApiMap]
61
+ # @return [ComplexType]
51
62
  def first_pin_type(pins, api_map)
52
63
  type = ComplexType::UNDEFINED
53
64
  pins.each do |pin|
@@ -59,6 +70,9 @@ module Solargraph
59
70
  type
60
71
  end
61
72
 
73
+ # @param gate [String]
74
+ # @param api_map [ApiMap]
75
+ # @return [ComplexType]
62
76
  def deep_constant_type(gate, api_map)
63
77
  type = ComplexType::ROOT
64
78
  return type if gate == ''
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ class Chain
6
+ class If < Link
7
+ def word
8
+ '<if>'
9
+ end
10
+
11
+ # @param links [::Array<Link>]
12
+ def initialize links
13
+ @links = links
14
+ end
15
+
16
+ def resolve api_map, name_pin, locals
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(', ')))]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -7,8 +7,10 @@ module Solargraph
7
7
  # @return [String]
8
8
  attr_reader :word
9
9
 
10
+ # @return [Pin::Base]
10
11
  attr_accessor :last_context
11
12
 
13
+ # @param word [String]
12
14
  def initialize word = '<undefined>'
13
15
  @word = word
14
16
  end
@@ -23,12 +25,16 @@ module Solargraph
23
25
 
24
26
  # @param api_map [ApiMap]
25
27
  # @param name_pin [Pin::Base]
26
- # @param locals [Array<Pin::Base>]
27
- # @return [Array<Pin::Base>]
28
+ # @param locals [::Enumerable<Pin::Base>]
29
+ # @return [::Array<Pin::Base>]
28
30
  def resolve api_map, name_pin, locals
29
31
  []
30
32
  end
31
33
 
34
+ def inspect
35
+ "#{self.class} #{word}"
36
+ end
37
+
32
38
  def head?
33
39
  @head ||= false
34
40
  end
@@ -8,7 +8,7 @@ module Solargraph
8
8
  '<or>'
9
9
  end
10
10
 
11
- # @param type [String]
11
+ # @param links [::Array<Link>]
12
12
  def initialize links
13
13
  @links = links
14
14
  end
@@ -7,11 +7,11 @@ module Solargraph
7
7
  # @return [String]
8
8
  attr_reader :word
9
9
 
10
- # @return [Array<Chain>]
10
+ # @return [::Array<Chain>]
11
11
  attr_reader :arguments
12
12
 
13
13
  # @param word [String]
14
- # @param arguments [Array<Chain>]
14
+ # @param arguments [::Array<Chain>]
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
@@ -20,7 +20,7 @@ module Solargraph
20
20
 
21
21
  # @param api_map [ApiMap]
22
22
  # @param name_pin [Pin::Base]
23
- # @param locals [Array<Pin::Base>]
23
+ # @param locals [::Array<Pin::Base>]
24
24
  def resolve api_map, name_pin, locals
25
25
  return super_pins(api_map, name_pin)
26
26
  end
@@ -19,23 +19,30 @@ module Solargraph
19
19
  autoload :GlobalVariable, 'solargraph/source/chain/global_variable'
20
20
  autoload :Literal, 'solargraph/source/chain/literal'
21
21
  autoload :Head, 'solargraph/source/chain/head'
22
+ autoload :If, 'solargraph/source/chain/if'
22
23
  autoload :Or, 'solargraph/source/chain/or'
23
24
  autoload :BlockVariable, 'solargraph/source/chain/block_variable'
25
+ autoload :BlockSymbol, 'solargraph/source/chain/block_symbol'
24
26
  autoload :ZSuper, 'solargraph/source/chain/z_super'
25
27
  autoload :Hash, 'solargraph/source/chain/hash'
28
+ autoload :Array, 'solargraph/source/chain/array'
26
29
 
27
30
  @@inference_stack = []
28
31
  @@inference_depth = 0
32
+ @@inference_invalidation_key = nil
33
+ @@inference_cache = {}
29
34
 
30
35
  UNDEFINED_CALL = Chain::Call.new('<undefined>')
31
36
  UNDEFINED_CONSTANT = Chain::Constant.new('<undefined>')
32
37
 
33
- # @return [Array<Source::Chain::Link>]
38
+ # @return [::Array<Source::Chain::Link>]
34
39
  attr_reader :links
35
40
 
36
41
  attr_reader :node
37
42
 
38
- # @param links [Array<Chain::Link>]
43
+ # @param node [Parser::AST::Node, nil]
44
+ # @param links [::Array<Chain::Link>]
45
+ # @param splat [Boolean]
39
46
  def initialize links, node = nil, splat = false
40
47
  @links = links.clone
41
48
  @links.push UNDEFINED_CALL if @links.empty?
@@ -56,28 +63,51 @@ module Solargraph
56
63
 
57
64
  # @param api_map [ApiMap]
58
65
  # @param name_pin [Pin::Base]
59
- # @param locals [Array<Pin::Base>]
60
- # @return [Array<Pin::Base>]
66
+ # @param locals [::Enumerable<Pin::LocalVariable>]
67
+ #
68
+ # @return [::Array<Pin::Base>]
61
69
  def define api_map, name_pin, locals
62
70
  return [] if undefined?
63
71
  working_pin = name_pin
64
72
  links[0..-2].each do |link|
65
73
  pins = link.resolve(api_map, working_pin, locals)
66
- type = infer_first_defined(pins, working_pin, api_map)
74
+ type = infer_first_defined(pins, working_pin, api_map, locals)
67
75
  return [] if type.undefined?
68
76
  working_pin = Pin::ProxyType.anonymous(type)
69
77
  end
70
- links.last.last_context = working_pin
78
+ links.last.last_context = name_pin
71
79
  links.last.resolve(api_map, working_pin, locals)
72
80
  end
73
81
 
74
82
  # @param api_map [ApiMap]
75
83
  # @param name_pin [Pin::Base]
76
- # @param locals [Array<Pin::Base>]
84
+ # @param locals [::Enumerable<Pin::LocalVariable>]
77
85
  # @return [ComplexType]
86
+ # @sg-ignore
78
87
  def infer api_map, name_pin, locals
88
+ out = nil
89
+ cached = @@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] unless node.nil?
90
+ return cached if cached && @@inference_invalidation_key == api_map.hash
91
+ out = infer_uncached api_map, name_pin, locals
92
+ if @@inference_invalidation_key != api_map.hash
93
+ @@inference_cache = {}
94
+ @@inference_invalidation_key = api_map.hash
95
+ end
96
+ @@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] = out unless node.nil?
97
+ out
98
+ end
99
+
100
+ # @param api_map [ApiMap]
101
+ # @param name_pin [Pin::Base]
102
+ # @param locals [::Enumerable<Pin::LocalVariable>]
103
+ # @return [ComplexType]
104
+ def infer_uncached api_map, name_pin, locals
105
+ from_here = base.infer(api_map, name_pin, locals) unless links.length == 1
106
+ if from_here
107
+ name_pin = name_pin.proxy(from_here)
108
+ end
79
109
  pins = define(api_map, name_pin, locals)
80
- type = infer_first_defined(pins, links.last.last_context, api_map)
110
+ type = infer_first_defined(pins, links.last.last_context, api_map, locals)
81
111
  maybe_nil(type)
82
112
  end
83
113
 
@@ -109,29 +139,46 @@ module Solargraph
109
139
 
110
140
  private
111
141
 
112
- # @param pins [Array<Pin::Base>]
142
+ # @param pins [::Array<Pin::Base>]
143
+ # @param context [Pin::Base]
113
144
  # @param api_map [ApiMap]
145
+ # @param locals [::Enumerable<Pin::LocalVariable>]
114
146
  # @return [ComplexType]
115
- def infer_first_defined pins, context, api_map
147
+ def infer_first_defined pins, context, api_map, locals
116
148
  possibles = []
149
+ # @todo this param tag shouldn't be needed to probe the type
150
+ # @todo ...but given it is needed, typecheck should complain that it is needed
151
+ # @param pin [Pin::Base]
117
152
  pins.each do |pin|
118
153
  # Avoid infinite recursion
119
154
  next if @@inference_stack.include?(pin.identity)
155
+
120
156
  @@inference_stack.push pin.identity
121
157
  type = pin.typify(api_map)
122
158
  @@inference_stack.pop
123
159
  if type.defined?
124
- possibles.push type
125
- break if pin.is_a?(Pin::Method)
160
+ if type.generic?
161
+ # @todo even at strong, no typechecking complaint
162
+ # happens when a [Pin::Base,nil] is passed into a method
163
+ # that accepts only [Pin::Namespace] as an argument
164
+ type = type.resolve_generics(pin.closure, context.return_type)
165
+ end
166
+ if type.defined?
167
+ possibles.push type
168
+ break if pin.is_a?(Pin::Method)
169
+ end
126
170
  end
127
171
  end
128
172
  if possibles.empty?
129
173
  # Limit method inference recursion
130
174
  return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
175
+
131
176
  @@inference_depth += 1
177
+ # @param pin [Pin::Base]
132
178
  pins.each do |pin|
133
179
  # Avoid infinite recursion
134
180
  next if @@inference_stack.include?(pin.identity)
181
+
135
182
  @@inference_stack.push pin.identity
136
183
  type = pin.probe(api_map)
137
184
  @@inference_stack.pop
@@ -143,17 +190,20 @@ module Solargraph
143
190
  @@inference_depth -= 1
144
191
  end
145
192
  return ComplexType::UNDEFINED if possibles.empty?
193
+
146
194
  type = if possibles.length > 1
147
195
  sorted = possibles.map { |t| t.rooted? ? "::#{t}" : t.to_s }.sort { |a, _| a == 'nil' ? 1 : 0 }
148
196
  ComplexType.parse(*sorted)
149
197
  else
150
- possibles.first
198
+ ComplexType.parse(possibles.map(&:to_s).join(', '))
151
199
  end
152
200
  return type if context.nil? || context.return_type.undefined?
153
- type.self_to(context.return_type.namespace)
201
+
202
+ type.self_to(context.return_type.tag)
154
203
  end
155
204
 
156
205
  # @param type [ComplexType]
206
+ # @return [ComplexType]
157
207
  def maybe_nil type
158
208
  return type if type.undefined? || type.void? || type.nullable?
159
209
  return type unless nullable?
@@ -69,6 +69,9 @@ module Solargraph
69
69
 
70
70
  private
71
71
 
72
+ # @param text [String]
73
+ # @param insert [String]
74
+ # @return [String]
72
75
  def commit text, insert
73
76
  start_offset = Position.to_offset(text, range.start)
74
77
  end_offset = Position.to_offset(text, range.ending)
@@ -115,6 +115,7 @@ module Solargraph
115
115
  end
116
116
  alias receiver recipient
117
117
 
118
+ # @return [AST::Node]
118
119
  def node
119
120
  @node ||= source.node_at(position.line, position.column)
120
121
  end
@@ -135,6 +136,7 @@ module Solargraph
135
136
  end
136
137
  end
137
138
 
139
+ # @return [Parser::AST::Node, nil]
138
140
  def recipient_node
139
141
  @recipient_node ||= Solargraph::Parser::NodeMethods.find_recipient_node(self)
140
142
  end
@@ -14,10 +14,10 @@ module Solargraph
14
14
 
15
15
  class << self
16
16
  # @param source [Source]
17
- # @param position [Position]
17
+ # @param position [Position, Array(Integer, Integer)]
18
18
  # @return [Source::Chain]
19
19
  def chain source, position
20
- new(source, position).chain
20
+ new(source, Solargraph::Position.normalize(position)).chain
21
21
  end
22
22
  end
23
23
 
@@ -41,12 +41,12 @@ module Solargraph
41
41
  parent = nil
42
42
  if !source.repaired? && source.parsed? && source.synchronized?
43
43
  tree = source.tree_at(position.line, position.column)
44
- # node, parent = source.tree_at(position.line, position.column)[0..2]
45
- tree.shift while tree.length > 1 && tree.first.type == :SCOPE
46
44
  node, parent = tree[0..2]
47
45
  elsif source.parsed? && source.repaired? && end_of_phrase == '.'
48
46
  node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2]
49
47
  node = Parser.parse(fixed_phrase) if node.nil?
48
+ elsif source.repaired?
49
+ node = Parser.parse(fixed_phrase)
50
50
  else
51
51
  node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2] unless source.error_ranges.any?{|r| r.nil? || r.include?(fixed_position)}
52
52
  # Exception for positions that chain literal nodes in unsynchronized sources
@@ -58,7 +58,7 @@ module Solargraph
58
58
  end
59
59
  return Chain.new([Chain::UNDEFINED_CALL]) if node.nil? || (node.type == :sym && !phrase.start_with?(':'))
60
60
  # chain = NodeChainer.chain(node, source.filename, parent && parent.type == :block)
61
- chain = Parser.chain(node, source.filename, parent && [:ITER, :block].include?(parent.type))
61
+ chain = Parser.chain(node, source.filename, parent)
62
62
  if source.repaired? || !source.parsed? || !source.synchronized?
63
63
  if end_of_phrase.strip == '.'
64
64
  chain.links.push Chain::UNDEFINED_CALL
@@ -126,10 +126,13 @@ module Solargraph
126
126
  Position.line_char_to_offset(@source.code, line, column)
127
127
  end
128
128
 
129
+ # @return [Integer]
129
130
  def signature_data
130
131
  @signature_data ||= get_signature_data_at(offset)
131
132
  end
132
133
 
134
+ # @param index [Integer]
135
+ # @return [Integer]
133
136
  def get_signature_data_at index
134
137
  brackets = 0
135
138
  squares = 0