solargraph 0.44.0 → 0.44.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0827e2be47eea923c2f61688ce4e97efa11d3d801f094ffb8a6cdb73a7fb52b3'
4
- data.tar.gz: dcbad1eaa64acab63ccc511a93c0e1370fc469815e2e67735fc79c2f4dc08038
3
+ metadata.gz: 346926f891270e103d6c7170fe5897587c1d5da45ea33b2a7f4238914b38b236
4
+ data.tar.gz: 451b09bf70dc9d760ebfdeb726821e6e653f196bd867da8c7638888803e33a72
5
5
  SHA512:
6
- metadata.gz: fa050d901186e2385685d2aab7934f611517d68b549f4cb064ab7c3524f99e890488675a06483c2b1f2e2cafc0417a3367972a1ea8b6c6614a3465e867313b03
7
- data.tar.gz: 4b12d6b0f65f53afd0ccbbdfc84a9fe8159f2f3a4bb3c625a84f1a9ee80be53f8c8b1d1ecfbae9bcf01ceff691388af5d0cef7271bb5470730fc4aa7a2471df9
6
+ metadata.gz: 624d1de49ef2762477d7a413adf282a058143a71689ea8cdfcc91177db94c765b997fca00fefd8d0d4915e44e6cd4ae1867297671611ba6d119d610116c5b80a
7
+ data.tar.gz: 9f146a371e075407cb8be7b96de08ff24583cf18eb1a29310c1a711c1bd347715d07b0ff6603e9a98b71be7406148e17c907abdcf3bd1a2aba58bd5aeff14685
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.44.1 - November 18, 2021
2
+ - Chain nil safety navigation operator (#420)
3
+ - Update closure and context for class_eval receiver (#487)
4
+ - SourceMap::Mapper handles invalid byte sequences (#474)
5
+ - Special handle var= references, which may use as var = (have space) (#498)
6
+ - Rebind define_method to self (#494)
7
+
1
8
  ## 0.44.0 - September 27, 2021
2
9
  - Allow opening parenthesis, space, and comma when using Diff::LCS (#465)
3
10
  - Support textDocument/documentHighlight
@@ -87,6 +87,10 @@ module Solargraph
87
87
  ComplexType.parse(*result.map(&:tag))
88
88
  end
89
89
 
90
+ def nullable?
91
+ @items.any?(&:nil_type?)
92
+ end
93
+
90
94
  private
91
95
 
92
96
  # @todo This is a quick and dirty hack that forces `self` keywords
@@ -31,7 +31,7 @@ module Solargraph
31
31
  # @param code [String]
32
32
  # @return [Array(Array<String>, Array<String>)]
33
33
  def generate_options filename, code
34
- args = ['-f', 'j', filename]
34
+ args = ['-f', 'j', '--force-exclusion', filename]
35
35
  base_options = RuboCop::Options.new
36
36
  options, paths = base_options.parse(args)
37
37
  options[:stdin] = code
@@ -71,6 +71,23 @@ module Solargraph
71
71
  else
72
72
  raise "No idea what to do with #{n}"
73
73
  end
74
+ elsif n.type == :csend
75
+ if n.children[0].is_a?(::Parser::AST::Node)
76
+ result.concat generate_links(n.children[0])
77
+ args = []
78
+ n.children[2..-1].each do |c|
79
+ args.push NodeChainer.chain(c)
80
+ end
81
+ result.push Chain::QCall.new(n.children[1].to_s, args, @in_block > 0 || block_passed?(n))
82
+ elsif n.children[0].nil?
83
+ args = []
84
+ n.children[2..-1].each do |c|
85
+ args.push NodeChainer.chain(c)
86
+ end
87
+ result.push Chain::QCall.new(n.children[1].to_s, args, @in_block > 0 || block_passed?(n))
88
+ else
89
+ raise "No idea what to do with #{n}"
90
+ end
74
91
  elsif n.type == :self
75
92
  result.push Chain::Head.new('self')
76
93
  elsif n.type == :zsuper
@@ -5,15 +5,39 @@ module Solargraph
5
5
  module Legacy
6
6
  module NodeProcessors
7
7
  class BlockNode < Parser::NodeProcessor::Base
8
+ include Legacy::NodeMethods
9
+
8
10
  def process
11
+ if other_class_eval?
12
+ other_class = Solargraph::Pin::Namespace.new(
13
+ type: :class,
14
+ name: unpack_name(node.children[0].children[0])
15
+ )
16
+ make_block_in other_class.context
17
+ process_children region.update(closure: other_class)
18
+ else
19
+ make_block_in nil
20
+ process_children region.update(closure: pins.last)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def other_class_eval?
27
+ node.children[0].type == :send &&
28
+ node.children[0].children[1] == :class_eval &&
29
+ [:cbase, :const].include?(node.children[0].children[0]&.type)
30
+ end
31
+
32
+ def make_block_in context
9
33
  pins.push Solargraph::Pin::Block.new(
10
34
  location: get_node_location(node),
35
+ context: context,
11
36
  closure: region.closure,
12
37
  receiver: node.children[0],
13
38
  comments: comments_for(node),
14
39
  scope: region.scope || region.closure.context.scope
15
40
  )
16
- process_children region.update(closure: pins.last)
17
41
  end
18
42
  end
19
43
  end
@@ -40,11 +40,16 @@ module Solargraph
40
40
  # end
41
41
 
42
42
  def references source, name
43
+ if name.end_with?("=")
44
+ reg = /#{Regexp.escape name[0..-2]}\s*=/
45
+ extract_offset = ->(code, offset) { reg.match(code, offset).offset(0) }
46
+ else
47
+ extract_offset = ->(code, offset) { [soff = code.index(name, offset), soff + name.length] }
48
+ end
43
49
  inner_node_references(name, source.node).map do |n|
44
50
  rng = Range.from_node(n)
45
51
  offset = Position.to_offset(source.code, rng.start)
46
- soff = source.code.index(name, offset)
47
- eoff = soff + name.length
52
+ soff, eoff = extract_offset[source.code, offset]
48
53
  Location.new(
49
54
  source.filename,
50
55
  Range.new(
@@ -60,6 +60,11 @@ module Solargraph
60
60
  result.concat generate_links(c)
61
61
  end
62
62
  result.push Chain::Call.new(n.children[-2].to_s, node_to_argchains(n.children.last), @in_block > 0 || block_passed?(n))
63
+ elsif n.type == :QCALL
64
+ n.children[0..-3].each do |c|
65
+ result.concat generate_links(c)
66
+ end
67
+ result.push Chain::QCall.new(n.children[-2].to_s, node_to_argchains(n.children.last), @in_block > 0 || block_passed?(n))
63
68
  elsif n.type == :ATTRASGN
64
69
  result.concat generate_links(n.children[0])
65
70
  result.push Chain::Call.new(n.children[1].to_s, node_to_argchains(n.children[2]), @in_block > 0 || block_passed?(n))
@@ -5,15 +5,39 @@ module Solargraph
5
5
  module Rubyvm
6
6
  module NodeProcessors
7
7
  class BlockNode < Parser::NodeProcessor::Base
8
+ include NodeMethods
9
+
8
10
  def process
11
+ if other_class_eval?
12
+ other_class = Solargraph::Pin::Namespace.new(
13
+ type: :class,
14
+ name: unpack_name(node.children[0].children[0])
15
+ )
16
+ make_block_in other_class.context
17
+ process_children region.update(closure: other_class)
18
+ else
19
+ make_block_in nil
20
+ process_children region.update(closure: pins.last)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def other_class_eval?
27
+ node.children[0].type == :CALL &&
28
+ node.children[0].children[1] == :class_eval &&
29
+ [:COLON2, :CONST].include?(node.children[0].children[0].type)
30
+ end
31
+
32
+ def make_block_in context
9
33
  pins.push Solargraph::Pin::Block.new(
10
34
  location: get_node_location(node),
35
+ context: context,
11
36
  closure: region.closure,
12
37
  receiver: node.children[0],
13
38
  comments: comments_for(node),
14
39
  scope: region.scope || region.closure.context.scope
15
40
  )
16
- process_children region.update(closure: pins.last)
17
41
  end
18
42
  end
19
43
  end
@@ -8,9 +8,10 @@ module Solargraph
8
8
  # @return [Parser::AST::Node]
9
9
  attr_reader :receiver
10
10
 
11
- def initialize receiver: nil, args: [], **splat
11
+ def initialize receiver: nil, args: [], context: nil, **splat
12
12
  super(**splat)
13
13
  @receiver = receiver
14
+ @context = context
14
15
  @parameters = args
15
16
  end
16
17
 
@@ -44,15 +45,24 @@ module Solargraph
44
45
  return nil unless api_map.rebindable_method_names.include?(word)
45
46
  chain = Parser.chain(receiver, location.filename)
46
47
  locals = api_map.source_map(location.filename).locals_at(location)
47
- if ['instance_eval', 'instance_exec', 'class_eval', 'class_exec', 'module_eval', 'module_exec'].include?(chain.links.last.word)
48
+ links_last_word = chain.links.last.word
49
+ if %w[instance_eval instance_exec class_eval class_exec module_eval module_exec].include?(links_last_word)
48
50
  return chain.base.infer(api_map, self, locals)
49
- else
50
- receiver_pin = chain.define(api_map, self, locals).first
51
- if receiver_pin && receiver_pin.docstring
52
- ys = receiver_pin.docstring.tag(:yieldself)
53
- if ys && ys.types && !ys.types.empty?
54
- return ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
55
- end
51
+ end
52
+ if 'define_method' == links_last_word and chain.define(api_map, self, locals).first&.path == 'Module#define_method' # change class type to instance type
53
+ if chain.links.size > 1 # Class.define_method
54
+ ty = chain.base.infer(api_map, self, locals)
55
+ return Solargraph::ComplexType.parse(ty.namespace)
56
+ else # define_method without self
57
+ return Solargraph::ComplexType.parse(closure.binder.namespace)
58
+ end
59
+ end
60
+ # other case without early return, read block yieldself tags
61
+ receiver_pin = chain.define(api_map, self, locals).first
62
+ if receiver_pin && receiver_pin.docstring
63
+ ys = receiver_pin.docstring.tag(:yieldself)
64
+ if ys && ys.types && !ys.types.empty?
65
+ return ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
56
66
  end
57
67
  end
58
68
  nil
@@ -80,7 +80,7 @@ module Solargraph
80
80
  end
81
81
  end
82
82
  end
83
- sections.map(&:to_s).join
83
+ sections.map(&:to_s).join.strip
84
84
  end
85
85
  end
86
86
 
@@ -18,19 +18,7 @@ module Solargraph
18
18
  true
19
19
  end
20
20
 
21
- # @param other [Pin::Base] The caller's block
22
- # @param position [Position, Array(Integer, Integer)] The caller's position
23
- # @return [Boolean]
24
- def visible_from?(other, position)
25
- position = Position.normalize(position)
26
- other.filename == filename &&
27
- match_tags(other.full_context.tag, full_context.tag) &&
28
- (other == closure ||
29
- (closure.location.range.contain?(other.location.range.start) && closure.location.range.contain?(other.location.range.ending))
30
- ) &&
31
- presence.contain?(position)
32
- end
33
-
21
+ # @param other_closure [Pin::Closure]
34
22
  # @param other_loc [Location]
35
23
  def visible_at?(other_closure, other_loc)
36
24
  return true if location.filename == other_loc.filename &&
@@ -51,6 +51,10 @@ module Solargraph
51
51
  clone.mark_head(false)
52
52
  end
53
53
 
54
+ def nullable?
55
+ false
56
+ end
57
+
54
58
  protected
55
59
 
56
60
  # Mark whether this link is the head of a chain
@@ -0,0 +1,11 @@
1
+ module Solargraph
2
+ class Source
3
+ class Chain
4
+ class QCall < Call
5
+ def nullable?
6
+ true
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -11,6 +11,7 @@ module Solargraph
11
11
  class Chain
12
12
  autoload :Link, 'solargraph/source/chain/link'
13
13
  autoload :Call, 'solargraph/source/chain/call'
14
+ autoload :QCall, 'solargraph/source/chain/q_call'
14
15
  autoload :Variable, 'solargraph/source/chain/variable'
15
16
  autoload :ClassVariable, 'solargraph/source/chain/class_variable'
16
17
  autoload :Constant, 'solargraph/source/chain/constant'
@@ -76,7 +77,8 @@ module Solargraph
76
77
  # @return [ComplexType]
77
78
  def infer api_map, name_pin, locals
78
79
  pins = define(api_map, name_pin, locals)
79
- infer_first_defined(pins, links.last.last_context, api_map)
80
+ type = infer_first_defined(pins, links.last.last_context, api_map)
81
+ maybe_nil(type)
80
82
  end
81
83
 
82
84
  # @return [Boolean]
@@ -101,6 +103,10 @@ module Solargraph
101
103
  @splat
102
104
  end
103
105
 
106
+ def nullable?
107
+ links.any?(&:nullable?)
108
+ end
109
+
104
110
  private
105
111
 
106
112
  # @param pins [Array<Pin::Base>]
@@ -146,6 +152,13 @@ module Solargraph
146
152
  return type if context.nil? || context.return_type.undefined?
147
153
  type.self_to(context.return_type.namespace)
148
154
  end
155
+
156
+ # @param type [ComplexType]
157
+ def maybe_nil type
158
+ return type if type.undefined? || type.void? || type.nullable?
159
+ return type unless nullable?
160
+ ComplexType.try_parse("#{type}, nil")
161
+ end
149
162
  end
150
163
  end
151
164
  end
@@ -42,7 +42,6 @@ module Solargraph
42
42
  @version = version
43
43
  @domains = []
44
44
  begin
45
- # @node, @comments = Source.parse_with_comments(@code, filename)
46
45
  @node, @comments = Solargraph::Parser.parse_with_comments(@code, filename)
47
46
  @parsed = true
48
47
  rescue Parser::SyntaxError, EncodingError => e
@@ -336,7 +335,6 @@ module Solargraph
336
335
  # @param parent [Symbol]
337
336
  # @return [void]
338
337
  def inner_folding_ranges top, result = [], parent = nil
339
- # return unless top.is_a?(::Parser::AST::Node)
340
338
  return unless Parser.is_ast_node?(top)
341
339
  if FOLDING_NODE_TYPES.include?(top.type)
342
340
  # @todo Smelly exception for hash's first-level array in RubyVM
@@ -433,7 +431,6 @@ module Solargraph
433
431
  # @return [void]
434
432
  def inner_tree_at node, position, stack
435
433
  return if node.nil?
436
- # here = Range.from_to(node.loc.expression.line, node.loc.expression.column, node.loc.expression.last_line, node.loc.expression.last_column)
437
434
  here = Range.from_node(node)
438
435
  if here.contain?(position) || colonized(here, position, node)
439
436
  stack.unshift node
@@ -53,11 +53,7 @@ module Solargraph
53
53
  #
54
54
  # @return [Array<Solargraph::Pin::Base>]
55
55
  def locals
56
- loc_pos = context_pin.location.range.contain?(cursor.position) ? cursor.position : context_pin.location.range.ending
57
- adj_pos = Position.new(loc_pos.line, (loc_pos.column.zero? ? 0 : loc_pos.column - 1))
58
- @locals ||= source_map.locals.select { |pin|
59
- pin.visible_from?(block, adj_pos)
60
- }.reverse
56
+ @locals ||= source_map.locals_at(location)
61
57
  end
62
58
 
63
59
  def gates
@@ -92,6 +88,10 @@ module Solargraph
92
88
  @source_map ||= api_map.source_map(cursor.filename)
93
89
  end
94
90
 
91
+ def location
92
+ Location.new(source_map.filename, Solargraph::Range.new(cursor.position, cursor.position))
93
+ end
94
+
95
95
  # @return [Solargraph::Pin::Base]
96
96
  def block
97
97
  @block ||= source_map.locate_block_pin(cursor.node_position.line, cursor.node_position.character)
@@ -61,7 +61,7 @@ module Solargraph
61
61
  end
62
62
 
63
63
  def process_comment source_position, comment_position, comment
64
- return unless comment =~ MACRO_REGEXP
64
+ return unless comment.encode('UTF-8', invalid: :replace, replace: '?') =~ MACRO_REGEXP
65
65
  cmnt = remove_inline_comment_hashes(comment)
66
66
  parse = Solargraph::Source.parse_docstring(cmnt)
67
67
  last_line = 0
@@ -169,7 +169,7 @@ module Solargraph
169
169
  # @todo Handle parser errors in !parse directives
170
170
  end
171
171
  when 'domain'
172
- namespace = closure_at(source_position)
172
+ namespace = closure_at(source_position) || Pin::ROOT_PIN
173
173
  namespace.domains.concat directive.tag.types unless directive.tag.types.nil?
174
174
  when 'override'
175
175
  pins.push Pin::Reference::Override.new(location, directive.tag.name, docstring.tags)
@@ -182,7 +182,7 @@ module Solargraph
182
182
  started = false
183
183
  comment.lines.each { |l|
184
184
  # Trim the comment and minimum leading whitespace
185
- p = l.gsub(/^#/, '')
185
+ p = l.encode('UTF-8', invalid: :replace, replace: '?').gsub(/^#/, '')
186
186
  if num.nil? && !p.strip.empty?
187
187
  num = p.index(/[^ ]/)
188
188
  started = true
@@ -197,7 +197,7 @@ module Solargraph
197
197
 
198
198
  # @return [void]
199
199
  def process_comment_directives
200
- return unless @code =~ MACRO_REGEXP
200
+ return unless @code.encode('UTF-8', invalid: :replace, replace: '?') =~ MACRO_REGEXP
201
201
  code_lines = @code.lines
202
202
  @source.associated_comments.each do |line, comments|
203
203
  src_pos = line ? Position.new(line, code_lines[line].to_s.chomp.index(/[^\s]/) || 0) : Position.new(code_lines.length, 0)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.44.0'
4
+ VERSION = '0.44.1'
5
5
  end
@@ -88,7 +88,7 @@ module Solargraph
88
88
  @rebindable_method_names ||= pins_by_class(Pin::Method)
89
89
  .select { |pin| pin.comments && pin.comments.include?('@yieldself') }
90
90
  .map(&:name)
91
- .concat(['instance_eval', 'instance_exec', 'class_eval', 'class_exec', 'module_eval', 'module_exec'])
91
+ .concat(['instance_eval', 'instance_exec', 'class_eval', 'class_exec', 'module_eval', 'module_exec', 'define_method'])
92
92
  .to_set
93
93
  end
94
94
 
data/solargraph.gemspec CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |s|
34
34
  s.add_runtime_dependency 'tilt', '~> 2.0'
35
35
  s.add_runtime_dependency 'yard', '~> 0.9', '>= 0.9.24'
36
36
 
37
- s.add_development_dependency 'pry', '~> 0.11.3'
37
+ s.add_development_dependency 'pry'
38
38
  s.add_development_dependency 'public_suffix', '~> 3.1'
39
39
  s.add_development_dependency 'rspec', '~> 3.5', '>= 3.5.0'
40
40
  s.add_development_dependency 'simplecov', '~> 0.14'
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.44.0
4
+ version: 0.44.1
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-09-27 00:00:00.000000000 Z
11
+ date: 2021-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backport
@@ -222,16 +222,16 @@ dependencies:
222
222
  name: pry
223
223
  requirement: !ruby/object:Gem::Requirement
224
224
  requirements:
225
- - - "~>"
225
+ - - ">="
226
226
  - !ruby/object:Gem::Version
227
- version: 0.11.3
227
+ version: '0'
228
228
  type: :development
229
229
  prerelease: false
230
230
  version_requirements: !ruby/object:Gem::Requirement
231
231
  requirements:
232
- - - "~>"
232
+ - - ">="
233
233
  - !ruby/object:Gem::Version
234
- version: 0.11.3
234
+ version: '0'
235
235
  - !ruby/object:Gem::Dependency
236
236
  name: public_suffix
237
237
  requirement: !ruby/object:Gem::Requirement
@@ -510,6 +510,7 @@ files:
510
510
  - lib/solargraph/source/chain/link.rb
511
511
  - lib/solargraph/source/chain/literal.rb
512
512
  - lib/solargraph/source/chain/or.rb
513
+ - lib/solargraph/source/chain/q_call.rb
513
514
  - lib/solargraph/source/chain/variable.rb
514
515
  - lib/solargraph/source/chain/z_super.rb
515
516
  - lib/solargraph/source/change.rb