solargraph 0.39.13 → 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 (68) 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 +1 -0
  6. data/lib/solargraph.rb +2 -4
  7. data/lib/solargraph/api_map.rb +75 -74
  8. data/lib/solargraph/api_map/cache.rb +2 -2
  9. data/lib/solargraph/api_map/store.rb +4 -8
  10. data/lib/solargraph/{bundle.rb → bench.rb} +6 -2
  11. data/lib/solargraph/compat.rb +14 -0
  12. data/lib/solargraph/complex_type.rb +2 -2
  13. data/lib/solargraph/convention.rb +14 -5
  14. data/lib/solargraph/convention/base.rb +16 -8
  15. data/lib/solargraph/convention/gemfile.rb +2 -5
  16. data/lib/solargraph/convention/gemspec.rb +3 -6
  17. data/lib/solargraph/convention/rspec.rb +3 -6
  18. data/lib/solargraph/documentor.rb +2 -0
  19. data/lib/solargraph/environ.rb +11 -6
  20. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +6 -1
  21. data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
  22. data/lib/solargraph/library.rb +7 -7
  23. data/lib/solargraph/parser/legacy/node_chainer.rb +7 -7
  24. data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +1 -1
  25. data/lib/solargraph/parser/legacy/node_processors/send_node.rb +36 -23
  26. data/lib/solargraph/parser/node_processor/base.rb +3 -0
  27. data/lib/solargraph/parser/rubyvm/node_chainer.rb +9 -9
  28. data/lib/solargraph/parser/rubyvm/node_methods.rb +1 -1
  29. data/lib/solargraph/parser/rubyvm/node_processors.rb +1 -0
  30. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +35 -11
  31. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +1 -1
  32. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +40 -29
  33. data/lib/solargraph/pin.rb +0 -3
  34. data/lib/solargraph/pin/common.rb +1 -1
  35. data/lib/solargraph/pin/conversions.rb +3 -4
  36. data/lib/solargraph/pin/documenting.rb +3 -9
  37. data/lib/solargraph/pin/method.rb +141 -7
  38. data/lib/solargraph/pin/method_alias.rb +1 -1
  39. data/lib/solargraph/position.rb +2 -14
  40. data/lib/solargraph/shell.rb +1 -0
  41. data/lib/solargraph/source.rb +10 -6
  42. data/lib/solargraph/source/chain.rb +18 -5
  43. data/lib/solargraph/source_map.rb +4 -1
  44. data/lib/solargraph/source_map/clip.rb +3 -2
  45. data/lib/solargraph/source_map/mapper.rb +10 -6
  46. data/lib/solargraph/type_checker.rb +35 -39
  47. data/lib/solargraph/type_checker/param_def.rb +1 -1
  48. data/lib/solargraph/version.rb +1 -1
  49. data/lib/solargraph/yard_map.rb +40 -47
  50. data/lib/solargraph/yard_map/core_fills.rb +185 -0
  51. data/lib/solargraph/yard_map/helpers.rb +16 -0
  52. data/lib/solargraph/yard_map/mapper.rb +14 -8
  53. data/lib/solargraph/{pin/yard_pin/constant.rb → yard_map/mapper/to_constant.rb} +6 -6
  54. data/lib/solargraph/yard_map/mapper/to_method.rb +78 -0
  55. data/lib/solargraph/{pin/yard_pin/namespace.rb → yard_map/mapper/to_namespace.rb} +6 -6
  56. data/lib/solargraph/yard_map/rdoc_to_yard.rb +1 -1
  57. data/lib/solargraph/yard_map/stdlib_fills.rb +43 -0
  58. data/lib/solargraph/yard_map/to_method.rb +79 -0
  59. data/solargraph.gemspec +4 -4
  60. metadata +20 -34
  61. data/lib/solargraph/core_fills.rb +0 -159
  62. data/lib/solargraph/pin/attribute.rb +0 -49
  63. data/lib/solargraph/pin/base_method.rb +0 -141
  64. data/lib/solargraph/pin/yard_pin.rb +0 -12
  65. data/lib/solargraph/pin/yard_pin/method.rb +0 -80
  66. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +0 -20
  67. data/lib/solargraph/stdlib_fills.rb +0 -40
  68. data/travis-bundler.rb +0 -11
@@ -6,7 +6,7 @@ module Solargraph
6
6
  # examples that defer mapping are aliases for superclass methods or
7
7
  # methods from included modules.
8
8
  #
9
- class MethodAlias < BaseMethod
9
+ class MethodAlias < Method
10
10
  # @return [::Symbol]
11
11
  attr_reader :scope
12
12
 
@@ -40,20 +40,8 @@ module Solargraph
40
40
  # @param position [Position]
41
41
  # @return [Integer]
42
42
  def self.to_offset text, position
43
- result = 0
44
- feed = 0
45
- line = position.line
46
- column = position.character
47
- text.lines.each do |l|
48
- line_length = l.length
49
- if feed == line
50
- result += column
51
- break
52
- end
53
- result += line_length
54
- feed += 1
55
- end
56
- result
43
+ return 0 if text.empty?
44
+ text.lines[0...position.line].sum(&:length) + position.character
57
45
  end
58
46
 
59
47
  # Get a numeric offset for the specified text and a position identified
@@ -153,6 +153,7 @@ module Solargraph
153
153
  probcount += problems.length
154
154
  end
155
155
  puts "#{probcount} problem#{probcount != 1 ? 's' : ''} found#{files.length != 1 ? " in #{filecount} of #{files.length} files" : ''}."
156
+ exit 1 if probcount > 0
156
157
  end
157
158
 
158
159
  desc 'scan', 'Test the workspace for problems'
@@ -284,7 +284,7 @@ module Solargraph
284
284
 
285
285
  FOLDING_NODE_TYPES = if Parser.rubyvm?
286
286
  %i[
287
- CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR
287
+ CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR HASH ARRAY LIST
288
288
  ].freeze
289
289
  else
290
290
  %i[
@@ -345,18 +345,22 @@ module Solargraph
345
345
 
346
346
  # @param top [Parser::AST::Node]
347
347
  # @param result [Array<Range>]
348
+ # @param parent [Symbol]
348
349
  # @return [void]
349
- def inner_folding_ranges top, result = []
350
+ def inner_folding_ranges top, result = [], parent = nil
350
351
  # return unless top.is_a?(::Parser::AST::Node)
351
352
  return unless Parser.is_ast_node?(top)
352
353
  if FOLDING_NODE_TYPES.include?(top.type)
353
- range = Range.from_node(top)
354
- if result.empty? || range.start.line > result.last.start.line
355
- result.push range unless range.ending.line - range.start.line < 2
354
+ # @todo Smelly exception for hash's first-level array in RubyVM
355
+ unless [:ARRAY, :LIST].include?(top.type) && parent == :HASH
356
+ range = Range.from_node(top)
357
+ if result.empty? || range.start.line > result.last.start.line
358
+ result.push range unless range.ending.line - range.start.line < 2
359
+ end
356
360
  end
357
361
  end
358
362
  top.children.each do |child|
359
- inner_folding_ranges(child, result)
363
+ inner_folding_ranges(child, result, top.type)
360
364
  end
361
365
  end
362
366
 
@@ -110,18 +110,21 @@ module Solargraph
110
110
  # @param api_map [ApiMap]
111
111
  # @return [ComplexType]
112
112
  def infer_first_defined pins, context, api_map
113
- type = ComplexType::UNDEFINED
113
+ possibles = []
114
114
  pins.each do |pin|
115
115
  # Avoid infinite recursion
116
116
  next if @@inference_stack.include?(pin.identity)
117
117
  @@inference_stack.push pin.identity
118
118
  type = pin.typify(api_map)
119
119
  @@inference_stack.pop
120
- break if type.defined?
120
+ if type.defined?
121
+ possibles.push type
122
+ break if pin.is_a?(Pin::Method)
123
+ end
121
124
  end
122
- if type.undefined?
125
+ if possibles.empty?
123
126
  # Limit method inference recursion
124
- return type if @@inference_depth >= 10 && pins.first.is_a?(Pin::BaseMethod)
127
+ return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
125
128
  @@inference_depth += 1
126
129
  pins.each do |pin|
127
130
  # Avoid infinite recursion
@@ -129,10 +132,20 @@ module Solargraph
129
132
  @@inference_stack.push pin.identity
130
133
  type = pin.probe(api_map)
131
134
  @@inference_stack.pop
132
- break if type.defined?
135
+ if type.defined?
136
+ possibles.push type
137
+ break if pin.is_a?(Pin::Method)
138
+ end
133
139
  end
134
140
  @@inference_depth -= 1
135
141
  end
142
+ return ComplexType::UNDEFINED if possibles.empty?
143
+ type = if possibles.length > 1
144
+ sorted = possibles.map { |t| t.rooted? ? "::#{t}" : t.to_s }.sort { |a, _| a == 'nil' ? 1 : 0 }
145
+ ComplexType.parse(*sorted)
146
+ else
147
+ possibles.first
148
+ end
136
149
  return type if context.nil? || context.return_type.undefined?
137
150
  type.self_to(context.return_type.namespace)
138
151
  end
@@ -30,7 +30,7 @@ module Solargraph
30
30
  @source = source.dup
31
31
  @pins = pins
32
32
  @locals = locals
33
- environ.merge Convention.for(source)
33
+ environ.merge Convention.for_local(self) unless filename.nil?
34
34
  @pin_class_hash = pins.to_set.classify(&:class).transform_values(&:to_a)
35
35
  @pin_select_cache = {}
36
36
  end
@@ -168,6 +168,9 @@ module Solargraph
168
168
  position = Position.new(line, character)
169
169
  found = nil
170
170
  pins.each do |pin|
171
+ # @todo Attribute pins should not be treated like closures, but
172
+ # there's probably a better way to handle it
173
+ next if pin.is_a?(Pin::Method) && pin.attribute?
171
174
  found = pin if (klasses.empty? || klasses.any? { |kls| pin.is_a?(kls) } ) && pin.location.range.contain?(position)
172
175
  break if pin.location.range.start.line > line
173
176
  end
@@ -149,7 +149,7 @@ module Solargraph
149
149
  frag_start = cursor.start_of_word.to_s.downcase
150
150
  filtered = result.uniq(&:name).select { |s|
151
151
  s.name.downcase.start_with?(frag_start) &&
152
- (!s.is_a?(Pin::BaseMethod) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
152
+ (!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
153
153
  }
154
154
  Completion.new(filtered, cursor.range)
155
155
  end
@@ -212,7 +212,8 @@ module Solargraph
212
212
  result.concat api_map.get_constants(context_pin.context.namespace, *gates)
213
213
  result.concat api_map.get_methods(block.binder.namespace, scope: block.binder.scope, visibility: [:public, :private, :protected])
214
214
  result.concat api_map.get_methods('Kernel')
215
- result.concat ApiMap.keywords
215
+ # result.concat ApiMap.keywords
216
+ result.concat api_map.keyword_pins
216
217
  result.concat yielded_self_pins
217
218
  end
218
219
  end
@@ -126,27 +126,31 @@ module Solargraph
126
126
  namespace = closure_at(source_position)
127
127
  t = (directive.tag.types.nil? || directive.tag.types.empty?) ? nil : directive.tag.types.flatten.join('')
128
128
  if t.nil? || t.include?('r')
129
- pins.push Solargraph::Pin::Attribute.new(
129
+ pins.push Solargraph::Pin::Method.new(
130
130
  location: location,
131
131
  closure: namespace,
132
132
  name: directive.tag.name,
133
133
  comments: docstring.all.to_s,
134
- access: :reader,
135
134
  scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
136
135
  visibility: :public,
137
- explicit: false
136
+ explicit: false,
137
+ attribute: true
138
138
  )
139
139
  end
140
140
  if t.nil? || t.include?('w')
141
- pins.push Solargraph::Pin::Attribute.new(
141
+ pins.push Solargraph::Pin::Method.new(
142
142
  location: location,
143
143
  closure: namespace,
144
144
  name: "#{directive.tag.name}=",
145
145
  comments: docstring.all.to_s,
146
- access: :writer,
147
146
  scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
148
- visibility: :public
147
+ visibility: :public,
148
+ attribute: true
149
149
  )
150
+ pins.last.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
151
+ if pins.last.return_type.defined?
152
+ pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
153
+ end
150
154
  end
151
155
  when 'parse'
152
156
  begin
@@ -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_by_class(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
@@ -227,7 +224,7 @@ module Solargraph
227
224
  base = base.base
228
225
  end
229
226
  closest = found.typify(api_map) if found
230
- if !found || closest.defined? || internal?(found)
227
+ if !found || (closest.defined? && internal_or_core?(found))
231
228
  unless ignored_pins.include?(found)
232
229
  result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
233
230
  @marked_ranges.push rng
@@ -244,8 +241,8 @@ module Solargraph
244
241
  base = chain
245
242
  until base.links.length == 1 && base.undefined?
246
243
  pins = base.define(api_map, block_pin, locals)
247
- if pins.first.is_a?(Pin::BaseMethod)
248
- # @type [Pin::BaseMethod]
244
+ if pins.first.is_a?(Pin::Method)
245
+ # @type [Pin::Method]
249
246
  pin = pins.first
250
247
  ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
251
248
  arity_problems_for(pin, fake_args_for(block_pin), location)
@@ -313,7 +310,6 @@ module Solargraph
313
310
  end
314
311
  else
315
312
  if par.decl == :kwarg
316
- # @todo Problem: missing required keyword argument
317
313
  result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
318
314
  end
319
315
  end
@@ -360,9 +356,14 @@ module Solargraph
360
356
 
361
357
  # @param pin [Pin::Base]
362
358
  def internal? pin
359
+ return false if pin.nil?
363
360
  pin.location && api_map.bundled?(pin.location.filename)
364
361
  end
365
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
+
366
367
  # @param pin [Pin::Base]
367
368
  def external? pin
368
369
  !internal? pin
@@ -395,7 +396,7 @@ module Solargraph
395
396
  true
396
397
  end
397
398
 
398
- # @param pin [Pin::BaseMethod]
399
+ # @param pin [Pin::Method]
399
400
  def arity_problems_for(pin, arguments, location)
400
401
  return [] unless pin.explicit?
401
402
  return [] if pin.parameters.empty? && arguments.empty?
@@ -410,29 +411,29 @@ module Solargraph
410
411
  if unchecked.empty? && pin.parameters.any? { |param| param.decl == :kwarg }
411
412
  return [Problem.new(location, "Missing keyword arguments to #{pin.path}")]
412
413
  end
414
+ settled_kwargs = 0
413
415
  unless unchecked.empty?
414
416
  kwargs = convert_hash(unchecked.last.node)
415
- # unless kwargs.empty?
416
- if pin.parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
417
- if kwargs.empty?
418
- add_params += 1
419
- else
420
- unchecked.pop
421
- pin.parameters.each do |param|
422
- next unless param.keyword?
423
- if kwargs.key?(param.name.to_sym)
424
- kwargs.delete param.name.to_sym
425
- elsif param.decl == :kwarg
426
- return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
427
- end
428
- end
429
- kwargs.clear if pin.parameters.any?(&:kwrestarg?)
430
- unless kwargs.empty?
431
- 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}")]
432
429
  end
433
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
434
435
  end
435
- # end
436
+ end
436
437
  end
437
438
  req = required_param_count(pin)
438
439
  if req + add_params < unchecked.length
@@ -443,23 +444,18 @@ module Solargraph
443
444
  return []
444
445
  end
445
446
  return [Problem.new(location, "Too many arguments to #{pin.path}")]
446
- elsif unchecked.length < req && (arguments.empty? || !arguments.last.splat?)
447
+ elsif unchecked.length < req - settled_kwargs && (arguments.empty? || !arguments.last.splat?)
447
448
  return [Problem.new(location, "Not enough arguments to #{pin.path}")]
448
449
  end
449
450
  []
450
451
  end
451
452
 
452
- # @param pin [Pin::BaseMethod]
453
+ # @param pin [Pin::Method]
453
454
  def required_param_count(pin)
454
- count = 0
455
- pin.parameters.each do |param|
456
- break unless param.decl == :arg
457
- count += 1
458
- end
459
- count
455
+ pin.parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
460
456
  end
461
457
 
462
- # @param pin [Pin::BaseMethod]
458
+ # @param pin [Pin::Method]
463
459
  def optional_param_count(pin)
464
460
  count = 0
465
461
  pin.parameters.each do |param|
@@ -20,7 +20,7 @@ module Solargraph
20
20
  class << self
21
21
  # Get an array of ParamDefs from a method pin.
22
22
  #
23
- # @param pin [Solargraph::Pin::BaseMethod]
23
+ # @param pin [Solargraph::Pin::Method]
24
24
  # @return [Array<ParamDef>]
25
25
  def from pin
26
26
  result = []
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.39.13'
4
+ VERSION = '0.40.0'
5
5
  end
@@ -10,11 +10,15 @@ module Solargraph
10
10
  # stdlib, and gems.
11
11
  #
12
12
  class YardMap
13
- autoload :Cache, 'solargraph/yard_map/cache'
14
- autoload :CoreDocs, 'solargraph/yard_map/core_docs'
15
- autoload :CoreGen, 'solargraph/yard_map/core_gen'
16
- autoload :Mapper, 'solargraph/yard_map/mapper'
17
- autoload :RdocToYard, 'solargraph/yard_map/rdoc_to_yard'
13
+ autoload :Cache, 'solargraph/yard_map/cache'
14
+ autoload :CoreDocs, 'solargraph/yard_map/core_docs'
15
+ autoload :CoreGen, 'solargraph/yard_map/core_gen'
16
+ autoload :Mapper, 'solargraph/yard_map/mapper'
17
+ autoload :RdocToYard, 'solargraph/yard_map/rdoc_to_yard'
18
+ autoload :CoreFills, 'solargraph/yard_map/core_fills'
19
+ autoload :StdlibFills, 'solargraph/yard_map/stdlib_fills'
20
+ autoload :Helpers, 'solargraph/yard_map/helpers'
21
+ autoload :ToMethod, 'solargraph/yard_map/to_method'
18
22
 
19
23
  CoreDocs.require_minimum
20
24
 
@@ -50,6 +54,8 @@ module Solargraph
50
54
  def initialize(required: [], gemset: {}, with_dependencies: true)
51
55
  # HACK: YardMap needs its own copy of this array
52
56
  @required = required.clone
57
+ # HACK: Hardcoded YAML handling
58
+ @required.push 'psych' if @required.include?('yaml')
53
59
  @with_dependencies = with_dependencies
54
60
  @gem_paths = {}
55
61
  @stdlib_namespaces = []
@@ -74,6 +80,8 @@ module Solargraph
74
80
  # @param new_gemset [Hash{String => String}]
75
81
  # @return [Boolean]
76
82
  def change new_requires, new_gemset, source_gems = []
83
+ # HACK: Hardcoded YAML handling
84
+ new_requires.push 'psych' if new_requires.include?('yaml')
77
85
  if new_requires.uniq.sort == required.uniq.sort && new_gemset == gemset && @source_gems.uniq.sort == source_gems.uniq.sort
78
86
  false
79
87
  else
@@ -131,7 +139,7 @@ module Solargraph
131
139
  # @param path [String]
132
140
  # @return [Pin::Base]
133
141
  def path_pin path
134
- pins.select{ |p| p.path == path }.first
142
+ pins.select { |p| p.path == path }.first
135
143
  end
136
144
 
137
145
  # Get the location of a file referenced by a require path.
@@ -151,6 +159,10 @@ module Solargraph
151
159
  nil
152
160
  end
153
161
 
162
+ def stdlib_pins
163
+ @stdlib_pins ||= []
164
+ end
165
+
154
166
  private
155
167
 
156
168
  # @return [YardMap::Cache]
@@ -158,10 +170,12 @@ module Solargraph
158
170
  @cache ||= YardMap::Cache.new
159
171
  end
160
172
 
173
+ # @return [Hash]
161
174
  def pin_class_hash
162
175
  @pin_class_hash ||= pins.to_set.classify(&:class).transform_values(&:to_a)
163
176
  end
164
177
 
178
+ # @return [Array<Pin::Base>]
165
179
  def pins_by_class klass
166
180
  @pin_select_cache[klass] ||= pin_class_hash.select { |key, _| key <= klass }.values.flatten
167
181
  end
@@ -179,12 +193,13 @@ module Solargraph
179
193
 
180
194
  # @return [void]
181
195
  def process_requires
182
- pins.clear
196
+ pins.replace core_pins
183
197
  unresolved_requires.clear
184
- # stdnames = {}
198
+ stdlib_pins.clear
199
+ environ = Convention.for_global(self)
185
200
  done = []
186
201
  from_std = []
187
- required.each do |r|
202
+ (required + environ.requires).each do |r|
188
203
  next if r.nil? || r.empty? || done.include?(r)
189
204
  done.push r
190
205
  cached = cache.get_path_pins(r)
@@ -209,7 +224,6 @@ module Solargraph
209
224
  yardocs.unshift yd
210
225
  result.concat process_yardoc yd, spec
211
226
  result.concat add_gem_dependencies(spec) if with_dependencies?
212
- stdlib_fill r, result
213
227
  end
214
228
  rescue Gem::LoadError => e
215
229
  base = r.split('/').first
@@ -219,7 +233,7 @@ module Solargraph
219
233
  if stdtmp.empty?
220
234
  unresolved_requires.push r
221
235
  else
222
- stdlib_fill base, stdtmp
236
+ stdlib_pins.concat stdtmp
223
237
  result.concat stdtmp
224
238
  end
225
239
  end
@@ -229,7 +243,13 @@ module Solargraph
229
243
  pins.concat result
230
244
  end
231
245
  end
232
- pins.concat core_pins
246
+ if required.include?('yaml') && required.include?('psych')
247
+ # HACK: Hardcoded YAML handling
248
+ # @todo Why can't this be handled with an override or a virtual pin?
249
+ pin = path_pin('YAML')
250
+ pin.instance_variable_set(:@return_type, ComplexType.parse('Module<Psych>')) unless pin.nil?
251
+ end
252
+ pins.concat environ.pins
233
253
  end
234
254
 
235
255
  # @param spec [Gem::Specification]
@@ -327,22 +347,6 @@ module Solargraph
327
347
  spec
328
348
  end
329
349
 
330
- # @param path [String]
331
- # @param pins [Array<Pin::Base>]
332
- # @return [void]
333
- def stdlib_fill path, pins
334
- StdlibFills.get(path).each do |ovr|
335
- pin = pins.select { |p| p.path == ovr.name }.first
336
- next if pin.nil?
337
- (ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
338
- pin.docstring.delete_tags tag.to_sym
339
- end
340
- ovr.tags.each do |tag|
341
- pin.docstring.add_tag(tag)
342
- end
343
- end
344
- end
345
-
346
350
  def load_core_pins
347
351
  yd = CoreDocs.yardoc_file
348
352
  ser = File.join(File.dirname(yd), 'core.ser')
@@ -360,23 +364,7 @@ module Solargraph
360
364
  else
361
365
  read_core_and_save_cache(yd, ser)
362
366
  end
363
- # HACK: Add Errno exception classes
364
- errno = result.select{ |pin| pin.path == 'Errno' }.first
365
- Errno.constants.each do |const|
366
- result.push Solargraph::Pin::Namespace.new(type: :class, name: const.to_s, closure: errno)
367
- result.push Solargraph::Pin::Reference::Superclass.new(closure: result.last, name: 'SystemCallError')
368
- end
369
- CoreFills::OVERRIDES.each do |ovr|
370
- pin = result.select { |p| p.path == ovr.name }.first
371
- next if pin.nil?
372
- (ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
373
- pin.docstring.delete_tags tag.to_sym
374
- end
375
- ovr.tags.each do |tag|
376
- pin.docstring.add_tag(tag)
377
- end
378
- end
379
- result
367
+ ApiMap::Store.new(result + CoreFills::ALL).pins.reject { |pin| pin.is_a?(Pin::Reference::Override) }
380
368
  end
381
369
 
382
370
  def read_core_and_save_cache yd, ser
@@ -384,7 +372,7 @@ module Solargraph
384
372
  load_yardoc yd
385
373
  result.concat Mapper.new(YARD::Registry.all).map
386
374
  # HACK: Assume core methods with a single `args` parameter accept restarg
387
- result.select { |pin| pin.is_a?(Solargraph::Pin::BaseMethod )}.each do |pin|
375
+ result.select { |pin| pin.is_a?(Solargraph::Pin::Method )}.each do |pin|
388
376
  if pin.parameters.length == 1 && pin.parameters.first.name == 'args' && pin.parameters.first.decl == :arg
389
377
  # @todo Smelly instance variable access
390
378
  pin.parameters.first.instance_variable_set(:@decl, :restarg)
@@ -403,7 +391,7 @@ module Solargraph
403
391
 
404
392
  def load_stdlib_pins base
405
393
  ser = File.join(File.dirname(CoreDocs.yardoc_stdlib_file), "#{base}.ser")
406
- if File.file?(ser)
394
+ result = if File.file?(ser)
407
395
  Solargraph.logger.info "Loading #{base} stdlib from cache"
408
396
  file = File.open(ser, 'rb')
409
397
  dump = file.read
@@ -418,6 +406,11 @@ module Solargraph
418
406
  else
419
407
  read_stdlib_and_save_cache(base, ser)
420
408
  end
409
+ fills = StdlibFills.get(base)
410
+ unless fills.empty?
411
+ result = ApiMap::Store.new(result + fills).pins.reject { |pin| pin.is_a?(Pin::Reference::Override) }
412
+ end
413
+ result
421
414
  end
422
415
 
423
416
  def read_stdlib_and_save_cache base, ser