solargraph 0.44.0 → 0.44.1

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: '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