solargraph 0.54.1 → 0.56.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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +2 -0
  3. data/.github/workflows/typecheck.yml +3 -1
  4. data/.gitignore +2 -0
  5. data/CHANGELOG.md +70 -0
  6. data/README.md +13 -3
  7. data/lib/solargraph/api_map/cache.rb +10 -1
  8. data/lib/solargraph/api_map/index.rb +175 -0
  9. data/lib/solargraph/api_map/store.rb +79 -126
  10. data/lib/solargraph/api_map.rb +247 -93
  11. data/lib/solargraph/bench.rb +17 -1
  12. data/lib/solargraph/complex_type/type_methods.rb +13 -1
  13. data/lib/solargraph/complex_type/unique_type.rb +118 -9
  14. data/lib/solargraph/complex_type.rb +48 -18
  15. data/lib/solargraph/convention/base.rb +3 -3
  16. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +60 -0
  17. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +100 -0
  18. data/lib/solargraph/convention/struct_definition.rb +101 -0
  19. data/lib/solargraph/convention.rb +5 -3
  20. data/lib/solargraph/doc_map.rb +274 -56
  21. data/lib/solargraph/equality.rb +33 -0
  22. data/lib/solargraph/gem_pins.rb +53 -37
  23. data/lib/solargraph/language_server/host/message_worker.rb +31 -11
  24. data/lib/solargraph/language_server/host.rb +24 -13
  25. data/lib/solargraph/language_server/message/base.rb +19 -12
  26. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  27. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  28. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  29. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  30. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  31. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -0
  32. data/lib/solargraph/library.rb +13 -11
  33. data/lib/solargraph/location.rb +28 -0
  34. data/lib/solargraph/logging.rb +1 -0
  35. data/lib/solargraph/parser/comment_ripper.rb +12 -6
  36. data/lib/solargraph/parser/flow_sensitive_typing.rb +227 -0
  37. data/lib/solargraph/parser/node_methods.rb +15 -1
  38. data/lib/solargraph/parser/node_processor.rb +3 -1
  39. data/lib/solargraph/parser/parser_gem/class_methods.rb +16 -14
  40. data/lib/solargraph/parser/parser_gem/node_chainer.rb +17 -23
  41. data/lib/solargraph/parser/parser_gem/node_methods.rb +5 -3
  42. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  43. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
  44. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
  45. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +4 -2
  46. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +23 -2
  47. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  48. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  49. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  50. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  51. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +21 -0
  52. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  53. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +4 -3
  54. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +29 -6
  55. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +41 -0
  56. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  57. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
  58. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +28 -16
  59. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +2 -1
  60. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  61. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  62. data/lib/solargraph/parser/parser_gem/node_processors.rb +10 -0
  63. data/lib/solargraph/parser/region.rb +1 -1
  64. data/lib/solargraph/parser.rb +1 -0
  65. data/lib/solargraph/pin/base.rb +326 -43
  66. data/lib/solargraph/pin/base_variable.rb +18 -10
  67. data/lib/solargraph/pin/block.rb +3 -3
  68. data/lib/solargraph/pin/breakable.rb +9 -0
  69. data/lib/solargraph/pin/callable.rb +77 -6
  70. data/lib/solargraph/pin/closure.rb +18 -1
  71. data/lib/solargraph/pin/common.rb +5 -0
  72. data/lib/solargraph/pin/delegated_method.rb +20 -1
  73. data/lib/solargraph/pin/documenting.rb +16 -0
  74. data/lib/solargraph/pin/keyword.rb +7 -2
  75. data/lib/solargraph/pin/local_variable.rb +15 -6
  76. data/lib/solargraph/pin/method.rb +172 -42
  77. data/lib/solargraph/pin/namespace.rb +17 -9
  78. data/lib/solargraph/pin/parameter.rb +61 -11
  79. data/lib/solargraph/pin/proxy_type.rb +12 -6
  80. data/lib/solargraph/pin/reference/override.rb +10 -6
  81. data/lib/solargraph/pin/reference/require.rb +2 -2
  82. data/lib/solargraph/pin/signature.rb +42 -0
  83. data/lib/solargraph/pin/singleton.rb +1 -1
  84. data/lib/solargraph/pin/symbol.rb +3 -2
  85. data/lib/solargraph/pin/until.rb +18 -0
  86. data/lib/solargraph/pin/while.rb +18 -0
  87. data/lib/solargraph/pin.rb +4 -1
  88. data/lib/solargraph/pin_cache.rb +185 -0
  89. data/lib/solargraph/position.rb +16 -0
  90. data/lib/solargraph/range.rb +16 -0
  91. data/lib/solargraph/rbs_map/conversions.rb +199 -66
  92. data/lib/solargraph/rbs_map/core_fills.rb +32 -16
  93. data/lib/solargraph/rbs_map/core_map.rb +34 -11
  94. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  95. data/lib/solargraph/rbs_map.rb +74 -16
  96. data/lib/solargraph/shell.rb +19 -18
  97. data/lib/solargraph/source/chain/array.rb +12 -8
  98. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  99. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  100. data/lib/solargraph/source/chain/call.rb +62 -25
  101. data/lib/solargraph/source/chain/constant.rb +1 -1
  102. data/lib/solargraph/source/chain/hash.rb +9 -3
  103. data/lib/solargraph/source/chain/head.rb +1 -1
  104. data/lib/solargraph/source/chain/if.rb +6 -1
  105. data/lib/solargraph/source/chain/link.rb +19 -5
  106. data/lib/solargraph/source/chain/literal.rb +27 -2
  107. data/lib/solargraph/source/chain/or.rb +1 -1
  108. data/lib/solargraph/source/chain/z_super.rb +1 -1
  109. data/lib/solargraph/source/chain.rb +106 -62
  110. data/lib/solargraph/source/cursor.rb +1 -11
  111. data/lib/solargraph/source/source_chainer.rb +2 -2
  112. data/lib/solargraph/source.rb +2 -1
  113. data/lib/solargraph/source_map/clip.rb +4 -2
  114. data/lib/solargraph/source_map/mapper.rb +9 -5
  115. data/lib/solargraph/source_map.rb +0 -17
  116. data/lib/solargraph/type_checker/checks.rb +4 -0
  117. data/lib/solargraph/type_checker.rb +41 -14
  118. data/lib/solargraph/version.rb +1 -1
  119. data/lib/solargraph/views/_method.erb +10 -10
  120. data/lib/solargraph/views/_namespace.erb +3 -3
  121. data/lib/solargraph/views/document.erb +10 -10
  122. data/lib/solargraph/workspace/config.rb +7 -3
  123. data/lib/solargraph/workspace.rb +16 -6
  124. data/lib/solargraph/yard_map/mapper/to_constant.rb +5 -2
  125. data/lib/solargraph/yard_map/mapper/to_method.rb +55 -15
  126. data/lib/solargraph/yard_map/mapper/to_namespace.rb +5 -2
  127. data/lib/solargraph/yard_map/mapper.rb +5 -3
  128. data/lib/solargraph/yard_map/to_method.rb +4 -2
  129. data/lib/solargraph/yardoc.rb +6 -9
  130. data/lib/solargraph.rb +20 -1
  131. data/rbs/fills/tuple.rbs +150 -0
  132. data/rbs_collection.yaml +19 -0
  133. data/solargraph.gemspec +6 -5
  134. metadata +56 -29
  135. data/lib/solargraph/cache.rb +0 -77
@@ -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
@@ -15,7 +15,7 @@ module Solargraph
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.new(types.uniq))]
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]
@@ -14,10 +14,8 @@ module Solargraph
14
14
  # expression.
15
15
  #
16
16
  class Chain
17
- #
18
- # A chain of constants, variables, and method calls for inferring types of
19
- # values.
20
- #
17
+ include Equality
18
+
21
19
  autoload :Link, 'solargraph/source/chain/link'
22
20
  autoload :Call, 'solargraph/source/chain/call'
23
21
  autoload :QCall, 'solargraph/source/chain/q_call'
@@ -41,7 +39,7 @@ module Solargraph
41
39
  @@inference_invalidation_key = nil
42
40
  @@inference_cache = {}
43
41
 
44
- UNDEFINED_CALL = Chain::Call.new('<undefined>')
42
+ UNDEFINED_CALL = Chain::Call.new('<undefined>', nil)
45
43
  UNDEFINED_CONSTANT = Chain::Constant.new('<undefined>')
46
44
 
47
45
  # @return [::Array<Source::Chain::Link>]
@@ -49,6 +47,11 @@ module Solargraph
49
47
 
50
48
  attr_reader :node
51
49
 
50
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
51
+ protected def equality_fields
52
+ [links, node]
53
+ end
54
+
52
55
  # @param node [Parser::AST::Node, nil]
53
56
  # @param links [::Array<Chain::Link>]
54
57
  # @param splat [Boolean]
@@ -72,16 +75,27 @@ module Solargraph
72
75
 
73
76
  # Determine potential Pins returned by this chain of words
74
77
  #
75
- # @param api_map [ApiMap]
76
- # @param name_pin [Pin::Closure] the surrounding closure pin for
77
- # the statement represented by this chain for type resolution
78
- # and method pin lookup.
78
+ # @param api_map [ApiMap] @param name_pin [Pin::Base] A pin
79
+ # representing the place in which expression is evaluated (e.g.,
80
+ # a Method pin, or a Module or Class pin if not run within a
81
+ # method - both in terms of the closure around the chain, as well
82
+ # as the self type used for any method calls in head position.
83
+ #
84
+ # Requirements for name_pin:
79
85
  #
80
- # For method calls (Chain::Call objects) as the first element
81
- # in the chain, 'name_pin.binder' should return the
82
- # ComplexType representing the LHS / "self type" of the call.
86
+ # * name_pin.context: This should be a type representing the
87
+ # namespace where we can look up non-local variables and
88
+ # method names. If it is a Class<X>, we will look up
89
+ # :class scoped methods/variables.
83
90
  #
84
- # @param locals [::Enumerable<Pin::LocalVariable>] Any local
91
+ # * name_pin.binder: Used for method call lookups only
92
+ # (Chain::Call links). For method calls as the first
93
+ # element in the chain, 'name_pin.binder' should be the
94
+ # same as name_pin.context above. For method calls later
95
+ # in the chain (e.g., 'b' in a.b.c), it should represent
96
+ # 'a'.
97
+ #
98
+ # @param locals [::Array<Pin::LocalVariable>] Any local
85
99
  # variables / method parameters etc visible by the statement
86
100
  #
87
101
  # @return [::Array<Pin::Base>] Pins representing possible return
@@ -98,9 +112,18 @@ module Solargraph
98
112
  working_pin = name_pin
99
113
  links[0..-2].each do |link|
100
114
  pins = link.resolve(api_map, working_pin, locals)
101
- type = infer_first_defined(pins, working_pin, api_map, locals)
102
- return [] if type.undefined?
103
- working_pin = Pin::ProxyType.anonymous(type)
115
+ type = infer_from_definitions(pins, working_pin, api_map, locals)
116
+ if type.undefined?
117
+ logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) => [] - undefined type from #{link.desc}" }
118
+ return []
119
+ end
120
+ # We continue to use the context from the head pin, in case
121
+ # we need it to, for instance, provide context for a block
122
+ # evaluation. However, we use the last link's return type
123
+ # for the binder, as this is chaining off of it, and the
124
+ # binder is now the lhs of the rhs we are evaluating.
125
+ working_pin = Pin::ProxyType.anonymous(name_pin.context, binder: type, closure: name_pin, source: :chain)
126
+ logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) - after processing #{link.desc}, new working_pin=#{working_pin} with binder #{working_pin.binder}" }
104
127
  end
105
128
  links.last.last_context = working_pin
106
129
  links.last.resolve(api_map, working_pin, locals)
@@ -108,30 +131,37 @@ module Solargraph
108
131
 
109
132
  # @param api_map [ApiMap]
110
133
  # @param name_pin [Pin::Base] The pin for the closure in which this code runs
111
- # @param locals [::Enumerable<Pin::LocalVariable>]
134
+ # @param locals [::Array<Pin::LocalVariable>]
112
135
  # @return [ComplexType]
113
136
  # @sg-ignore
114
137
  def infer api_map, name_pin, locals
115
- out = nil
116
- cached = @@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] unless node.nil?
117
- return cached if cached && @@inference_invalidation_key == api_map.hash
118
- out = infer_uncached api_map, name_pin, locals
119
- if @@inference_invalidation_key != api_map.hash
120
- @@inference_cache = {}
138
+ cache_key = [node, node&.location, links, name_pin&.return_type, locals]
139
+ if @@inference_invalidation_key == api_map.hash
140
+ cached = @@inference_cache[cache_key]
141
+ return cached if cached
142
+ else
121
143
  @@inference_invalidation_key = api_map.hash
144
+ @@inference_cache = {}
122
145
  end
123
- @@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] = out unless node.nil?
124
- out
146
+ out = infer_uncached(api_map, name_pin, locals).downcast_to_literal_if_possible
147
+ logger.debug { "Chain#infer() - caching result - cache_key_hash=#{cache_key.hash}, links.map(&:hash)=#{links.map(&:hash)}, links=#{links}, cache_key.map(&:hash) = #{cache_key.map(&:hash)}, cache_key=#{cache_key}" }
148
+ @@inference_cache[cache_key] = out
125
149
  end
126
150
 
127
151
  # @param api_map [ApiMap]
128
152
  # @param name_pin [Pin::Base]
129
- # @param locals [::Enumerable<Pin::LocalVariable>]
153
+ # @param locals [::Array<Pin::LocalVariable>]
130
154
  # @return [ComplexType]
131
155
  def infer_uncached api_map, name_pin, locals
132
156
  pins = define(api_map, name_pin, locals)
133
- type = infer_first_defined(pins, links.last.last_context, api_map, locals)
134
- maybe_nil(type)
157
+ if pins.empty?
158
+ logger.debug { "Chain#infer_uncached(links=#{links.map(&:desc)}, locals=#{locals.map(&:desc)}) => undefined - no pins" }
159
+ return ComplexType::UNDEFINED
160
+ end
161
+ type = infer_from_definitions(pins, links.last.last_context, api_map, locals)
162
+ out = maybe_nil(type)
163
+ logger.debug { "Chain#infer_uncached(links=#{self.links.map(&:desc)}, locals=#{locals.map(&:desc)}, name_pin=#{name_pin}, name_pin.closure=#{name_pin.closure.inspect}, name_pin.binder=#{name_pin.binder}) => #{out.rooted_tags.inspect}" }
164
+ out
135
165
  end
136
166
 
137
167
  # @return [Boolean]
@@ -160,6 +190,18 @@ module Solargraph
160
190
  links.any?(&:nullable?)
161
191
  end
162
192
 
193
+ include Logging
194
+
195
+ def desc
196
+ links.map(&:desc).to_s
197
+ end
198
+
199
+ def to_s
200
+ desc
201
+ end
202
+
203
+ include Logging
204
+
163
205
  private
164
206
 
165
207
  # @param pins [::Array<Pin::Base>]
@@ -167,16 +209,18 @@ module Solargraph
167
209
  # @param api_map [ApiMap]
168
210
  # @param locals [::Enumerable<Pin::LocalVariable>]
169
211
  # @return [ComplexType]
170
- def infer_first_defined pins, context, api_map, locals
171
- possibles = []
212
+ def infer_from_definitions pins, context, api_map, locals
213
+ # @type [::Array<ComplexType>]
214
+ types = []
215
+ unresolved_pins = []
172
216
  # @todo this param tag shouldn't be needed to probe the type
173
217
  # @todo ...but given it is needed, typecheck should complain that it is needed
174
218
  # @param pin [Pin::Base]
175
219
  pins.each do |pin|
176
220
  # Avoid infinite recursion
177
- next if @@inference_stack.include?(pin.identity)
221
+ next if @@inference_stack.include?(pin)
178
222
 
179
- @@inference_stack.push pin.identity
223
+ @@inference_stack.push pin
180
224
  type = pin.typify(api_map)
181
225
  @@inference_stack.pop
182
226
  if type.defined?
@@ -186,41 +230,41 @@ module Solargraph
186
230
  # that accepts only [Pin::Namespace] as an argument
187
231
  type = type.resolve_generics(pin.closure, context.binder)
188
232
  end
189
- if type.defined?
190
- possibles.push type
191
- break if pin.is_a?(Pin::Method)
192
- end
233
+ types << type
234
+ else
235
+ unresolved_pins << pin
193
236
  end
194
237
  end
195
- if possibles.empty?
196
- # Limit method inference recursion
197
- return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
198
-
199
- @@inference_depth += 1
200
- # @param pin [Pin::Base]
201
- pins.each do |pin|
202
- # Avoid infinite recursion
203
- next if @@inference_stack.include?(pin.identity)
204
-
205
- @@inference_stack.push pin.identity
206
- type = pin.probe(api_map)
207
- @@inference_stack.pop
208
- if type.defined?
209
- possibles.push type
210
- break if pin.is_a?(Pin::Method)
211
- end
212
- end
213
- @@inference_depth -= 1
238
+
239
+ # Limit method inference recursion
240
+ if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
241
+ return ComplexType::UNDEFINED
214
242
  end
215
- return ComplexType::UNDEFINED if possibles.empty?
216
243
 
217
- type = if possibles.length > 1
218
- # Move nil to the end by convention
219
- sorted = possibles.sort { |a, _| a.tag == 'nil' ? 1 : 0 }
220
- ComplexType.new(sorted.uniq)
221
- else
222
- ComplexType.new(possibles)
244
+ @@inference_depth += 1
245
+ # @param pin [Pin::Base]
246
+ unresolved_pins.each do |pin|
247
+ # Avoid infinite recursion
248
+ if @@inference_stack.include?(pin.identity)
249
+ next
250
+ end
251
+
252
+ @@inference_stack.push(pin.identity)
253
+ type = pin.probe(api_map)
254
+ @@inference_stack.pop
255
+ types.push type if type
223
256
  end
257
+ @@inference_depth -= 1
258
+
259
+ type = if types.empty?
260
+ ComplexType::UNDEFINED
261
+ elsif types.length > 1
262
+ # Move nil to the end by convention
263
+ sorted = types.flat_map(&:items).sort { |a, _| a.tag == 'nil' ? 1 : 0 }
264
+ ComplexType.new(sorted.uniq)
265
+ else
266
+ ComplexType.new(types)
267
+ end
224
268
  return type if context.nil? || context.return_type.undefined?
225
269
 
226
270
  type.self_to_type(context.return_type)
@@ -35,6 +35,7 @@ module Solargraph
35
35
  # The part of the word before the current position. Given the text
36
36
  # `foo.bar`, the start_of_word at position(0, 6) is `ba`.
37
37
  #
38
+ # @sg-ignore Improve resolution of String#match below
38
39
  # @return [String]
39
40
  def start_of_word
40
41
  @start_of_word ||= begin
@@ -103,17 +104,6 @@ module Solargraph
103
104
  @string ||= source.string_at?(position)
104
105
  end
105
106
 
106
-
107
- # True if the cursor's chain is an assignment to a variable.
108
- #
109
- # When the chain is an assignment, `Cursor#word` will contain the
110
- # variable name.
111
- #
112
- # @return [Boolean]
113
- def assign?
114
- [:lvasgn, :ivasgn, :gvasgn, :cvasgn].include? chain&.node&.type
115
- end
116
-
117
107
  # Get a cursor pointing to the method that receives the current statement
118
108
  # as an argument.
119
109
  #
@@ -32,8 +32,8 @@ module Solargraph
32
32
  # @return [Source::Chain]
33
33
  def chain
34
34
  # Special handling for files that end with an integer and a period
35
- return Chain.new([Chain::Literal.new('Integer'), Chain::UNDEFINED_CALL]) if phrase =~ /^[0-9]+\.$/
36
- return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
35
+ return Chain.new([Chain::Literal.new('Integer', Integer(phrase[0..-2])), Chain::UNDEFINED_CALL]) if phrase =~ /^[0-9]+\.$/
36
+ return Chain.new([Chain::Literal.new('Symbol', phrase[1..].to_sym)]) if phrase.start_with?(':') && !phrase.start_with?('::')
37
37
  return SourceChainer.chain(source, Position.new(position.line, position.character + 1)) if end_of_phrase.strip == '::' && source.code[Position.to_offset(source.code, position)].to_s.match?(/[a-z]/i)
38
38
  begin
39
39
  return Chain.new([]) if phrase.end_with?('..')
@@ -307,7 +307,7 @@ module Solargraph
307
307
 
308
308
  # A hash of line numbers and their associated comments.
309
309
  #
310
- # @return [Hash{Integer => Array<String>}]
310
+ # @return [Hash{Integer => Array<String>, nil}]
311
311
  def stringified_comments
312
312
  @stringified_comments ||= {}
313
313
  end
@@ -375,6 +375,7 @@ module Solargraph
375
375
 
376
376
  protected
377
377
 
378
+ # @return [Array<Change>]
378
379
  def changes
379
380
  @changes ||= []
380
381
  end
@@ -11,7 +11,9 @@ module Solargraph
11
11
  def initialize api_map, cursor
12
12
  @api_map = api_map
13
13
  @cursor = cursor
14
- block.rebind(api_map) if block.is_a?(Pin::Block)
14
+ block_pin = block
15
+ block_pin.rebind(api_map) if block_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(block_pin.receiver).contain?(cursor.range.start)
16
+ @in_block = nil
15
17
  end
16
18
 
17
19
  # @return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor's position
@@ -40,7 +42,7 @@ module Solargraph
40
42
  end
41
43
  end
42
44
 
43
- # @return [Array<Pin::Base>]
45
+ # @return [Array<Pin::Method>]
44
46
  def signify
45
47
  return [] unless cursor.argument?
46
48
  chain = Parser.chain(cursor.recipient_node, cursor.filename)
@@ -41,7 +41,7 @@ module Solargraph
41
41
  s = Position.new(0, 0)
42
42
  e = Position.from_offset(code, code.length)
43
43
  location = Location.new(filename, Range.new(s, e))
44
- [[Pin::Namespace.new(location: location, name: '')], []]
44
+ [[Pin::Namespace.new(location: location, name: '', source: :source_map)], []]
45
45
  end
46
46
 
47
47
  class << self
@@ -55,6 +55,7 @@ module Solargraph
55
55
 
56
56
  # @return [Array<Solargraph::Pin::Base>]
57
57
  def pins
58
+ # @type [Array<Solargraph::Pin::Base>]
58
59
  @pins ||= []
59
60
  end
60
61
 
@@ -140,7 +141,8 @@ module Solargraph
140
141
  scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
141
142
  visibility: :public,
142
143
  explicit: false,
143
- attribute: true
144
+ attribute: true,
145
+ source: :source_map
144
146
  )
145
147
  end
146
148
  if t.nil? || t.include?('w')
@@ -151,10 +153,11 @@ module Solargraph
151
153
  comments: docstring.all.to_s,
152
154
  scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
153
155
  visibility: :public,
154
- attribute: true
156
+ attribute: true,
157
+ source: :source_map
155
158
  )
156
159
  pins.push method_pin
157
- method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
160
+ method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last, source: :source_map)
158
161
  if pins.last.return_type.defined?
159
162
  pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
160
163
  end
@@ -205,7 +208,8 @@ module Solargraph
205
208
  namespace = closure_at(source_position) || Pin::ROOT_PIN
206
209
  namespace.domains.concat directive.tag.types unless directive.tag.types.nil?
207
210
  when 'override'
208
- pins.push Pin::Reference::Override.new(location, directive.tag.name, docstring.tags)
211
+ pins.push Pin::Reference::Override.new(location, directive.tag.name, docstring.tags,
212
+ source: :source_map)
209
213
  when 'macro'
210
214
  # @todo Handle macros
211
215
  end
@@ -118,23 +118,6 @@ module Solargraph
118
118
  _locate_pin line, character, Pin::Namespace, Pin::Method, Pin::Block
119
119
  end
120
120
 
121
- # @todo Candidate for deprecation
122
- #
123
- # @param other_map [SourceMap]
124
- # @return [Boolean]
125
- def try_merge! other_map
126
- return false if pins.length != other_map.pins.length || locals.length != other_map.locals.length || requires.map(&:name).uniq.sort != other_map.requires.map(&:name).uniq.sort
127
-
128
- pins.each_index do |i|
129
- return false unless pins[i].try_merge!(other_map.pins[i])
130
- end
131
- locals.each_index do |i|
132
- return false unless locals[i].try_merge!(other_map.locals[i])
133
- end
134
- @source = other_map.source
135
- true
136
- end
137
-
138
121
  # @param name [String]
139
122
  # @return [Array<Location>]
140
123
  def references name
@@ -50,6 +50,8 @@ module Solargraph
50
50
  # @param inferred [ComplexType]
51
51
  # @return [Boolean]
52
52
  def any_types_match? api_map, expected, inferred
53
+ expected = expected.downcast_to_literal_if_possible
54
+ inferred = inferred.downcast_to_literal_if_possible
53
55
  return duck_types_match?(api_map, expected, inferred) if expected.duck_type?
54
56
  # walk through the union expected type and see if any members
55
57
  # of the union match the inferred type
@@ -71,6 +73,8 @@ module Solargraph
71
73
  # @param expected [ComplexType]
72
74
  # @return [Boolean]
73
75
  def all_types_match? api_map, inferred, expected
76
+ expected = expected.downcast_to_literal_if_possible
77
+ inferred = inferred.downcast_to_literal_if_possible
74
78
  return duck_types_match?(api_map, expected, inferred) if expected.duck_type?
75
79
  inferred.each do |inf|
76
80
  next if inf.duck_type?
@@ -29,6 +29,7 @@ module Solargraph
29
29
  # @todo Smarter directory resolution
30
30
  @api_map = api_map || Solargraph::ApiMap.load(File.dirname(filename))
31
31
  @rules = Rules.new(level)
32
+ # @type [Array<Range>]
32
33
  @marked_ranges = []
33
34
  end
34
35
 
@@ -413,7 +414,7 @@ module Solargraph
413
414
  # @param locals [Array<Pin::LocalVariable>]
414
415
  # @param location [Location]
415
416
  # @param pin [Pin::Method]
416
- # @param params [Hash{String => [nil, Hash]}]
417
+ # @param params [Hash{String => Hash{Symbol => String, Solargraph::ComplexType}}]
417
418
  # @param idx [Integer]
418
419
  #
419
420
  # @return [Array<Problem>]
@@ -467,13 +468,24 @@ module Solargraph
467
468
  end
468
469
 
469
470
  # @param pin [Pin::Method]
470
- # @return [Hash{String => Hash{Symbol => BaseObject}}]
471
+ # @return [Hash{String => Hash{Symbol => String, ComplexType}}]
471
472
  def param_hash(pin)
472
- tags = pin.docstring.tags(:param)
473
- return {} if tags.empty?
473
+ # @type [Hash{String => Hash{Symbol => String, ComplexType}}]
474
474
  result = {}
475
+ pin.parameters.each do |param|
476
+ type = param.typify(api_map)
477
+ next if type.nil? || type.undefined?
478
+ result[param.name.to_s] = {
479
+ tagged: type.tags,
480
+ qualified: type
481
+ }
482
+ end
483
+ # see if we have additional tags to pay attention to from YARD -
484
+ # e.g., kwargs in a **restkwargs splat
485
+ tags = pin.docstring.tags(:param)
475
486
  tags.each do |tag|
476
- next if tag.types.nil? || tag.types.empty?
487
+ next if result.key? tag.name.to_s
488
+ next if tag.types.nil?
477
489
  result[tag.name.to_s] = {
478
490
  tagged: tag.types.join(', '),
479
491
  qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, pin.full_context.namespace)
@@ -483,15 +495,29 @@ module Solargraph
483
495
  end
484
496
 
485
497
  # @param pins [Array<Pin::Method>]
486
- # @return [Hash{String => Hash{Symbol => BasicObject}}]
498
+ # @return [Hash{String => Hash{Symbol => String, ComplexType}}]
487
499
  def first_param_hash(pins)
488
- pins.each do |pin|
500
+ return {} if pins.empty?
501
+ first_pin_type = pins.first.typify(api_map)
502
+ first_pin = pins.first.proxy first_pin_type
503
+ param_names = first_pin.parameter_names
504
+ results = param_hash(first_pin)
505
+ pins[1..].each do |pin|
489
506
  # @todo this assignment from parametric use of Hash should not lose its generic
490
507
  # @type [Hash{String => Hash{Symbol => BasicObject}}]
491
- result = param_hash(pin)
492
- return result unless result.empty?
508
+
509
+ # documentation of types in superclasses should fail back to
510
+ # subclasses if the subclass hasn't documented something
511
+ superclass_results = param_hash(pin)
512
+ superclass_results.each do |param_name, details|
513
+ next unless param_names.include?(param_name)
514
+
515
+ results[param_name] ||= {}
516
+ results[param_name][:tagged] ||= details[:tagged]
517
+ results[param_name][:qualified] ||= details[:qualified]
518
+ end
493
519
  end
494
- {}
520
+ results
495
521
  end
496
522
 
497
523
  # @param pin [Pin::Base]
@@ -512,7 +538,7 @@ module Solargraph
512
538
  !internal? pin
513
539
  end
514
540
 
515
- # @param pin [Pin::Base]
541
+ # @param pin [Pin::BaseVariable]
516
542
  def declared_externally? pin
517
543
  return true if pin.assignment.nil?
518
544
  chain = Solargraph::Parser.chain(pin.assignment, filename)
@@ -562,7 +588,7 @@ module Solargraph
562
588
  return [] unless pin.explicit?
563
589
  return [] if parameters.empty? && arguments.empty?
564
590
  return [] if pin.anon_splat?
565
- unchecked = arguments.clone
591
+ unchecked = arguments.dup # creates copy of and unthaws array
566
592
  add_params = 0
567
593
  if unchecked.empty? && parameters.any? { |param| param.decl == :kwarg }
568
594
  return [Problem.new(location, "Missing keyword arguments to #{pin.path}")]
@@ -584,7 +610,8 @@ module Solargraph
584
610
  kwargs.delete param.name.to_sym
585
611
  settled_kwargs += 1
586
612
  elsif param.decl == :kwarg
587
- return [] if arguments.last.links.last.is_a?(Solargraph::Source::Chain::Hash) && arguments.last.links.last.splatted?
613
+ last_arg_last_link = arguments.last.links.last
614
+ return [] if last_arg_last_link.is_a?(Solargraph::Source::Chain::Hash) && last_arg_last_link.splatted?
588
615
  return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
589
616
  end
590
617
  end
@@ -638,7 +665,7 @@ module Solargraph
638
665
  (pin.closure && pin.closure.docstring.has_tag?('abstract'))
639
666
  end
640
667
 
641
- # @param pin [Pin::Base]
668
+ # @param pin [Pin::Method]
642
669
  # @return [Array<Source::Chain>]
643
670
  def fake_args_for(pin)
644
671
  args = []
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.54.1'
4
+ VERSION = '0.56.0'
5
5
  end