solargraph 0.39.0 → 0.40.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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -7
  3. data/CHANGELOG.md +984 -0
  4. data/Rakefile +12 -1
  5. data/SPONSORS.md +6 -0
  6. data/lib/.rubocop.yml +21 -0
  7. data/lib/solargraph/api_map/cache.rb +4 -0
  8. data/lib/solargraph/api_map/store.rb +35 -51
  9. data/lib/solargraph/api_map.rb +94 -87
  10. data/lib/solargraph/{bundle.rb → bench.rb} +6 -2
  11. data/lib/solargraph/compat.rb +23 -0
  12. data/lib/solargraph/complex_type.rb +2 -2
  13. data/lib/solargraph/convention/base.rb +16 -8
  14. data/lib/solargraph/convention/gemfile.rb +2 -5
  15. data/lib/solargraph/convention/gemspec.rb +3 -6
  16. data/lib/solargraph/convention/rspec.rb +3 -6
  17. data/lib/solargraph/convention.rb +14 -5
  18. data/lib/solargraph/diagnostics/rubocop.rb +2 -1
  19. data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
  20. data/lib/solargraph/documentor.rb +4 -0
  21. data/lib/solargraph/environ.rb +11 -6
  22. data/lib/solargraph/language_server/host.rb +1 -1
  23. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +6 -1
  24. data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
  25. data/lib/solargraph/language_server/message/text_document/formatting.rb +7 -3
  26. data/lib/solargraph/language_server/uri_helpers.rb +23 -3
  27. data/lib/solargraph/library.rb +22 -8
  28. data/lib/solargraph/parser/legacy/class_methods.rb +4 -0
  29. data/lib/solargraph/parser/legacy/node_chainer.rb +10 -7
  30. data/lib/solargraph/parser/legacy/node_methods.rb +16 -3
  31. data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +1 -1
  32. data/lib/solargraph/parser/legacy/node_processors/send_node.rb +48 -23
  33. data/lib/solargraph/parser/node_processor/base.rb +3 -0
  34. data/lib/solargraph/parser/rubyvm/class_methods.rb +6 -2
  35. data/lib/solargraph/parser/rubyvm/node_chainer.rb +11 -9
  36. data/lib/solargraph/parser/rubyvm/node_methods.rb +6 -1
  37. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +35 -11
  38. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +1 -1
  39. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +6 -1
  40. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +6 -1
  41. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +52 -67
  42. data/lib/solargraph/parser/rubyvm/node_processors.rb +2 -0
  43. data/lib/solargraph/pin/base.rb +2 -2
  44. data/lib/solargraph/pin/base_variable.rb +1 -1
  45. data/lib/solargraph/pin/block.rb +28 -14
  46. data/lib/solargraph/pin/closure.rb +1 -1
  47. data/lib/solargraph/pin/common.rb +1 -1
  48. data/lib/solargraph/pin/constant.rb +1 -1
  49. data/lib/solargraph/pin/conversions.rb +3 -4
  50. data/lib/solargraph/pin/documenting.rb +6 -11
  51. data/lib/solargraph/pin/local_variable.rb +1 -1
  52. data/lib/solargraph/pin/method.rb +143 -9
  53. data/lib/solargraph/pin/method_alias.rb +2 -2
  54. data/lib/solargraph/pin/namespace.rb +1 -1
  55. data/lib/solargraph/pin/parameter.rb +2 -2
  56. data/lib/solargraph/pin/proxy_type.rb +1 -1
  57. data/lib/solargraph/pin.rb +0 -3
  58. data/lib/solargraph/position.rb +2 -14
  59. data/lib/solargraph/shell.rb +2 -1
  60. data/lib/solargraph/source/chain/call.rb +9 -0
  61. data/lib/solargraph/source/chain/head.rb +14 -8
  62. data/lib/solargraph/source/chain/z_super.rb +30 -0
  63. data/lib/solargraph/source/chain.rb +19 -36
  64. data/lib/solargraph/source/source_chainer.rb +2 -1
  65. data/lib/solargraph/source.rb +24 -9
  66. data/lib/solargraph/source_map/clip.rb +78 -44
  67. data/lib/solargraph/source_map/mapper.rb +41 -21
  68. data/lib/solargraph/source_map.rb +20 -2
  69. data/lib/solargraph/type_checker/param_def.rb +1 -1
  70. data/lib/solargraph/type_checker.rb +61 -42
  71. data/lib/solargraph/version.rb +1 -1
  72. data/lib/solargraph/views/_name_type_tag.erb +1 -1
  73. data/lib/solargraph/workspace.rb +1 -1
  74. data/lib/solargraph/yard_map/core_fills.rb +185 -0
  75. data/lib/solargraph/yard_map/helpers.rb +16 -0
  76. data/lib/solargraph/{pin/yard_pin/constant.rb → yard_map/mapper/to_constant.rb} +6 -6
  77. data/lib/solargraph/yard_map/mapper/to_method.rb +78 -0
  78. data/lib/solargraph/{pin/yard_pin/namespace.rb → yard_map/mapper/to_namespace.rb} +6 -6
  79. data/lib/solargraph/yard_map/mapper.rb +17 -8
  80. data/lib/solargraph/yard_map/rdoc_to_yard.rb +26 -15
  81. data/lib/solargraph/yard_map/stdlib_fills.rb +43 -0
  82. data/lib/solargraph/yard_map/to_method.rb +79 -0
  83. data/lib/solargraph/yard_map.rb +140 -92
  84. data/lib/solargraph.rb +5 -4
  85. data/solargraph.gemspec +5 -5
  86. data/yardoc/2.2.2.tar.gz +0 -0
  87. metadata +29 -41
  88. data/.rubocop.yml +0 -6
  89. data/lib/solargraph/core_fills.rb +0 -159
  90. data/lib/solargraph/pin/attribute.rb +0 -49
  91. data/lib/solargraph/pin/base_method.rb +0 -141
  92. data/lib/solargraph/pin/yard_pin/method.rb +0 -65
  93. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +0 -26
  94. data/lib/solargraph/pin/yard_pin.rb +0 -12
  95. data/lib/solargraph/stdlib_fills.rb +0 -32
  96. data/travis-bundler.rb +0 -11
@@ -73,15 +73,15 @@ module Solargraph
73
73
  # @return [Array<Problem>]
74
74
  def method_tag_problems
75
75
  result = []
76
- # @param pin [Pin::BaseMethod]
77
- source_map.pins.select { |pin| pin.is_a?(Pin::BaseMethod) }.each do |pin|
76
+ # @param pin [Pin::Method]
77
+ source_map.pins_by_class(Pin::Method).each do |pin|
78
78
  result.concat method_return_type_problems_for(pin)
79
79
  result.concat method_param_type_problems_for(pin)
80
80
  end
81
81
  result
82
82
  end
83
83
 
84
- # @param pin [Pin::BaseMethod]
84
+ # @param pin [Pin::Method]
85
85
  # @return [Array<Problem>]
86
86
  def method_return_type_problems_for pin
87
87
  result = []
@@ -115,7 +115,7 @@ module Solargraph
115
115
  pin.location && source_map.source.comment_at?(pin.location.range.ending)
116
116
  end
117
117
 
118
- # @param pin [Pin::BaseMethod]
118
+ # @param pin [Pin::Method]
119
119
  # @return [Array<Problem>]
120
120
  def method_param_type_problems_for pin
121
121
  stack = api_map.get_method_stack(pin.namespace, pin.name, scope: pin.scope)
@@ -147,14 +147,12 @@ module Solargraph
147
147
  result = []
148
148
  all_variables.each do |pin|
149
149
  if pin.return_type.defined?
150
- # @todo Somwhere in here we still need to determine if the variable is defined by an external call
151
150
  declared = pin.typify(api_map)
152
151
  if declared.defined?
153
152
  if rules.validate_tags?
154
153
  inferred = pin.probe(api_map)
155
154
  if inferred.undefined?
156
155
  next if rules.ignore_all_undefined?
157
- # next unless internal?(pin) # @todo This might be redundant for variables
158
156
  if declared_externally?(pin)
159
157
  ignored_pins.push pin
160
158
  else
@@ -172,7 +170,6 @@ module Solargraph
172
170
  result.push Problem.new(pin.location, "Unresolved type #{pin.return_type} for variable #{pin.name}", pin: pin)
173
171
  end
174
172
  else
175
- # @todo Check if the variable is defined by an external call
176
173
  inferred = pin.probe(api_map)
177
174
  if inferred.undefined? && declared_externally?(pin)
178
175
  ignored_pins.push pin
@@ -184,8 +181,7 @@ module Solargraph
184
181
 
185
182
  # @return [Array<Pin::BaseVariable>]
186
183
  def all_variables
187
- source_map.pins.select { |pin| pin.is_a?(Pin::BaseVariable) } +
188
- source_map.locals.select { |pin| pin.is_a?(Pin::LocalVariable) }
184
+ source_map.pins_by_class(Pin::BaseVariable) + source_map.locals.select { |pin| pin.is_a?(Pin::LocalVariable) }
189
185
  end
190
186
 
191
187
  def const_problems
@@ -228,7 +224,7 @@ module Solargraph
228
224
  base = base.base
229
225
  end
230
226
  closest = found.typify(api_map) if found
231
- if !found || closest.defined? || internal?(found)
227
+ if !found || (closest.defined? && internal_or_core?(found))
232
228
  unless ignored_pins.include?(found)
233
229
  result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
234
230
  @marked_ranges.push rng
@@ -245,10 +241,14 @@ module Solargraph
245
241
  base = chain
246
242
  until base.links.length == 1 && base.undefined?
247
243
  pins = base.define(api_map, block_pin, locals)
248
- if pins.first.is_a?(Pin::BaseMethod)
249
- # @type [Pin::BaseMethod]
244
+ if pins.first.is_a?(Pin::Method)
245
+ # @type [Pin::Method]
250
246
  pin = pins.first
251
- ap = arity_problems_for(pin, base.links.last.arguments, location)
247
+ ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
248
+ arity_problems_for(pin, fake_args_for(block_pin), location)
249
+ else
250
+ arity_problems_for(pin, base.links.last.arguments, location)
251
+ end
252
252
  unless ap.empty?
253
253
  result.concat ap
254
254
  break
@@ -310,7 +310,6 @@ module Solargraph
310
310
  end
311
311
  else
312
312
  if par.decl == :kwarg
313
- # @todo Problem: missing required keyword argument
314
313
  result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
315
314
  end
316
315
  end
@@ -357,9 +356,14 @@ module Solargraph
357
356
 
358
357
  # @param pin [Pin::Base]
359
358
  def internal? pin
359
+ return false if pin.nil?
360
360
  pin.location && api_map.bundled?(pin.location.filename)
361
361
  end
362
362
 
363
+ def internal_or_core? pin
364
+ internal?(pin) || api_map.yard_map.core_pins.include?(pin) || api_map.yard_map.stdlib_pins.include?(pin)
365
+ end
366
+
363
367
  # @param pin [Pin::Base]
364
368
  def external? pin
365
369
  !internal? pin
@@ -392,7 +396,7 @@ module Solargraph
392
396
  true
393
397
  end
394
398
 
395
- # @param pin [Pin::BaseMethod]
399
+ # @param pin [Pin::Method]
396
400
  def arity_problems_for(pin, arguments, location)
397
401
  return [] unless pin.explicit?
398
402
  return [] if pin.parameters.empty? && arguments.empty?
@@ -407,29 +411,29 @@ module Solargraph
407
411
  if unchecked.empty? && pin.parameters.any? { |param| param.decl == :kwarg }
408
412
  return [Problem.new(location, "Missing keyword arguments to #{pin.path}")]
409
413
  end
414
+ settled_kwargs = 0
410
415
  unless unchecked.empty?
411
416
  kwargs = convert_hash(unchecked.last.node)
412
- # unless kwargs.empty?
413
- if pin.parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
414
- if kwargs.empty?
415
- add_params += 1
416
- else
417
- unchecked.pop
418
- pin.parameters.each do |param|
419
- next unless param.keyword?
420
- if kwargs.key?(param.name.to_sym)
421
- kwargs.delete param.name.to_sym
422
- elsif param.decl == :kwarg
423
- return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
424
- end
425
- end
426
- kwargs.clear if pin.parameters.any?(&:kwrestarg?)
427
- unless kwargs.empty?
428
- return [Problem.new(location, "Unrecognized keyword argument #{kwargs.keys.first} to #{pin.path}")]
417
+ if pin.parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
418
+ if kwargs.empty?
419
+ add_params += 1
420
+ else
421
+ unchecked.pop
422
+ pin.parameters.each do |param|
423
+ next unless param.keyword?
424
+ if kwargs.key?(param.name.to_sym)
425
+ kwargs.delete param.name.to_sym
426
+ settled_kwargs += 1
427
+ elsif param.decl == :kwarg
428
+ return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
429
429
  end
430
430
  end
431
+ kwargs.clear if pin.parameters.any?(&:kwrestarg?)
432
+ unless kwargs.empty?
433
+ return [Problem.new(location, "Unrecognized keyword argument #{kwargs.keys.first} to #{pin.path}")]
434
+ end
431
435
  end
432
- # end
436
+ end
433
437
  end
434
438
  req = required_param_count(pin)
435
439
  if req + add_params < unchecked.length
@@ -440,23 +444,18 @@ module Solargraph
440
444
  return []
441
445
  end
442
446
  return [Problem.new(location, "Too many arguments to #{pin.path}")]
443
- elsif unchecked.length < req && (arguments.empty? || !arguments.last.splat?)
447
+ elsif unchecked.length < req - settled_kwargs && (arguments.empty? || !arguments.last.splat?)
444
448
  return [Problem.new(location, "Not enough arguments to #{pin.path}")]
445
449
  end
446
450
  []
447
451
  end
448
452
 
449
- # @param pin [Pin::BaseMethod]
453
+ # @param pin [Pin::Method]
450
454
  def required_param_count(pin)
451
- count = 0
452
- pin.parameters.each do |param|
453
- break unless param.decl == :arg
454
- count += 1
455
- end
456
- count
455
+ pin.parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
457
456
  end
458
457
 
459
- # @param pin [Pin::BaseMethod]
458
+ # @param pin [Pin::Method]
460
459
  def optional_param_count(pin)
461
460
  count = 0
462
461
  pin.parameters.each do |param|
@@ -470,5 +469,25 @@ module Solargraph
470
469
  pin.docstring.has_tag?(:abstract) ||
471
470
  (pin.closure && pin.closure.docstring.has_tag?(:abstract))
472
471
  end
472
+
473
+ def fake_args_for(pin)
474
+ args = []
475
+ with_opts = false
476
+ with_block = false
477
+ pin.parameters.each do |pin|
478
+ if [:kwarg, :kwoptarg, :kwrestarg].include?(pin.decl)
479
+ with_opts = true
480
+ elsif pin.decl == :block
481
+ with_block = true
482
+ elsif pin.decl == :restarg
483
+ args.push Solargraph::Source::Chain.new([Solargraph::Source::Chain::Variable.new(pin.name)], nil, true)
484
+ else
485
+ args.push Solargraph::Source::Chain.new([Solargraph::Source::Chain::Variable.new(pin.name)])
486
+ end
487
+ end
488
+ args.push Solargraph::Parser.chain_string('{}') if with_opts
489
+ args.push Solargraph::Parser.chain_string('&') if with_block
490
+ args
491
+ end
473
492
  end
474
493
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.39.0'
4
+ VERSION = '0.40.0'
5
5
  end
@@ -2,7 +2,7 @@
2
2
  <% unless tag.types.nil? or tag.types.empty? %>
3
3
  [<%= escape(tag.types.join(', ')) %>]
4
4
  <% end %>
5
- <% unless tag.text.empty? %>
5
+ <% unless tag.text.nil? || tag.text.empty? %>
6
6
  <% unless (tag.name.nil? or tag.name.empty?) and (tag.types.nil? or tag.types.empty?) %>
7
7
  -
8
8
  <% end %>
@@ -170,7 +170,7 @@ module Solargraph
170
170
  Dir.chdir base do
171
171
  begin
172
172
  # @type [Gem::Specification]
173
- spec = eval(File.read(file), binding, file)
173
+ spec = eval(File.read(file), TOPLEVEL_BINDING, file)
174
174
  next unless Gem::Specification === spec
175
175
  @gemnames.push spec.name
176
176
  result.concat(spec.require_paths.map { |path| File.join(base, path) })
@@ -0,0 +1,185 @@
1
+ module Solargraph
2
+ class YardMap
3
+ module CoreFills
4
+ Override = Pin::Reference::Override
5
+
6
+ KEYWORDS = [
7
+ '__ENCODING__', '__LINE__', '__FILE__', 'BEGIN', 'END', 'alias', 'and',
8
+ 'begin', 'break', 'case', 'class', 'def', 'defined?', 'do', 'else',
9
+ 'elsif', 'end', 'ensure', 'false', 'for', 'if', 'in', 'module', 'next',
10
+ 'nil', 'not', 'or', 'redo', 'rescue', 'retry', 'return', 'self', 'super',
11
+ 'then', 'true', 'undef', 'unless', 'until', 'when', 'while', 'yield'
12
+ ].map { |k| Pin::Keyword.new(k) }
13
+
14
+ methods_with_yieldparam_subtypes = %w[
15
+ Array#each Array#map Array#map! Array#any? Array#all? Array#index
16
+ Array#keep_if Array#delete_if
17
+ Enumerable#each_entry Enumerable#map Enumerable#any? Enumerable#all?
18
+ Enumerable#select Enumerable#reject
19
+ Set#each
20
+ ]
21
+
22
+ OVERRIDES = [
23
+ Override.method_return('Array#concat', 'Array'),
24
+ Override.method_return('Array#keep_if', 'self'),
25
+ Override.method_return('Array#delete_if', 'self'),
26
+ Override.from_comment('Array#map', %(
27
+ @overload map(&block)
28
+ @return [Array]
29
+ @overload map()
30
+ @return [Enumerator]
31
+ )),
32
+ Override.from_comment('Array#reject', %(
33
+ @overload reject(&block)
34
+ @return [self]
35
+ @overload reject()
36
+ @return [Enumerator]
37
+ )),
38
+ Override.method_return('Array#reverse', 'self', delete: ['overload']),
39
+ Override.from_comment('Array#select', %(
40
+ @overload select(&block)
41
+ @return [self]
42
+ @overload select()
43
+ @return [Enumerator]
44
+ )),
45
+ Override.from_comment('Array#[]', %(
46
+ @overload [](range)
47
+ @param range [Range]
48
+ @return [self]
49
+ @overload [](num1, num2)
50
+ @param num1 [Integer]
51
+ @param num2 [Integer]
52
+ @return [self]
53
+ @overload [](num)
54
+ @param num [Integer]
55
+ @return_single_parameter
56
+ @return_single_parameter
57
+ )),
58
+ Override.from_comment('Array#first', %(
59
+ @overload first(num)
60
+ @param num [Integer]
61
+ @return [self]
62
+ @return_single_parameter
63
+ )),
64
+ Override.from_comment('Array#last', %(
65
+ @overload last(num)
66
+ @param num [Integer]
67
+ @return [self]
68
+ @return_single_parameter
69
+ )),
70
+ Override.method_return('Array#map', 'Array'),
71
+ Override.method_return('Array#uniq', 'self'),
72
+ Override.method_return('Array#zip', 'Array, nil'),
73
+
74
+ Override.from_comment('BasicObject#==', %(
75
+ @param other [BasicObject]
76
+ @return [Boolean]
77
+ )),
78
+ Override.method_return('BasicObject#initialize', 'void'),
79
+
80
+ Override.method_return('Class#new', 'self'),
81
+ Override.method_return('Class.new', 'Class<Object>'),
82
+ Override.method_return('Class#allocate', 'self'),
83
+ Override.method_return('Class.allocate', 'Class<Object>'),
84
+
85
+ Override.method_return('Enumerable#select', 'self'),
86
+
87
+ Override.method_return('File.absolute_path', 'String'),
88
+ Override.method_return('File.basename', 'String'),
89
+ Override.method_return('File.dirname', 'String'),
90
+ Override.method_return('File.extname', 'String'),
91
+ Override.method_return('File.join', 'String'),
92
+
93
+ Override.from_comment('Float#+', %(
94
+ @param y [Numeric]
95
+ @return [Numeric]
96
+ )),
97
+
98
+ Override.from_comment('Hash#[]', %(
99
+ @return_value_parameter
100
+ )),
101
+
102
+ # @todo This override isn't robust enough. It needs to allow for
103
+ # parameterized Hash types, e.g., [Hash{Symbol => String}].
104
+ Override.from_comment('Hash#[]=', %(
105
+ @param_tuple
106
+ )),
107
+
108
+ Override.method_return('Hash#merge', 'Hash'),
109
+
110
+ Override.from_comment('Integer#+', %(
111
+ @param y [Numeric]
112
+ @return [Numeric]
113
+ )),
114
+
115
+ Override.method_return('Kernel#puts', 'nil'),
116
+
117
+ Override.from_comment('Numeric#+', %(
118
+ @param y [Numeric]
119
+ @return [Numeric]
120
+ )),
121
+
122
+ Override.method_return('Object#!', 'Boolean'),
123
+ Override.method_return('Object#clone', 'self', delete: [:overload]),
124
+ Override.method_return('Object#dup', 'self', delete: [:overload]),
125
+ Override.method_return('Object#freeze', 'self', delete: [:overload]),
126
+ Override.method_return('Object#inspect', 'String'),
127
+ Override.method_return('Object#taint', 'self'),
128
+ Override.method_return('Object#to_s', 'String'),
129
+ Override.method_return('Object#untaint', 'self'),
130
+ Override.from_comment('Object#tap', %(
131
+ @return [self]
132
+ @yieldparam [self]
133
+ )),
134
+
135
+ Override.from_comment('STDERR', %(
136
+ @type [IO]
137
+ )),
138
+
139
+ Override.from_comment('STDIN', %(
140
+ @type [IO]
141
+ )),
142
+
143
+ Override.from_comment('STDOUT', %(
144
+ @type [IO]
145
+ )),
146
+
147
+ Override.method_return('String#freeze', 'self'),
148
+ Override.method_return('String#split', 'Array<String>'),
149
+ Override.method_return('String#lines', 'Array<String>'),
150
+ Override.from_comment('String#each_line', %(
151
+ @yieldparam [String]
152
+ )),
153
+ Override.from_comment('String.new', %(
154
+ @overload new(*)
155
+ @return [self]
156
+ ))
157
+ ].concat(
158
+ methods_with_yieldparam_subtypes.map do |path|
159
+ Override.from_comment(path, %(
160
+ @yieldparam_single_parameter
161
+ ))
162
+ end
163
+ )
164
+
165
+ PINS = [
166
+ Pin::Reference::Superclass.new(closure: Pin::Namespace.new(name: 'File'), name: 'IO'),
167
+ Pin::Reference::Superclass.new(closure: Pin::Namespace.new(name: 'Integer'), name: 'Numeric'),
168
+ Pin::Reference::Superclass.new(closure: Pin::Namespace.new(name: 'Float'), name: 'Numeric')
169
+ ].concat(
170
+ # HACK: Add Errno exception classes
171
+ begin
172
+ errno = Solargraph::Pin::Namespace.new(name: 'Errno')
173
+ result = []
174
+ Errno.constants.each do |const|
175
+ result.push Solargraph::Pin::Namespace.new(type: :class, name: const.to_s, closure: errno)
176
+ result.push Solargraph::Pin::Reference::Superclass.new(closure: result.last, name: 'SystemCallError')
177
+ end
178
+ result
179
+ end
180
+ )
181
+
182
+ ALL = KEYWORDS + PINS + OVERRIDES
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,16 @@
1
+ module Solargraph
2
+ class YardMap
3
+ module Helpers
4
+ module_function
5
+
6
+ # @param code_object [YARD::CodeObjects::Base]
7
+ # @param spec [Gem::Specification]
8
+ # @return [Solargraph::Location, nil]
9
+ def object_location code_object, spec
10
+ return nil if spec.nil? || code_object.nil? || code_object.file.nil? || code_object.line.nil?
11
+ file = File.join(spec.full_gem_path, code_object.file)
12
+ Solargraph::Location.new(file, Solargraph::Range.from_to(code_object.line - 1, 0, code_object.line - 1, 0))
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- module Pin
5
- module YardPin
6
- class Constant < Pin::Constant
7
- include YardMixin
4
+ class YardMap
5
+ class Mapper
6
+ module ToConstant
7
+ extend YardMap::Helpers
8
8
 
9
- def initialize code_object, closure = nil, spec = nil
9
+ def self.make code_object, closure = nil, spec = nil
10
10
  closure ||= Solargraph::Pin::Namespace.new(
11
11
  name: code_object.namespace.to_s,
12
12
  gates: [code_object.namespace.to_s]
13
13
  )
14
- super(
14
+ Pin::Constant.new(
15
15
  location: object_location(code_object, spec),
16
16
  closure: closure,
17
17
  name: code_object.name.to_s,
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class YardMap
5
+ class Mapper
6
+ module ToMethod
7
+ extend YardMap::Helpers
8
+
9
+ def self.make code_object, name = nil, scope = nil, visibility = nil, closure = nil, spec = nil
10
+ closure ||= Solargraph::Pin::Namespace.new(
11
+ name: code_object.namespace.to_s,
12
+ gates: [code_object.namespace.to_s]
13
+ )
14
+ location = object_location(code_object, spec)
15
+ comments = code_object.docstring ? code_object.docstring.all.to_s : ''
16
+ Pin::Method.new(
17
+ location: location,
18
+ closure: closure,
19
+ name: name || code_object.name.to_s,
20
+ comments: comments,
21
+ scope: scope || code_object.scope,
22
+ visibility: visibility || code_object.visibility,
23
+ parameters: get_parameters(code_object, location, comments),
24
+ explicit: code_object.is_explicit?
25
+ )
26
+ end
27
+
28
+ class << self
29
+ private
30
+
31
+ # @param code_object [YARD::CodeObjects::Base]
32
+ # @return [Array<Solargraph::Pin::Parameter>]
33
+ def get_parameters code_object, location, comments
34
+ return [] unless code_object.is_a?(YARD::CodeObjects::MethodObject)
35
+ # HACK: Skip `nil` and `self` parameters that are sometimes emitted
36
+ # for methods defined in C
37
+ # See https://github.com/castwide/solargraph/issues/345
38
+ code_object.parameters.select { |a| a[0] && a[0] != 'self' }.map do |a|
39
+ Solargraph::Pin::Parameter.new(
40
+ location: location,
41
+ closure: self,
42
+ comments: comments,
43
+ name: arg_name(a),
44
+ presence: nil,
45
+ decl: arg_type(a),
46
+ asgn_code: a[1]
47
+ )
48
+ end
49
+ end
50
+
51
+ # @param a [Array]
52
+ # @return [String]
53
+ def arg_name a
54
+ a[0].gsub(/[^a-z0-9_]/i, '')
55
+ end
56
+
57
+ # @param a [Array]
58
+ # @return [::Symbol]
59
+ def arg_type a
60
+ if a[0].start_with?('**')
61
+ :kwrestarg
62
+ elsif a[0].start_with?('*')
63
+ :restarg
64
+ elsif a[0].start_with?('&')
65
+ :blockarg
66
+ elsif a[0].end_with?(':')
67
+ a[1] ? :kwoptarg : :kwarg
68
+ elsif a[1]
69
+ :optarg
70
+ else
71
+ :arg
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- module Pin
5
- module YardPin
6
- class Namespace < Pin::Namespace
7
- include YardMixin
4
+ class YardMap
5
+ class Mapper
6
+ module ToNamespace
7
+ extend YardMap::Helpers
8
8
 
9
- def initialize code_object, spec, closure = nil
9
+ def self.make code_object, spec, closure = nil
10
10
  closure ||= Solargraph::Pin::Namespace.new(
11
11
  name: code_object.namespace.to_s,
12
12
  closure: Pin::ROOT_PIN,
13
13
  gates: [code_object.namespace.to_s]
14
14
  )
15
- super(
15
+ Pin::Namespace.new(
16
16
  location: object_location(code_object, spec),
17
17
  name: code_object.name.to_s,
18
18
  comments: code_object.docstring ? code_object.docstring.all.to_s : '',
@@ -3,6 +3,10 @@
3
3
  module Solargraph
4
4
  class YardMap
5
5
  class Mapper
6
+ autoload :ToMethod, 'solargraph/yard_map/mapper/to_method'
7
+ autoload :ToNamespace, 'solargraph/yard_map/mapper/to_namespace'
8
+ autoload :ToConstant, 'solargraph/yard_map/mapper/to_constant'
9
+
6
10
  # @param code_objects [Array<YARD::CodeObjects::Base>]
7
11
  # @param spec [Gem::Specification]
8
12
  def initialize code_objects, spec = nil
@@ -17,25 +21,30 @@ module Solargraph
17
21
  @code_objects.each do |co|
18
22
  @pins.concat generate_pins co
19
23
  end
24
+ # Some yardocs contain documentation for dependencies that can be
25
+ # ignored here. The YardMap will load dependencies separately.
26
+ @pins.keep_if { |pin| pin.location.nil? || File.file?(pin.location.filename) } if @spec
20
27
  @pins
21
28
  end
22
29
 
30
+ private
31
+
23
32
  # @param code_object [YARD::CodeObjects::Base]
24
33
  # @return [Array<Pin::Base>]
25
34
  def generate_pins code_object
26
35
  result = []
27
36
  if code_object.is_a?(YARD::CodeObjects::NamespaceObject)
28
- nspin = Solargraph::Pin::YardPin::Namespace.new(code_object, @spec, @namespace_pins[code_object.namespace.to_s])
37
+ nspin = ToNamespace.make(code_object, @spec, @namespace_pins[code_object.namespace.to_s])
29
38
  @namespace_pins[code_object.path] = nspin
30
39
  result.push nspin
31
40
  if code_object.is_a?(YARD::CodeObjects::ClassObject) and !code_object.superclass.nil?
32
41
  # This method of superclass detection is a bit of a hack. If
33
42
  # the superclass is a Proxy, it is assumed to be undefined in its
34
43
  # yardoc and converted to a fully qualified namespace.
35
- if code_object.superclass.is_a?(YARD::CodeObjects::Proxy)
36
- superclass = "::#{code_object.superclass}"
44
+ superclass = if code_object.superclass.is_a?(YARD::CodeObjects::Proxy)
45
+ "::#{code_object.superclass}"
37
46
  else
38
- superclass = code_object.superclass.to_s
47
+ code_object.superclass.to_s
39
48
  end
40
49
  result.push Solargraph::Pin::Reference::Superclass.new(name: superclass, closure: nspin)
41
50
  end
@@ -52,14 +61,14 @@ module Solargraph
52
61
  closure = @namespace_pins[code_object.namespace.to_s]
53
62
  if code_object.name == :initialize && code_object.scope == :instance
54
63
  # @todo Check the visibility of <Class>.new
55
- result.push Solargraph::Pin::YardPin::Method.new(code_object, 'new', :class, :public, closure, @spec)
56
- result.push Solargraph::Pin::YardPin::Method.new(code_object, 'initialize', :instance, :private, closure, @spec)
64
+ result.push ToMethod.make(code_object, 'new', :class, :public, closure, @spec)
65
+ result.push ToMethod.make(code_object, 'initialize', :instance, :private, closure, @spec)
57
66
  else
58
- result.push Solargraph::Pin::YardPin::Method.new(code_object, nil, nil, nil, closure, @spec)
67
+ result.push ToMethod.make(code_object, nil, nil, nil, closure, @spec)
59
68
  end
60
69
  elsif code_object.is_a?(YARD::CodeObjects::ConstantObject)
61
70
  closure = @namespace_pins[code_object.namespace]
62
- result.push Solargraph::Pin::YardPin::Constant.new(code_object, closure, @spec)
71
+ result.push ToConstant.make(code_object, closure, @spec)
63
72
  end
64
73
  result
65
74
  end