solargraph 0.42.4 → 0.43.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28ad96860cdfaaa7ce608149d111164649664a86e13567c63efb0218cac98bff
4
- data.tar.gz: 12f96ea8a87a97a98e0f91774bff44ff3c736fe5268cbdb959cfbf0ce70c53b6
3
+ metadata.gz: 89a1a9d76094688ff7ebe1af3dec4452c379819408ffc458eddcd75f5b66d2eb
4
+ data.tar.gz: 9b03143ba896ccd2d3bd0a44c9a1e90f06e3ed757a47a08e6b8aaf2a9f56e62e
5
5
  SHA512:
6
- metadata.gz: '00259fb37ec37b1090797678288f75fc9e1fd26db368d11f6e98f6c89b78745141d416a6a40cc507ce1f032056318c9f67946d9a6d9e17646aee0c9b54a1fd5d'
7
- data.tar.gz: 264c5b2e39c4f946f9e375b7d5ef17f97d42c7b6343aa632f1c0319e1a2c6b2b2d73dc50f31b7b863b55b814e0b089cfae63137e8548927e2e0935c4e3243402
6
+ metadata.gz: a6d4e99416af96a8a11ca569d096f4ba1491155f3fde1efc734e59c73d1794007d0b7b1e936c1dfb248472df1fa679c7701866176de99119e8f6a0b8eef721d4
7
+ data.tar.gz: edd612d341e6c9bb421e4bbb8db04badc855e924eca469c47943c374813025810151aca1abdd0da13100597803799a50c7355a362b8a0ae65187c0760464e840
data/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
- ## 0.42.4
1
+ ## 0.43.0 - July 25, 2021
2
+ - Correct arity checks when restarg precedes arg (#418)
3
+ - Improve the performance of catalog by 4 times (#457)
4
+ - Type checker validates duck type variables and params (#453)
5
+ - Kernel#raise exception type checker
6
+ - Pin::Base#inspect includes path
7
+ - Fix arity with combined restargs and kwrestargs (#396)
8
+
9
+ ## 0.42.4 - July 11, 2021
2
10
  - Yardoc cache handling
3
11
  - Fix required_paths when gemspec is used (#451)
4
12
  - fix: yard stdout may break language client (#454)
@@ -138,7 +138,7 @@ module Solargraph
138
138
 
139
139
  # An array of pins based on Ruby keywords (`if`, `end`, etc.).
140
140
  #
141
- # @return [Array<Solargraph::Pin::Keyword>]
141
+ # @return [Enumerable<Solargraph::Pin::Keyword>]
142
142
  def keyword_pins
143
143
  store.pins_by_class(Pin::Keyword)
144
144
  end
@@ -5,10 +5,10 @@ require 'set'
5
5
  module Solargraph
6
6
  class ApiMap
7
7
  class Store
8
- # @return [Array<Solargraph::Pin::Base>]
8
+ # @return [Enumerable<Solargraph::Pin::Base>]
9
9
  attr_reader :pins
10
10
 
11
- # @param pins [Array<Solargraph::Pin::Base>]
11
+ # @param pins [Enumerable<Solargraph::Pin::Base>]
12
12
  def initialize pins = []
13
13
  @pins = pins
14
14
  index
@@ -16,7 +16,7 @@ module Solargraph
16
16
 
17
17
  # @param fqns [String]
18
18
  # @param visibility [Array<Symbol>]
19
- # @return [Array<Solargraph::Pin::Base>]
19
+ # @return [Enumerable<Solargraph::Pin::Base>]
20
20
  def get_constants fqns, visibility = [:public]
21
21
  namespace_children(fqns).select { |pin|
22
22
  !pin.name.empty? && (pin.is_a?(Pin::Namespace) || pin.is_a?(Pin::Constant)) && visibility.include?(pin.visibility)
@@ -26,7 +26,7 @@ module Solargraph
26
26
  # @param fqns [String]
27
27
  # @param scope [Symbol]
28
28
  # @param visibility [Array<Symbol>]
29
- # @return [Array<Solargraph::Pin::Base>]
29
+ # @return [Enumerable<Solargraph::Pin::Base>]
30
30
  def get_methods fqns, scope: :instance, visibility: [:public]
31
31
  namespace_children(fqns).select do |pin|
32
32
  pin.is_a?(Pin::Method) && pin.scope == scope && visibility.include?(pin.visibility)
@@ -61,14 +61,14 @@ module Solargraph
61
61
  end
62
62
 
63
63
  # @param path [String]
64
- # @return [Array<Solargraph::Pin::Base>]
64
+ # @return [Enumerable<Solargraph::Pin::Base>]
65
65
  def get_path_pins path
66
66
  path_pin_hash[path] || []
67
67
  end
68
68
 
69
69
  # @param fqns [String]
70
70
  # @param scope [Symbol] :class or :instance
71
- # @return [Array<Solargraph::Pin::Base>]
71
+ # @return [Enumerable<Solargraph::Pin::Base>]
72
72
  def get_instance_variables(fqns, scope = :instance)
73
73
  all_instance_variables.select { |pin|
74
74
  pin.binder.namespace == fqns && pin.binder.scope == scope
@@ -76,12 +76,12 @@ module Solargraph
76
76
  end
77
77
 
78
78
  # @param fqns [String]
79
- # @return [Array<Solargraph::Pin::Base>]
79
+ # @return [Enumerable<Solargraph::Pin::Base>]
80
80
  def get_class_variables(fqns)
81
81
  namespace_children(fqns).select{|pin| pin.is_a?(Pin::ClassVariable)}
82
82
  end
83
83
 
84
- # @return [Array<Solargraph::Pin::Base>]
84
+ # @return [Enumerable<Solargraph::Pin::Base>]
85
85
  def get_symbols
86
86
  symbols.uniq(&:name)
87
87
  end
@@ -97,12 +97,12 @@ module Solargraph
97
97
  @namespaces ||= Set.new
98
98
  end
99
99
 
100
- # @return [Array<Solargraph::Pin::Base>]
100
+ # @return [Enumerable<Solargraph::Pin::Base>]
101
101
  def namespace_pins
102
102
  pins_by_class(Solargraph::Pin::Namespace)
103
103
  end
104
104
 
105
- # @return [Array<Solargraph::Pin::Method>]
105
+ # @return [Enumerable<Solargraph::Pin::Method>]
106
106
  def method_pins
107
107
  pins_by_class(Solargraph::Pin::Method)
108
108
  end
@@ -131,7 +131,7 @@ module Solargraph
131
131
  end
132
132
  end
133
133
 
134
- # @return [Array<Pin::Block>]
134
+ # @return [Enumerable<Pin::Block>]
135
135
  def block_pins
136
136
  pins_by_class(Pin::Block)
137
137
  end
@@ -142,9 +142,9 @@ module Solargraph
142
142
  end
143
143
 
144
144
  # @param klass [Class]
145
- # @return [Array<Solargraph::Pin::Base>]
145
+ # @return [Enumerable<Solargraph::Pin::Base>]
146
146
  def pins_by_class klass
147
- @pin_select_cache[klass] ||= @pin_class_hash.select { |key, _| key <= klass }.values.flatten
147
+ @pin_select_cache[klass] ||= @pin_class_hash.each_with_object(Set.new) { |(key, o), n| n.merge(o) if key <= klass }
148
148
  end
149
149
 
150
150
  private
@@ -171,7 +171,7 @@ module Solargraph
171
171
  end
172
172
  end
173
173
 
174
- # @return [Array<Solargraph::Pin::Symbol>]
174
+ # @return [Enumerable<Solargraph::Pin::Symbol>]
175
175
  def symbols
176
176
  pins_by_class(Pin::Symbol)
177
177
  end
@@ -193,7 +193,7 @@ module Solargraph
193
193
  end
194
194
 
195
195
  # @param name [String]
196
- # @return [Array<Solargraph::Pin::Base>]
196
+ # @return [Enumerable<Solargraph::Pin::Base>]
197
197
  def namespace_children name
198
198
  namespace_map[name] || []
199
199
  end
@@ -216,8 +216,8 @@ module Solargraph
216
216
  set = pins.to_set
217
217
  @pin_class_hash = set.classify(&:class).transform_values(&:to_a)
218
218
  @pin_select_cache = {}
219
- @namespace_map = set.classify(&:namespace).transform_values(&:to_a)
220
- @path_pin_hash = set.classify(&:path).transform_values(&:to_a)
219
+ @namespace_map = set.classify(&:namespace)
220
+ @path_pin_hash = set.classify(&:path)
221
221
  @namespaces = @path_pin_hash.keys.compact.to_set
222
222
  pins_by_class(Pin::Reference::Include).each do |pin|
223
223
  include_references[pin.namespace] ||= []
@@ -51,6 +51,10 @@ module Solargraph
51
51
  def select &block
52
52
  @items.select &block
53
53
  end
54
+ def namespace
55
+ # cache this attr for high frequency call
56
+ @namespace ||= method_missing(:namespace).to_s
57
+ end
54
58
 
55
59
  def method_missing name, *args, &block
56
60
  return if @items.first.nil?
@@ -72,9 +72,12 @@ module Solargraph
72
72
 
73
73
  # @return [String]
74
74
  def namespace
75
- @namespace ||= 'Object' if duck_type?
76
- @namespace ||= 'NilClass' if nil_type?
77
- @namespace ||= (name == 'Class' || name == 'Module') && !subtypes.empty? ? subtypes.first.name : name
75
+ # if priority higher than ||=, old implements cause unnecessary check
76
+ @namespace ||= lambda do
77
+ return 'Object' if duck_type?
78
+ return 'NilClass' if nil_type?
79
+ return (name == 'Class' || name == 'Module') && !subtypes.empty? ? subtypes.first.name : name
80
+ end.call
78
81
  end
79
82
 
80
83
  # @return [Symbol] :class or :instance
@@ -41,7 +41,8 @@ module Solargraph
41
41
  result = explicit_library_for(uri) ||
42
42
  implicit_library_for(uri) ||
43
43
  generic_library_for(uri)
44
- result.attach sources.find(uri) if sources.include?(uri)
44
+ # previous library for already call attach. avoid call twice
45
+ # result.attach sources.find(uri) if sources.include?(uri)
45
46
  result
46
47
  end
47
48
 
@@ -82,7 +83,6 @@ module Solargraph
82
83
  libraries.each do |lib|
83
84
  if filename.start_with?(lib.workspace.directory)
84
85
  lib.attach sources.find(uri)
85
- lib.catalog
86
86
  return lib
87
87
  end
88
88
  end
@@ -98,7 +98,6 @@ module Solargraph
98
98
  # @return [Library]
99
99
  def generic_library_for uri
100
100
  generic_library.attach sources.find(uri)
101
- generic_library.catalog
102
101
  generic_library
103
102
  end
104
103
 
@@ -56,7 +56,7 @@ module Solargraph
56
56
  end
57
57
  @current = source
58
58
  maybe_map @current
59
- api_map.catalog bench unless synchronized?
59
+ catalog_inlock
60
60
  end
61
61
  end
62
62
 
@@ -368,12 +368,16 @@ module Solargraph
368
368
  # @return [void]
369
369
  def catalog
370
370
  mutex.synchronize do
371
- break if synchronized?
371
+ catalog_inlock
372
+ end
373
+ end
374
+
375
+ private def catalog_inlock
376
+ return if synchronized?
372
377
  logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
373
378
  api_map.catalog bench
374
379
  @synchronized = true
375
380
  logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)" if logger.info?
376
- end
377
381
  end
378
382
 
379
383
  def bench
@@ -102,13 +102,26 @@ module Solargraph
102
102
  result.concat generate_links(n.children[0])
103
103
  elsif n.type == :block_pass
104
104
  result.push Chain::BlockVariable.new("&#{n.children[0].children[0].to_s}")
105
+ elsif n.type == :hash
106
+ result.push Chain::Hash.new('::Hash', hash_is_splatted?(n))
105
107
  else
106
108
  lit = infer_literal_node_type(n)
107
- result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
109
+ # if lit == '::Hash'
110
+ # result.push Chain::Hash.new(lit, hash_is_splatted?(n))
111
+ # else
112
+ result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
113
+ # end
108
114
  end
109
115
  result
110
116
  end
111
117
 
118
+ def hash_is_splatted? node
119
+ return false unless Parser.is_ast_node?(node) && node.type == :hash
120
+ return false unless Parser.is_ast_node?(node.children.last) && node.children.last.type == :kwsplat
121
+ return false if Parser.is_ast_node?(node.children.last.children[0]) && node.children.last.children[0].type == :hash
122
+ true
123
+ end
124
+
112
125
  def block_passed? node
113
126
  node.children.last.is_a?(::Parser::AST::Node) && node.children.last.type == :block_pass
114
127
  end
@@ -97,8 +97,10 @@ module Solargraph
97
97
  end
98
98
 
99
99
  def convert_hash node
100
- return {} unless Parser.is_ast_node?(node) && node.type == :hash
101
- return convert_hash(node.children[0].children[0]) if splatted_hash?(node)
100
+ return {} unless Parser.is_ast_node?(node)
101
+ return convert_hash(node.children[0]) if node.type == :kwsplat
102
+ return convert_hash(node.children[0]) if Parser.is_ast_node?(node.children[0]) && node.children[0].type == :kwsplat
103
+ return {} unless node.type == :hash
102
104
  result = {}
103
105
  node.children.each do |pair|
104
106
  result[pair.children[0].children[0]] = Solargraph::Parser.chain(pair.children[1])
@@ -124,9 +126,14 @@ module Solargraph
124
126
  end
125
127
 
126
128
  def splatted_call? node
129
+ return false unless Parser.is_ast_node?(node)
127
130
  Parser.is_ast_node?(node.children[0]) && node.children[0].type == :kwsplat && node.children[0].children[0].type != :hash
128
131
  end
129
132
 
133
+ def any_splatted_call?(nodes)
134
+ nodes.any? { |n| splatted_call?(n) }
135
+ end
136
+
130
137
  # @todo Temporarily here for testing. Move to Solargraph::Parser.
131
138
  def call_nodes_from node
132
139
  return [] unless node.is_a?(::Parser::AST::Node)
@@ -97,13 +97,31 @@ module Solargraph
97
97
  result.concat generate_links(n.children[0])
98
98
  elsif n.type == :BLOCK_PASS
99
99
  result.push Chain::BlockVariable.new("&#{n.children[1].children[0].to_s}")
100
+ elsif n.type == :HASH
101
+ result.push Chain::Hash.new('::Hash', hash_is_splatted?(n))
100
102
  else
101
103
  lit = infer_literal_node_type(n)
102
- result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
104
+ if lit
105
+ if lit == '::Hash'
106
+ result.push Chain::Hash.new(lit, hash_is_splatted?(n))
107
+ else
108
+ result.push Chain::Literal.new(lit)
109
+ end
110
+ else
111
+ result.push Chain::Link.new
112
+ end
113
+ # result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
103
114
  end
104
115
  result
105
116
  end
106
117
 
118
+ def hash_is_splatted? node
119
+ return false unless Parser.is_ast_node?(node.children[0]) && node.children[0].type == :LIST
120
+ list = node.children[0].children
121
+ eol = list.rindex(&:nil?)
122
+ eol && Parser.is_ast_node?(list[eol + 1])
123
+ end
124
+
107
125
  def block_passed? node
108
126
  node.children.last.is_a?(RubyVM::AbstractSyntaxTree::Node) && node.children.last.type == :BLOCK_PASS
109
127
  end
@@ -114,6 +132,9 @@ module Solargraph
114
132
  node.children[0..-2].map { |c| NodeChainer.chain(c) }
115
133
  elsif node.type == :SPLAT
116
134
  [NodeChainer.chain(node)]
135
+ elsif node.type == :ARGSPUSH
136
+ result = node_to_argchains(node.children[0])
137
+ result.push NodeChainer.chain(node.children[1]) if Parser.is_ast_node?(node.children[1])
117
138
  elsif node.type == :ARGSCAT
118
139
  result = node.children[0].children[0..-2].map { |c| NodeChainer.chain(c) }
119
140
  result.push NodeChainer.chain(node.children[1])
@@ -117,9 +117,14 @@ module Solargraph
117
117
  end
118
118
 
119
119
  def splatted_call? node
120
+ return false unless Parser.is_ast_node?(node)
120
121
  splatted_node?(node) && node.children[0].children[1].type != :HASH
121
122
  end
122
123
 
124
+ def any_splatted_call?(nodes)
125
+ nodes.any? { |n| splatted_call?(n) }
126
+ end
127
+
123
128
  def node? node
124
129
  node.is_a?(RubyVM::AbstractSyntaxTree::Node)
125
130
  end
@@ -218,7 +218,7 @@ module Solargraph
218
218
  end
219
219
 
220
220
  def inspect
221
- "#<#{self.class} at #{self.location.inspect}>"
221
+ "#<#{self.class} `#{self.path}` at #{self.location.inspect}>"
222
222
  end
223
223
 
224
224
  protected
@@ -21,6 +21,7 @@ module Solargraph
21
21
  autoload :Or, 'solargraph/source/chain/or'
22
22
  autoload :BlockVariable, 'solargraph/source/chain/block_variable'
23
23
  autoload :ZSuper, 'solargraph/source/chain/z_super'
24
+ autoload :Hash, 'solargraph/source/chain/hash'
24
25
 
25
26
  @@inference_stack = []
26
27
  @@inference_depth = 0
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ class Chain
6
+ class Hash < Literal
7
+ # @param type [String]
8
+ # @param splatted [Boolean]
9
+ def initialize type, splatted = false
10
+ super(type)
11
+ @splatted = splatted
12
+ end
13
+
14
+ def word
15
+ @word ||= "<#{@type}>"
16
+ end
17
+
18
+ def resolve api_map, name_pin, locals
19
+ [Pin::ProxyType.anonymous(@complex_type)]
20
+ end
21
+
22
+ def splatted?
23
+ @splatted
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -213,7 +213,7 @@ module Solargraph
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
215
  # result.concat ApiMap.keywords
216
- result.concat api_map.keyword_pins
216
+ result.concat api_map.keyword_pins.to_a
217
217
  result.concat yielded_self_pins
218
218
  end
219
219
  end
@@ -148,6 +148,7 @@ module Solargraph
148
148
  all_variables.each do |pin|
149
149
  if pin.return_type.defined?
150
150
  declared = pin.typify(api_map)
151
+ next if declared.duck_type?
151
152
  if declared.defined?
152
153
  if rules.validate_tags?
153
154
  inferred = pin.probe(api_map)
@@ -416,7 +417,7 @@ module Solargraph
416
417
  end
417
418
  settled_kwargs = 0
418
419
  unless unchecked.empty?
419
- if Parser.is_ast_node?(unchecked.last.node) && splatted_call?(unchecked.last.node)
420
+ if any_splatted_call?(unchecked.map(&:node))
420
421
  settled_kwargs = pin.parameters.count(&:keyword?)
421
422
  else
422
423
  kwargs = convert_hash(unchecked.last.node)
@@ -431,6 +432,7 @@ module Solargraph
431
432
  kwargs.delete param.name.to_sym
432
433
  settled_kwargs += 1
433
434
  elsif param.decl == :kwarg
435
+ return [] if arguments.last.links.last.is_a?(Solargraph::Source::Chain::Hash) && arguments.last.links.last.splatted?
434
436
  return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
435
437
  end
436
438
  end
@@ -450,12 +452,17 @@ module Solargraph
450
452
  if unchecked.length == req + opt + 1 && unchecked.last.links.last.is_a?(Source::Chain::BlockVariable)
451
453
  return []
452
454
  end
453
- if req + add_params + 1 == unchecked.length && splatted_call?(unchecked.last.node) && (pin.parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
455
+ if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (pin.parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
454
456
  return []
455
457
  end
458
+ return [] if arguments.length - req == pin.parameters.select { |p| [:optarg, :kwoptarg].include?(p.decl) }.length
456
459
  return [Problem.new(location, "Too many arguments to #{pin.path}")]
457
- elsif unchecked.length < req - settled_kwargs && (arguments.empty? || !arguments.last.splat?)
458
- return [Problem.new(location, "Not enough arguments to #{pin.path}")]
460
+ elsif unchecked.length < req - settled_kwargs && (arguments.empty? || (!arguments.last.splat? && !arguments.last.links.last.is_a?(Solargraph::Source::Chain::Hash)))
461
+ # HACK: Kernel#raise signature is incorrect in Ruby 2.7 core docs.
462
+ # See https://github.com/castwide/solargraph/issues/418
463
+ unless arguments.empty? && pin.path == 'Kernel#raise'
464
+ return [Problem.new(location, "Not enough arguments to #{pin.path}")]
465
+ end
459
466
  end
460
467
  []
461
468
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.42.4'
4
+ VERSION = '0.43.0'
5
5
  end
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.42.4
4
+ version: 0.43.0
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-07-11 00:00:00.000000000 Z
11
+ date: 2021-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backport
@@ -502,6 +502,7 @@ files:
502
502
  - lib/solargraph/source/chain/class_variable.rb
503
503
  - lib/solargraph/source/chain/constant.rb
504
504
  - lib/solargraph/source/chain/global_variable.rb
505
+ - lib/solargraph/source/chain/hash.rb
505
506
  - lib/solargraph/source/chain/head.rb
506
507
  - lib/solargraph/source/chain/instance_variable.rb
507
508
  - lib/solargraph/source/chain/link.rb