solargraph 0.40.2 → 0.41.2

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/README.md +15 -0
  4. data/SPONSORS.md +1 -0
  5. data/lib/.rubocop.yml +2 -2
  6. data/lib/solargraph.rb +8 -7
  7. data/lib/solargraph/api_map.rb +52 -75
  8. data/lib/solargraph/api_map/store.rb +5 -0
  9. data/lib/solargraph/bench.rb +19 -18
  10. data/lib/solargraph/compat.rb +15 -1
  11. data/lib/solargraph/diagnostics/rubocop.rb +10 -2
  12. data/lib/solargraph/diagnostics/rubocop_helpers.rb +19 -20
  13. data/lib/solargraph/language_server/host.rb +74 -1
  14. data/lib/solargraph/language_server/host/diagnoser.rb +9 -1
  15. data/lib/solargraph/language_server/message/completion_item/resolve.rb +1 -0
  16. data/lib/solargraph/language_server/message/extended/environment.rb +3 -3
  17. data/lib/solargraph/language_server/message/initialize.rb +30 -35
  18. data/lib/solargraph/language_server/message/text_document/formatting.rb +68 -18
  19. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  20. data/lib/solargraph/library.rb +94 -21
  21. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -1
  22. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +11 -12
  23. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +1 -6
  24. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +1 -1
  25. data/lib/solargraph/source.rb +1 -1
  26. data/lib/solargraph/source/chain/head.rb +0 -16
  27. data/lib/solargraph/source/source_chainer.rb +1 -0
  28. data/lib/solargraph/source_map/mapper.rb +0 -5
  29. data/lib/solargraph/type_checker.rb +25 -22
  30. data/lib/solargraph/type_checker/checks.rb +9 -5
  31. data/lib/solargraph/type_checker/rules.rb +5 -1
  32. data/lib/solargraph/version.rb +1 -1
  33. data/lib/solargraph/workspace/config.rb +19 -3
  34. data/lib/solargraph/yard_map/core_fills.rb +1 -0
  35. metadata +2 -2
@@ -109,7 +109,6 @@ module Solargraph
109
109
  end
110
110
 
111
111
  def node_to_argchains node
112
- # @todo Process array, splat, argscat
113
112
  return [] unless Parser.is_ast_node?(node)
114
113
  if [:ZARRAY, :ARRAY, :LIST].include?(node.type)
115
114
  node.children[0..-2].map { |c| NodeChainer.chain(c) }
@@ -32,7 +32,6 @@ module Solargraph
32
32
  region.closure.parameters.push locals.last
33
33
  end
34
34
  end
35
- # @todo Optional args, keyword args, etc.
36
35
  if node.children[6]
37
36
  locals.push Solargraph::Pin::Parameter.new(
38
37
  location: region.closure.location,
@@ -55,19 +54,19 @@ module Solargraph
55
54
  )
56
55
  region.closure.parameters.push locals.last
57
56
  end
58
- if node.children.last
59
- locals.push Solargraph::Pin::Parameter.new(
60
- location: region.closure.location,
61
- closure: region.closure,
62
- comments: comments_for(node),
63
- name: node.children.last.to_s,
64
- presence: region.closure.location.range,
65
- decl: :blockarg
66
- )
67
- region.closure.parameters.push locals.last
68
- end
69
57
  end
70
58
  process_children
59
+ if node.children.last
60
+ locals.push Solargraph::Pin::Parameter.new(
61
+ location: region.closure.location,
62
+ closure: region.closure,
63
+ comments: comments_for(node),
64
+ name: node.children.last.to_s,
65
+ presence: region.closure.location.range,
66
+ decl: :blockarg
67
+ )
68
+ region.closure.parameters.push locals.last
69
+ end
71
70
  end
72
71
 
73
72
  private
@@ -16,12 +16,7 @@ module Solargraph
16
16
  presence: region.closure.location.range,
17
17
  decl: :optarg
18
18
  )
19
- idx = region.closure.parameters.find_index { |par| par.decl != :arg }
20
- if idx
21
- region.closure.parameters.insert idx, locals.last
22
- else
23
- region.closure.parameters.push locals.last
24
- end
19
+ region.closure.parameters.push locals.last
25
20
  node.children[1] && NodeProcessor.process(node.children[1], region, pins, locals)
26
21
  end
27
22
  end
@@ -226,7 +226,7 @@ module Solargraph
226
226
 
227
227
  # @return [void]
228
228
  def process_private_constant
229
- # @todo Bare `private_constant` causes an error
229
+ return unless Parser.is_ast_node?(node.children.last)
230
230
  node.children.last.children[0..-2].each do |child|
231
231
  if [:LIT, :STR].include?(child.type)
232
232
  cn = child.children[0].to_s
@@ -175,7 +175,7 @@ module Solargraph
175
175
  synced
176
176
  end
177
177
 
178
- # @param position [Position]
178
+ # @param position [Position, Array(Integer, Integer)]
179
179
  # @return [Source::Cursor]
180
180
  def cursor_at position
181
181
  Cursor.new(self, position)
@@ -13,22 +13,6 @@ module Solargraph
13
13
  # return super_pins(api_map, name_pin) if word == 'super'
14
14
  []
15
15
  end
16
-
17
- # @todo This is temporary. Chain heads need to handle arguments to
18
- # `super`.
19
- # def arguments
20
- # []
21
- # end
22
-
23
- private
24
-
25
- # # @param api_map [ApiMap]
26
- # # @param name_pin [Pin::Base]
27
- # # @return [Array<Pin::Base>]
28
- # def super_pins api_map, name_pin
29
- # pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.scope)
30
- # pins.reject{|p| p.path == name_pin.path}
31
- # end
32
16
  end
33
17
  end
34
18
  end
@@ -34,6 +34,7 @@ module Solargraph
34
34
  # Special handling for files that end with an integer and a period
35
35
  return Chain.new([Chain::Literal.new('Integer'), Chain::UNDEFINED_CALL]) if phrase =~ /^[0-9]+\.$/
36
36
  return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
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)
37
38
  begin
38
39
  return Chain.new([]) if phrase.end_with?('..')
39
40
  node = nil
@@ -71,11 +71,6 @@ module Solargraph
71
71
  pos = Solargraph::Position.new(comment_position.line + line_num - 1, comment_position.column)
72
72
  process_directive(source_position, pos, d)
73
73
  last_line = line_num + 1
74
- # @todo The below call assumes the topmost comment line. The above
75
- # process occasionally emits incorrect comment positions due to
76
- # blank lines in comment blocks, but at least it processes all the
77
- # directives.
78
- # process_directive(source_position, comment_position, d)
79
74
  end
80
75
  end
81
76
 
@@ -95,7 +95,7 @@ module Solargraph
95
95
  result.push Problem.new(pin.location, "Untyped method #{pin.path} could not be inferred")
96
96
  end
97
97
  elsif rules.validate_tags?
98
- unless pin.node.nil? || declared.void? || macro_pin?(pin) || abstract?(pin)
98
+ unless pin.node.nil? || declared.void? || virtual_pin?(pin) || abstract?(pin)
99
99
  inferred = pin.probe(api_map).self_to(pin.full_context.namespace)
100
100
  if inferred.undefined?
101
101
  unless rules.ignore_all_undefined? || external?(pin)
@@ -111,7 +111,7 @@ module Solargraph
111
111
  result
112
112
  end
113
113
 
114
- def macro_pin? pin
114
+ def virtual_pin? pin
115
115
  pin.location && source_map.source.comment_at?(pin.location.range.ending)
116
116
  end
117
117
 
@@ -129,10 +129,10 @@ module Solargraph
129
129
  end
130
130
  end
131
131
  end
132
- params.each_pair do |name, tag|
133
- type = tag.qualify(api_map, pin.full_context.namespace)
132
+ params.each_pair do |name, data|
133
+ type = data[:qualified]
134
134
  if type.undefined?
135
- result.push Problem.new(pin.location, "Unresolved type #{tag} for #{name} param on #{pin.path}", pin: pin)
135
+ result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}", pin: pin)
136
136
  end
137
137
  end
138
138
  result
@@ -266,12 +266,12 @@ module Solargraph
266
266
  result.concat kwarg_problems_for argchain, api_map, block_pin, locals, location, pin, params, idx
267
267
  break
268
268
  else
269
- ptype = params[par.name]
269
+ ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
270
270
  if ptype.nil?
271
271
  # @todo Some level (strong, I guess) should require the param here
272
272
  else
273
273
  argtype = argchain.infer(api_map, block_pin, locals)
274
- if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
274
+ if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
275
275
  result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
276
276
  end
277
277
  end
@@ -299,19 +299,19 @@ module Solargraph
299
299
  result.concat kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
300
300
  else
301
301
  if argchain
302
- ptype = params[par.name]
303
- if ptype.nil?
302
+ data = params[par.name]
303
+ if data.nil?
304
304
  # @todo Some level (strong, I guess) should require the param here
305
305
  else
306
+ ptype = data[:qualified]
307
+ next if ptype.undefined?
306
308
  argtype = argchain.infer(api_map, block_pin, locals)
307
309
  if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
308
310
  result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
309
311
  end
310
312
  end
311
- else
312
- if par.decl == :kwarg
313
- result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
314
- end
313
+ elsif par.decl == :kwarg
314
+ result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
315
315
  end
316
316
  end
317
317
  end
@@ -321,14 +321,11 @@ module Solargraph
321
321
  def kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
322
322
  result = []
323
323
  kwargs.each_pair do |pname, argchain|
324
- ptype = params[pname.to_s]
325
- if ptype.nil?
326
- # Probably nothing to do here. All of these args should be optional.
327
- else
328
- argtype = argchain.infer(api_map, block_pin, locals)
329
- if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
330
- result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{pname} expected #{ptype}, received #{argtype}")
331
- end
324
+ next unless params.key?(pname.to_s)
325
+ ptype = params[pname.to_s][:qualified]
326
+ argtype = argchain.infer(api_map, block_pin, locals)
327
+ if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
328
+ result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{pname} expected #{ptype}, received #{argtype}")
332
329
  end
333
330
  end
334
331
  result
@@ -342,7 +339,10 @@ module Solargraph
342
339
  result = {}
343
340
  tags.each do |tag|
344
341
  next if tag.types.nil? || tag.types.empty?
345
- result[tag.name.to_s] = Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, pin.full_context.namespace)
342
+ result[tag.name.to_s] = {
343
+ tagged: tag.types.join(', '),
344
+ qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, pin.full_context.namespace)
345
+ }
346
346
  end
347
347
  result
348
348
  end
@@ -450,6 +450,9 @@ module Solargraph
450
450
  if unchecked.length == req + opt + 1 && unchecked.last.links.last.is_a?(Source::Chain::BlockVariable)
451
451
  return []
452
452
  end
453
+ if req + add_params + 1 == unchecked.length && splatted_call?(unchecked.last.node) && (pin.parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
454
+ return []
455
+ end
453
456
  return [Problem.new(location, "Too many arguments to #{pin.path}")]
454
457
  elsif unchecked.length < req - settled_kwargs && (arguments.empty? || !arguments.last.splat?)
455
458
  return [Problem.new(location, "Not enough arguments to #{pin.path}")]
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Solargraph
2
4
  class TypeChecker
5
+ # Helper methods for performing type checks
6
+ #
3
7
  module Checks
4
8
  module_function
5
9
 
@@ -62,7 +66,7 @@ module Solargraph
62
66
  # @param inferred [ComplexType]
63
67
  # @return [Boolean]
64
68
  def duck_types_match? api_map, expected, inferred
65
- raise ArgumentError, "Expected type must be duck type" unless expected.duck_type?
69
+ raise ArgumentError, 'Expected type must be duck type' unless expected.duck_type?
66
70
  expected.each do |exp|
67
71
  next unless exp.duck_type?
68
72
  quack = exp.to_s[1..-1]
@@ -71,7 +75,7 @@ module Solargraph
71
75
  true
72
76
  end
73
77
 
74
- # @param type [ComplexType]
78
+ # @param type [ComplexType::UniqueType]
75
79
  # @return [String]
76
80
  def fuzz type
77
81
  if type.parameters?
@@ -82,13 +86,13 @@ module Solargraph
82
86
  end
83
87
 
84
88
  # @param api_map [ApiMap]
85
- # @param cls1 [ComplexType]
86
- # @param cls2 [ComplexType]
89
+ # @param cls1 [ComplexType::UniqueType]
90
+ # @param cls2 [ComplexType::UniqueType]
87
91
  # @return [Boolean]
88
92
  def either_way?(api_map, cls1, cls2)
89
93
  f1 = fuzz(cls1)
90
94
  f2 = fuzz(cls2)
91
- api_map.super_and_sub?(f1, f2) || api_map.super_and_sub?(f2, f1)
95
+ api_map.type_include?(f1, f2) || api_map.super_and_sub?(f1, f2) || api_map.super_and_sub?(f2, f1)
92
96
  end
93
97
  end
94
98
  end
@@ -1,12 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Solargraph
2
4
  class TypeChecker
5
+ # Definitions of type checking rules to be performed at various levels
6
+ #
3
7
  class Rules
4
8
  LEVELS = {
5
9
  normal: 0,
6
10
  typed: 1,
7
11
  strict: 2,
8
12
  strong: 3
9
- }
13
+ }.freeze
10
14
 
11
15
  # @return [Symbol]
12
16
  attr_reader :level
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.40.2'
4
+ VERSION = '0.41.2'
5
5
  end
@@ -85,6 +85,13 @@ module Solargraph
85
85
  raw_data['reporters']
86
86
  end
87
87
 
88
+ # A hash of options supported by the formatter
89
+ #
90
+ # @return [Hash]
91
+ def formatter
92
+ raw_data['formatter']
93
+ end
94
+
88
95
  # An array of plugins to require.
89
96
  #
90
97
  # @return [Array<String>]
@@ -144,6 +151,14 @@ module Solargraph
144
151
  'require' => [],
145
152
  'domains' => [],
146
153
  'reporters' => %w[rubocop require_not_found],
154
+ 'formatter' => {
155
+ 'rubocop' => {
156
+ 'cops' => 'safe',
157
+ 'except' => [],
158
+ 'only' => [],
159
+ 'extra_args' =>[]
160
+ }
161
+ },
147
162
  'require_paths' => [],
148
163
  'plugins' => [],
149
164
  'max_files' => MAX_FILES
@@ -155,9 +170,10 @@ module Solargraph
155
170
  # @param globs [Array<String>]
156
171
  # @return [Array<String>]
157
172
  def process_globs globs
158
- result = []
159
- globs.each do |glob|
160
- result.concat Dir[File.join directory, glob].map{ |f| f.gsub(/\\/, '/') }
173
+ result = globs.flat_map do |glob|
174
+ Dir[File.join directory, glob]
175
+ .map{ |f| f.gsub(/\\/, '/') }
176
+ .select { |f| File.file?(f) }
161
177
  end
162
178
  result
163
179
  end
@@ -111,6 +111,7 @@ module Solargraph
111
111
  @param y [Numeric]
112
112
  @return [Numeric]
113
113
  )),
114
+ Override.method_return('Integer#times', 'Enumerator', delete: [:overload]),
114
115
 
115
116
  Override.method_return('Kernel#puts', 'nil'),
116
117
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.40.2
4
+ version: 0.41.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-18 00:00:00.000000000 Z
11
+ date: 2021-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backport