solargraph 0.50.0 → 0.53.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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +40 -0
  3. data/.github/workflows/rspec.yml +4 -8
  4. data/.github/workflows/typecheck.yml +34 -0
  5. data/.yardopts +2 -2
  6. data/CHANGELOG.md +81 -3
  7. data/README.md +13 -16
  8. data/SPONSORS.md +2 -9
  9. data/lib/solargraph/api_map/cache.rb +60 -20
  10. data/lib/solargraph/api_map/store.rb +47 -11
  11. data/lib/solargraph/api_map.rb +161 -95
  12. data/lib/solargraph/bench.rb +2 -2
  13. data/lib/solargraph/cache.rb +30 -6
  14. data/lib/solargraph/complex_type/type_methods.rb +54 -9
  15. data/lib/solargraph/complex_type/unique_type.rb +154 -57
  16. data/lib/solargraph/complex_type.rb +91 -17
  17. data/lib/solargraph/convention.rb +0 -3
  18. data/lib/solargraph/converters/dd.rb +5 -0
  19. data/lib/solargraph/converters/dl.rb +3 -0
  20. data/lib/solargraph/converters/dt.rb +3 -0
  21. data/lib/solargraph/diagnostics/rubocop.rb +8 -7
  22. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
  23. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  24. data/lib/solargraph/diagnostics.rb +2 -2
  25. data/lib/solargraph/doc_map.rb +146 -0
  26. data/lib/solargraph/gem_pins.rb +64 -0
  27. data/lib/solargraph/language_server/host/cataloger.rb +1 -0
  28. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  29. data/lib/solargraph/language_server/host/dispatch.rb +10 -4
  30. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  31. data/lib/solargraph/language_server/host/sources.rb +7 -4
  32. data/lib/solargraph/language_server/host.rb +26 -7
  33. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  34. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  35. data/lib/solargraph/language_server/message/initialize.rb +11 -0
  36. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  37. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  38. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -4
  39. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  40. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  41. data/lib/solargraph/language_server/message/text_document.rb +1 -1
  42. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  43. data/lib/solargraph/language_server/message.rb +1 -0
  44. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  45. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  46. data/lib/solargraph/library.rb +86 -16
  47. data/lib/solargraph/location.rb +1 -0
  48. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  49. data/lib/solargraph/parser/node_methods.rb +47 -7
  50. data/lib/solargraph/parser/node_processor/base.rb +9 -0
  51. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -5
  52. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  53. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
  54. data/lib/solargraph/parser/parser_gem/node_methods.rb +499 -0
  55. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  56. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
  57. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  58. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  59. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
  60. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  61. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +1 -1
  62. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  63. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  65. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  67. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  68. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  69. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +2 -2
  71. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -0
  73. data/lib/solargraph/parser/parser_gem.rb +12 -0
  74. data/lib/solargraph/parser/region.rb +1 -1
  75. data/lib/solargraph/parser/snippet.rb +2 -0
  76. data/lib/solargraph/parser.rb +9 -10
  77. data/lib/solargraph/pin/base.rb +64 -9
  78. data/lib/solargraph/pin/base_variable.rb +6 -2
  79. data/lib/solargraph/pin/block.rb +19 -9
  80. data/lib/solargraph/pin/closure.rb +17 -2
  81. data/lib/solargraph/pin/common.rb +7 -3
  82. data/lib/solargraph/pin/conversions.rb +33 -3
  83. data/lib/solargraph/pin/delegated_method.rb +97 -0
  84. data/lib/solargraph/pin/documenting.rb +25 -34
  85. data/lib/solargraph/pin/instance_variable.rb +4 -0
  86. data/lib/solargraph/pin/local_variable.rb +13 -1
  87. data/lib/solargraph/pin/method.rb +182 -18
  88. data/lib/solargraph/pin/namespace.rb +18 -5
  89. data/lib/solargraph/pin/parameter.rb +44 -14
  90. data/lib/solargraph/pin/reference/override.rb +2 -2
  91. data/lib/solargraph/pin/reference.rb +8 -0
  92. data/lib/solargraph/pin/search.rb +4 -4
  93. data/lib/solargraph/pin/signature.rb +123 -3
  94. data/lib/solargraph/pin.rb +1 -1
  95. data/lib/solargraph/range.rb +4 -6
  96. data/lib/solargraph/rbs_map/conversions.rb +294 -50
  97. data/lib/solargraph/rbs_map/core_fills.rb +7 -24
  98. data/lib/solargraph/rbs_map/core_map.rb +3 -2
  99. data/lib/solargraph/rbs_map/core_signs.rb +2 -0
  100. data/lib/solargraph/rbs_map/stdlib_map.rb +2 -5
  101. data/lib/solargraph/rbs_map.rb +20 -11
  102. data/lib/solargraph/shell.rb +62 -59
  103. data/lib/solargraph/source/chain/array.rb +32 -0
  104. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  105. data/lib/solargraph/source/chain/call.rb +99 -46
  106. data/lib/solargraph/source/chain/constant.rb +15 -1
  107. data/lib/solargraph/source/chain/if.rb +23 -0
  108. data/lib/solargraph/source/chain/link.rb +8 -2
  109. data/lib/solargraph/source/chain/or.rb +1 -1
  110. data/lib/solargraph/source/chain/z_super.rb +3 -3
  111. data/lib/solargraph/source/chain.rb +29 -14
  112. data/lib/solargraph/source/change.rb +3 -0
  113. data/lib/solargraph/source/cursor.rb +2 -0
  114. data/lib/solargraph/source/source_chainer.rb +8 -5
  115. data/lib/solargraph/source.rb +18 -19
  116. data/lib/solargraph/source_map/clip.rb +25 -23
  117. data/lib/solargraph/source_map/mapper.rb +12 -1
  118. data/lib/solargraph/source_map.rb +30 -7
  119. data/lib/solargraph/type_checker/checks.rb +10 -2
  120. data/lib/solargraph/type_checker.rb +123 -45
  121. data/lib/solargraph/version.rb +1 -1
  122. data/lib/solargraph/workspace/config.rb +14 -11
  123. data/lib/solargraph/workspace.rb +3 -2
  124. data/lib/solargraph/yard_map/cache.rb +6 -0
  125. data/lib/solargraph/yard_map/helpers.rb +1 -1
  126. data/lib/solargraph/yard_map/mapper/to_method.rb +11 -1
  127. data/lib/solargraph/yard_map/mapper.rb +1 -1
  128. data/lib/solargraph/yard_map/to_method.rb +11 -4
  129. data/lib/solargraph/yard_map.rb +1 -284
  130. data/lib/solargraph/yard_tags.rb +20 -0
  131. data/lib/solargraph/yardoc.rb +52 -0
  132. data/lib/solargraph.rb +6 -4
  133. data/solargraph.gemspec +11 -5
  134. metadata +131 -75
  135. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  136. data/lib/solargraph/convention/rspec.rb +0 -30
  137. data/lib/solargraph/documentor.rb +0 -76
  138. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  139. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  140. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
  141. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  142. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +0 -23
  143. data/lib/solargraph/parser/legacy/node_processors/gvasgn_node.rb +0 -23
  144. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
  145. data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
  146. data/lib/solargraph/parser/legacy.rb +0 -12
  147. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -149
  148. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  149. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
  150. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  151. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  152. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
  153. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
  154. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
  155. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  156. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  157. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  158. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  159. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  160. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  161. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  162. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
  163. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
  164. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  165. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
  166. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
  167. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
  168. data/lib/solargraph/parser/rubyvm.rb +0 -40
  169. data/lib/yard-solargraph.rb +0 -33
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'yard'
4
- require 'yard-solargraph'
5
- require 'set'
4
+ require 'solargraph/yard_tags'
6
5
 
7
6
  module Solargraph
8
7
  # An index of pins and other ApiMap-related data for a Source.
@@ -18,7 +17,7 @@ module Solargraph
18
17
  # @return [Array<Pin::Base>]
19
18
  attr_reader :pins
20
19
 
21
- # @return [Array<Pin::Base>]
20
+ # @return [Array<Pin::LocalVariable>]
22
21
  attr_reader :locals
23
22
 
24
23
  # @param source [Source]
@@ -30,17 +29,21 @@ module Solargraph
30
29
  @pins = pins
31
30
  @locals = locals
32
31
  environ.merge Convention.for_local(self) unless filename.nil?
32
+ self.convention_pins = environ.pins
33
33
  @pin_class_hash = pins.to_set.classify(&:class).transform_values(&:to_a)
34
34
  @pin_select_cache = {}
35
35
  end
36
36
 
37
+ # @param klass [Class]
38
+ # @return [Array<Pin::Base>]
37
39
  def pins_by_class klass
38
40
  @pin_select_cache[klass] ||= @pin_class_hash.select { |key, _| key <= klass }.values.flatten
39
41
  end
40
42
 
43
+ # @return [Set<String>]
41
44
  def rebindable_method_names
42
45
  @rebindable_method_names ||= pins_by_class(Pin::Method)
43
- .select { |pin| pin.comments && pin.comments.include?('@yieldself') }
46
+ .select { |pin| pin.comments && pin.comments.include?('@yieldreceiver') }
44
47
  .map(&:name)
45
48
  .to_set
46
49
  end
@@ -65,11 +68,12 @@ module Solargraph
65
68
  @environ ||= Environ.new
66
69
  end
67
70
 
71
+ # all pins except Solargraph::Pin::Reference::Reference
68
72
  # @return [Array<Pin::Base>]
69
73
  def document_symbols
70
- @document_symbols ||= pins.select { |pin|
74
+ @document_symbols ||= (pins + convention_pins).select do |pin|
71
75
  pin.path && !pin.path.empty?
72
- }
76
+ end
73
77
  end
74
78
 
75
79
  # @param query [String]
@@ -97,10 +101,16 @@ module Solargraph
97
101
  (pins + locals).select { |pin| pin.location == location }
98
102
  end
99
103
 
104
+ # @param line [Integer]
105
+ # @param character [Integer]
106
+ # @return [Pin::Method,Pin::Namespace]
100
107
  def locate_named_path_pin line, character
101
108
  _locate_pin line, character, Pin::Namespace, Pin::Method
102
109
  end
103
110
 
111
+ # @param line [Integer]
112
+ # @param character [Integer]
113
+ # @return [Pin::Namespace,Pin::Method,Pin::Block]
104
114
  def locate_block_pin line, character
105
115
  _locate_pin line, character, Pin::Namespace, Pin::Method, Pin::Block
106
116
  end
@@ -159,10 +169,23 @@ module Solargraph
159
169
 
160
170
  private
161
171
 
172
+ # @return [Array<Pin::Base>]
173
+ def convention_pins
174
+ @convention_pins || []
175
+ end
176
+
177
+ # @param pins [Array<Pin::Base>]
178
+ # @return [Array<Pin::Base>]
179
+ def convention_pins=(pins)
180
+ # unmemoizing the document_symbols in case it was called from any of convnetions
181
+ @document_symbols = nil
182
+ @convention_pins = pins
183
+ end
184
+
162
185
  # @param line [Integer]
163
186
  # @param character [Integer]
164
187
  # @param klasses [Array<Class>]
165
- # @return [Pin::Base]
188
+ # @return [Pin::Base, nil]
166
189
  def _locate_pin line, character, *klasses
167
190
  position = Position.new(line, character)
168
191
  found = nil
@@ -51,8 +51,13 @@ module Solargraph
51
51
  # @return [Boolean]
52
52
  def any_types_match? api_map, expected, inferred
53
53
  return duck_types_match?(api_map, expected, inferred) if expected.duck_type?
54
+ # walk through the union expected type and see if any members
55
+ # of the union match the inferred type
54
56
  expected.each do |exp|
55
57
  next if exp.duck_type?
58
+ # @todo: there should be a level of typechecking where all
59
+ # unique types in the inferred must match one of the
60
+ # expected unique types
56
61
  inferred.each do |inf|
57
62
  # return true if exp == inf || api_map.super_and_sub?(fuzz(inf), fuzz(exp))
58
63
  return true if exp == inf || either_way?(api_map, inf, exp)
@@ -103,9 +108,12 @@ module Solargraph
103
108
  # @param cls2 [ComplexType::UniqueType]
104
109
  # @return [Boolean]
105
110
  def either_way?(api_map, cls1, cls2)
106
- f1 = fuzz(cls1)
107
- f2 = fuzz(cls2)
111
+ # @todo there should be a level of typechecking which uses the
112
+ # full tag with parameters to determine compatibility
113
+ f1 = cls1.name
114
+ f2 = cls2.name
108
115
  api_map.type_include?(f1, f2) || api_map.super_and_sub?(f1, f2) || api_map.super_and_sub?(f2, f1)
116
+ # api_map.type_include?(f1, f2) || api_map.super_and_sub?(f1, f2) || api_map.super_and_sub?(f2, f1)
109
117
  end
110
118
  end
111
119
  end
@@ -22,7 +22,7 @@ module Solargraph
22
22
  attr_reader :api_map
23
23
 
24
24
  # @param filename [String]
25
- # @param api_map [ApiMap]
25
+ # @param api_map [ApiMap, nil]
26
26
  # @param level [Symbol]
27
27
  def initialize filename, api_map: nil, level: :normal
28
28
  @filename = filename
@@ -51,6 +51,7 @@ module Solargraph
51
51
 
52
52
  class << self
53
53
  # @param filename [String]
54
+ # @param level [Symbol]
54
55
  # @return [self]
55
56
  def load filename, level = :normal
56
57
  source = Solargraph::Source.load(filename)
@@ -61,6 +62,7 @@ module Solargraph
61
62
 
62
63
  # @param code [String]
63
64
  # @param filename [String, nil]
65
+ # @param level [Symbol]
64
66
  # @return [self]
65
67
  def load_string code, filename = nil, level = :normal
66
68
  source = Solargraph::Source.load_string(code, filename)
@@ -91,7 +93,12 @@ module Solargraph
91
93
  declared = pin.typify(api_map).self_to(pin.full_context.namespace)
92
94
  if declared.undefined?
93
95
  if pin.return_type.undefined? && rules.require_type_tags?
94
- result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin)
96
+ if pin.attribute?
97
+ inferred = pin.probe(api_map).self_to(pin.full_context.namespace)
98
+ result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin) unless inferred.defined?
99
+ else
100
+ result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin)
101
+ end
95
102
  elsif pin.return_type.defined? && !resolved_constant?(pin)
96
103
  result.push Problem.new(pin.location, "Unresolved return type #{pin.return_type} for #{pin.path}", pin: pin)
97
104
  elsif rules.must_tag_or_infer? && pin.probe(api_map).undefined?
@@ -121,11 +128,16 @@ module Solargraph
121
128
  # @return [Boolean]
122
129
  def resolved_constant? pin
123
130
  return true if pin.typify(api_map).defined?
124
- api_map.get_constants('', *pin.closure.gates)
125
- .select { |p| p.name == pin.return_type.namespace }
126
- .any? { |p| p.infer(api_map).defined? }
131
+ constant_pins = api_map.get_constants('', *pin.closure.gates)
132
+ .select { |p| p.name == pin.return_type.namespace }
133
+ return true if constant_pins.find { |p| p.typify(api_map).defined? }
134
+ # will need to probe when a constant name is assigned to a
135
+ # class/module (alias)
136
+ return true if constant_pins.find { |p| p.probe(api_map).defined? }
137
+ false
127
138
  end
128
139
 
140
+ # @param pin [Pin::Base]
129
141
  def virtual_pin? pin
130
142
  pin.location && source_map.source.comment_at?(pin.location.range.ending)
131
143
  end
@@ -141,12 +153,23 @@ module Solargraph
141
153
  sig.parameters.each do |par|
142
154
  break if par.decl == :restarg || par.decl == :kwrestarg || par.decl == :blockarg
143
155
  unless params[par.name]
144
- result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
156
+ if pin.attribute?
157
+ inferred = pin.probe(api_map).self_to(pin.full_context.namespace)
158
+ if inferred.undefined?
159
+ result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
160
+ end
161
+ else
162
+ result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
163
+ end
145
164
  end
146
165
  end
147
166
  end
148
167
  end
168
+ # @todo Should be able to probe type of name and data here
169
+ # @param name [String]
170
+ # @param data [Hash{Symbol => BasicObject}]
149
171
  params.each_pair do |name, data|
172
+ # @type [ComplexType]
150
173
  type = data[:qualified]
151
174
  if type.undefined?
152
175
  result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}", pin: pin)
@@ -155,6 +178,7 @@ module Solargraph
155
178
  result
156
179
  end
157
180
 
181
+ # @return [Array<Pin::Base>]
158
182
  def ignored_pins
159
183
  @ignored_pins ||= []
160
184
  end
@@ -202,6 +226,7 @@ module Solargraph
202
226
  source_map.pins_by_class(Pin::BaseVariable) + source_map.locals.select { |pin| pin.is_a?(Pin::LocalVariable) }
203
227
  end
204
228
 
229
+ # @return [Array<Problem>]
205
230
  def const_problems
206
231
  return [] unless rules.validate_consts?
207
232
  result = []
@@ -220,6 +245,7 @@ module Solargraph
220
245
  result
221
246
  end
222
247
 
248
+ # @return [Array<Problem>]
223
249
  def call_problems
224
250
  result = []
225
251
  Solargraph::Parser::NodeMethods.call_nodes_from(source_map.source.node).each do |call|
@@ -243,7 +269,7 @@ module Solargraph
243
269
  end
244
270
  closest = found.typify(api_map) if found
245
271
  if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
246
- unless closest.parameterized? || ignored_pins.include?(found)
272
+ unless closest.generic? || ignored_pins.include?(found)
247
273
  result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
248
274
  @marked_ranges.push rng
249
275
  end
@@ -254,12 +280,21 @@ module Solargraph
254
280
  result
255
281
  end
256
282
 
283
+ # @param chain [Solargraph::Source::Chain]
284
+ # @param api_map [Solargraph::ApiMap]
285
+ # @param block_pin [Solargraph::Pin::Base]
286
+ # @param locals [Array<Solargraph::Pin::Base>]
287
+ # @param location [Solargraph::Location]
288
+ # @return [Array<Problem>]
257
289
  def argument_problems_for chain, api_map, block_pin, locals, location
258
290
  result = []
259
291
  base = chain
260
292
  until base.links.length == 1 && base.undefined?
261
293
  pins = base.define(api_map, block_pin, locals)
262
- if pins.first.is_a?(Pin::Method)
294
+
295
+ if pins.first.is_a?(Pin::DelegatedMethod) && !pins.first.resolvable?(api_map)
296
+ # Do nothing, as we can't find the actual method implementation
297
+ elsif pins.first.is_a?(Pin::Method)
263
298
  # @type [Pin::Method]
264
299
  pin = pins.first
265
300
  ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
@@ -271,21 +306,30 @@ module Solargraph
271
306
  result.concat ap
272
307
  break
273
308
  end
274
- break unless rules.validate_calls?
309
+ break if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
310
+
275
311
  params = first_param_hash(pins)
276
312
 
277
313
  all_errors = []
278
314
  pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
279
315
  errors = []
316
+ # @todo these should be able to be probed
317
+ # @param par [Parameter]
318
+ # @param idx [Integer]
280
319
  sig.parameters.each_with_index do |par, idx|
281
320
  argchain = base.links.last.arguments[idx]
282
- if argchain.nil? && par.decl == :arg
283
- errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
284
- next
321
+ if argchain.nil?
322
+ if par.decl == :arg
323
+ errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
324
+ next
325
+ else
326
+ last = base.links.last.arguments.last
327
+ argchain = last if last && [:kwsplat, :hash].include?(last.node.type)
328
+ end
285
329
  end
286
330
  if argchain
287
331
  if par.decl != :arg
288
- errors.concat kwarg_problems_for argchain, api_map, block_pin, locals, location, pin, params, idx
332
+ errors.concat kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
289
333
  next
290
334
  else
291
335
  ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
@@ -317,35 +361,53 @@ module Solargraph
317
361
  result
318
362
  end
319
363
 
320
- def kwarg_problems_for argchain, api_map, block_pin, locals, location, pin, params, first
364
+ # @param sig [Pin::Signature]
365
+ # @param argchain [Source::Chain]
366
+ # @param api_map [ApiMap]
367
+ # @param block_pin [Pin::Block]
368
+ # @param locals [Array<Pin::LocalVariable>]
369
+ # @param location [Location]
370
+ # @param pin [Pin::Method]
371
+ # @param params [Hash{String => [nil, Hash]}]
372
+ # @param idx [Integer]
373
+ #
374
+ # @return [Array<Problem>]
375
+ def kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
321
376
  result = []
322
377
  kwargs = convert_hash(argchain.node)
323
- pin.signatures.first.parameters[first..-1].each_with_index do |par, cur|
324
- idx = first + cur
325
- argchain = kwargs[par.name.to_sym]
326
- if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
327
- result.concat kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
328
- else
329
- if argchain
330
- data = params[par.name]
331
- if data.nil?
332
- # @todo Some level (strong, I guess) should require the param here
333
- else
334
- ptype = data[:qualified]
335
- next if ptype.undefined?
378
+ par = sig.parameters[idx]
379
+ argchain = kwargs[par.name.to_sym]
380
+ if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
381
+ result.concat kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
382
+ else
383
+ if argchain
384
+ data = params[par.name]
385
+ if data.nil?
386
+ # @todo Some level (strong, I guess) should require the param here
387
+ else
388
+ ptype = data[:qualified]
389
+ unless ptype.undefined?
336
390
  argtype = argchain.infer(api_map, block_pin, locals)
337
391
  if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
338
392
  result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
339
393
  end
340
394
  end
341
- elsif par.decl == :kwarg
342
- result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
343
395
  end
396
+ elsif par.decl == :kwarg
397
+ result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
344
398
  end
345
399
  end
346
400
  result
347
401
  end
348
402
 
403
+ # @param api_map [ApiMap]
404
+ # @param block_pin [Pin::Block]
405
+ # @param locals [Array<Pin::LocalVariable>]
406
+ # @param location [Location]
407
+ # @param pin [Pin::Method]
408
+ # @param params [Hash{String => [nil, Hash]}]
409
+ # @param kwargs [Hash{Symbol => Source::Chain}]
410
+ # @return [Array<Problem>]
349
411
  def kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
350
412
  result = []
351
413
  kwargs.each_pair do |pname, argchain|
@@ -359,8 +421,8 @@ module Solargraph
359
421
  result
360
422
  end
361
423
 
362
- # @param [Pin::Method]
363
- # @return [Hash]
424
+ # @param pin [Pin::Method]
425
+ # @return [Hash{String => Hash{Symbol => BaseObject}}]
364
426
  def param_hash(pin)
365
427
  tags = pin.docstring.tags(:param)
366
428
  return {} if tags.empty?
@@ -375,10 +437,12 @@ module Solargraph
375
437
  result
376
438
  end
377
439
 
378
- # @param [Array<Pin::Method>]
379
- # @return [Hash]
440
+ # @param pins [Array<Pin::Method>]
441
+ # @return [Hash{String => Hash{Symbol => BasicObject}}]
380
442
  def first_param_hash(pins)
381
443
  pins.each do |pin|
444
+ # @todo this assignment from parametric use of Hash should not lose its generic
445
+ # @type [Hash{String => Hash{Symbol => BasicObject}]
382
446
  result = param_hash(pin)
383
447
  return result unless result.empty?
384
448
  end
@@ -392,6 +456,7 @@ module Solargraph
392
456
  end
393
457
 
394
458
  # True if the pin is either internal (part of the workspace) or from the core/stdlib
459
+ # @param pin [Pin::Base]
395
460
  def internal_or_core? pin
396
461
  # @todo RBS pins are not necessarily core/stdlib pins
397
462
  internal?(pin) || pin.source == :rbs
@@ -402,6 +467,7 @@ module Solargraph
402
467
  !internal? pin
403
468
  end
404
469
 
470
+ # @param pin [Pin::Base]
405
471
  def declared_externally? pin
406
472
  return true if pin.assignment.nil?
407
473
  chain = Solargraph::Parser.chain(pin.assignment, filename)
@@ -429,6 +495,10 @@ module Solargraph
429
495
  true
430
496
  end
431
497
 
498
+ # @param pin [Pin::Method]
499
+ # @param arguments [Array<Source::Chain>]
500
+ # @param location [Location]
501
+ # @return [Array<Problem>]
432
502
  def arity_problems_for pin, arguments, location
433
503
  results = pin.signatures.map do |sig|
434
504
  r = parameterized_arity_problems_for(pin, sig.parameters, arguments, location)
@@ -438,16 +508,15 @@ module Solargraph
438
508
  results.first
439
509
  end
440
510
 
511
+ # @param pin [Pin::Method]
512
+ # @param parameters [Array<Pin::Parameter>]
513
+ # @param arguments [Array<Source::Chain>]
514
+ # @param location [Location]
515
+ # @return [Array<Problem>]
441
516
  def parameterized_arity_problems_for(pin, parameters, arguments, location)
442
517
  return [] unless pin.explicit?
443
518
  return [] if parameters.empty? && arguments.empty?
444
519
  return [] if pin.anon_splat?
445
- if parameters.empty?
446
- # Functions tagged param_tuple accepts two arguments (e.g., Hash#[]=)
447
- return [] if pin.docstring.tag(:param_tuple) && arguments.length == 2
448
- return [] if arguments.length == 1 && arguments.last.links.last.is_a?(Source::Chain::BlockVariable)
449
- return [Problem.new(location, "Too many arguments to #{pin.path}")]
450
- end
451
520
  unchecked = arguments.clone
452
521
  add_params = 0
453
522
  if unchecked.empty? && parameters.any? { |param| param.decl == :kwarg }
@@ -487,9 +556,6 @@ module Solargraph
487
556
  return [] if parameters.any?(&:rest?)
488
557
  opt = optional_param_count(parameters)
489
558
  return [] if unchecked.length <= req + opt
490
- if unchecked.length == req + opt + 1 && unchecked.last.links.last.is_a?(Source::Chain::BlockVariable)
491
- return []
492
- end
493
559
  if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
494
560
  return []
495
561
  end
@@ -505,20 +571,30 @@ module Solargraph
505
571
  []
506
572
  end
507
573
 
574
+ # @param parameters [Enumerable<Pin::Parameter>]
575
+ # @todo need to use generic types in method to choose correct
576
+ # signature and generate Integer as return type
577
+ # @sg-ignore
578
+ # @return [Integer]
508
579
  def required_param_count(parameters)
509
580
  parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
510
581
  end
511
582
 
583
+ # @param parameters [Enumerable<Pin::Parameter>]
512
584
  # @param pin [Pin::Method]
585
+ # @return [Integer]
513
586
  def optional_param_count(parameters)
514
587
  parameters.select { |p| p.decl == :optarg }.length
515
588
  end
516
589
 
590
+ # @param pin [Pin::Method]
517
591
  def abstract? pin
518
- pin.docstring.has_tag?(:abstract) ||
519
- (pin.closure && pin.closure.docstring.has_tag?(:abstract))
592
+ pin.docstring.has_tag?('abstract') ||
593
+ (pin.closure && pin.closure.docstring.has_tag?('abstract'))
520
594
  end
521
595
 
596
+ # @param pin [Pin::Base]
597
+ # @return [Array<Source::Chain>]
522
598
  def fake_args_for(pin)
523
599
  args = []
524
600
  with_opts = false
@@ -539,10 +615,12 @@ module Solargraph
539
615
  args
540
616
  end
541
617
 
618
+ # @param problems [Array<Problem>]
619
+ # @return [Array<Problem>]
542
620
  def without_ignored problems
543
621
  problems.reject do |problem|
544
622
  node = source_map.source.node_at(problem.location.range.start.line, problem.location.range.start.column)
545
- source_map.source.comments_for(node)&.include?('@sg-ignore')
623
+ node && source_map.source.comments_for(node)&.include?('@sg-ignore')
546
624
  end
547
625
  end
548
626
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.50.0'
4
+ VERSION = '0.53.0'
5
5
  end
@@ -14,12 +14,12 @@ module Solargraph
14
14
  # @return [String]
15
15
  attr_reader :directory
16
16
 
17
- # @return [Hash]
17
+ # @return [Hash{String => BasicObject}]
18
18
  attr_reader :raw_data
19
19
 
20
20
  # @param directory [String]
21
21
  def initialize directory = ''
22
- @directory = directory
22
+ @directory = File.absolute_path(directory)
23
23
  @raw_data = config_data
24
24
  included
25
25
  excluded
@@ -41,8 +41,10 @@ module Solargraph
41
41
  @excluded ||= process_exclusions(@raw_data['exclude'])
42
42
  end
43
43
 
44
+ # @param filename [String]
44
45
  def allow? filename
45
- filename.start_with?(directory) &&
46
+ filename = File.absolute_path(filename, directory)
47
+ filename.start_with?(directory) &&
46
48
  !excluded.include?(filename) &&
47
49
  excluded_directories.none? { |d| filename.start_with?(d) }
48
50
  end
@@ -110,7 +112,7 @@ module Solargraph
110
112
 
111
113
  # @return [String]
112
114
  def global_config_path
113
- ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
115
+ ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
114
116
  File.join(Dir.home, '.config', 'solargraph', 'config.yml')
115
117
  end
116
118
 
@@ -120,7 +122,7 @@ module Solargraph
120
122
  File.join(@directory, '.solargraph.yml')
121
123
  end
122
124
 
123
- # @return [Hash]
125
+ # @return [Hash{String => Array, Hash, Integer}]
124
126
  def config_data
125
127
  workspace_config = read_config(workspace_config_path)
126
128
  global_config = read_config(global_config_path)
@@ -135,15 +137,15 @@ module Solargraph
135
137
 
136
138
  # Read a .solargraph yaml config
137
139
  #
138
- # @param directory [String]
139
- # @return [Hash, nil]
140
+ # @param config_path [String]
141
+ # @return [Hash{String => Array, Hash, Integer}, nil]
140
142
  def read_config config_path = ''
141
143
  return nil if config_path.empty?
142
144
  return nil unless File.file?(config_path)
143
145
  YAML.safe_load(File.read(config_path))
144
146
  end
145
147
 
146
- # @return [Hash]
148
+ # @return [Hash{String => Array, Hash, Integer}]
147
149
  def default_config
148
150
  {
149
151
  'include' => ['**/*.rb'],
@@ -171,7 +173,7 @@ module Solargraph
171
173
  # @return [Array<String>]
172
174
  def process_globs globs
173
175
  result = globs.flat_map do |glob|
174
- Dir[File.join directory, glob]
176
+ Dir[File.absolute_path(glob, directory)]
175
177
  .map{ |f| f.gsub(/\\/, '/') }
176
178
  .select { |f| File.file?(f) }
177
179
  end
@@ -186,7 +188,7 @@ module Solargraph
186
188
  def process_exclusions globs
187
189
  remainder = globs.select do |glob|
188
190
  if glob_is_directory?(glob)
189
- exdir = File.join(directory, glob_to_directory(glob))
191
+ exdir = File.absolute_path(glob_to_directory(glob), directory)
190
192
  included.delete_if { |file| file.start_with?(exdir) }
191
193
  false
192
194
  else
@@ -221,10 +223,11 @@ module Solargraph
221
223
  glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
222
224
  end
223
225
 
226
+ # @return [Array<String>]
224
227
  def excluded_directories
225
228
  @raw_data['exclude']
226
229
  .select { |g| glob_is_directory?(g) }
227
- .map { |g| File.join(directory, glob_to_directory(g)) }
230
+ .map { |g| File.absolute_path(glob_to_directory(g), directory) }
228
231
  end
229
232
  end
230
233
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'open3'
4
- require 'rubygems'
5
4
  require 'json'
6
5
 
7
6
  module Solargraph
@@ -104,7 +103,8 @@ module Solargraph
104
103
  # @return [Boolean]
105
104
  def would_require? path
106
105
  require_paths.each do |rp|
107
- return true if File.exist?(File.join(rp, "#{path}.rb"))
106
+ full = File.join rp, path
107
+ return true if File.exist?(full) or File.exist?(full << ".rb")
108
108
  end
109
109
  false
110
110
  end
@@ -199,6 +199,7 @@ module Solargraph
199
199
  config.require_paths.map{|p| File.join(directory, p)}
200
200
  end
201
201
 
202
+ # @return [void]
202
203
  def require_plugins
203
204
  config.plugins.each do |plugin|
204
205
  begin
@@ -4,13 +4,19 @@ module Solargraph
4
4
  class YardMap
5
5
  class Cache
6
6
  def initialize
7
+ # @type [Hash{String => Array<Solargraph::Pin::Base>}]
7
8
  @path_pins = {}
8
9
  end
9
10
 
11
+ # @param path [String]
12
+ # @param pins [Array<Solargraph::Pin::Base>]
13
+ # @return [Array<Solargraph::Pin::Base>]
10
14
  def set_path_pins path, pins
11
15
  @path_pins[path] = pins
12
16
  end
13
17
 
18
+ # @param path [String]
19
+ # @return [Array<Solargraph::Pin::Base>]
14
20
  def get_path_pins path
15
21
  @path_pins[path]
16
22
  end
@@ -4,7 +4,7 @@ module Solargraph
4
4
  module_function
5
5
 
6
6
  # @param code_object [YARD::CodeObjects::Base]
7
- # @param spec [Gem::Specification]
7
+ # @param spec [Gem::Specification, nil]
8
8
  # @return [Solargraph::Location, nil]
9
9
  def object_location code_object, spec
10
10
  return nil if spec.nil? || code_object.nil? || code_object.file.nil? || code_object.line.nil?