solargraph 0.54.0 → 0.54.5

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/lib/solargraph/api_map/cache.rb +10 -1
  4. data/lib/solargraph/api_map/index.rb +167 -0
  5. data/lib/solargraph/api_map/store.rb +72 -121
  6. data/lib/solargraph/api_map.rb +94 -36
  7. data/lib/solargraph/bench.rb +17 -1
  8. data/lib/solargraph/complex_type/type_methods.rb +17 -11
  9. data/lib/solargraph/complex_type/unique_type.rb +93 -10
  10. data/lib/solargraph/complex_type.rb +68 -18
  11. data/lib/solargraph/convention.rb +1 -0
  12. data/lib/solargraph/doc_map.rb +1 -0
  13. data/lib/solargraph/equality.rb +33 -0
  14. data/lib/solargraph/language_server/host/message_worker.rb +48 -5
  15. data/lib/solargraph/language_server/host.rb +12 -11
  16. data/lib/solargraph/language_server/message/base.rb +19 -12
  17. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  18. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  19. data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
  20. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  21. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -0
  22. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  23. data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
  24. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  25. data/lib/solargraph/language_server/progress.rb +19 -2
  26. data/lib/solargraph/library.rb +31 -41
  27. data/lib/solargraph/location.rb +21 -1
  28. data/lib/solargraph/parser/node_methods.rb +1 -1
  29. data/lib/solargraph/parser/node_processor.rb +1 -0
  30. data/lib/solargraph/parser/parser_gem/class_methods.rb +2 -6
  31. data/lib/solargraph/parser/parser_gem/node_methods.rb +3 -3
  32. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +23 -19
  33. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +8 -2
  34. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +1 -1
  35. data/lib/solargraph/parser.rb +2 -5
  36. data/lib/solargraph/pin/base.rb +41 -17
  37. data/lib/solargraph/pin/base_variable.rb +4 -3
  38. data/lib/solargraph/pin/block.rb +6 -26
  39. data/lib/solargraph/pin/callable.rb +147 -0
  40. data/lib/solargraph/pin/closure.rb +8 -3
  41. data/lib/solargraph/pin/common.rb +2 -6
  42. data/lib/solargraph/pin/conversions.rb +3 -2
  43. data/lib/solargraph/pin/instance_variable.rb +2 -2
  44. data/lib/solargraph/pin/method.rb +57 -31
  45. data/lib/solargraph/pin/namespace.rb +5 -5
  46. data/lib/solargraph/pin/parameter.rb +11 -12
  47. data/lib/solargraph/pin/proxy_type.rb +1 -1
  48. data/lib/solargraph/pin/signature.rb +3 -129
  49. data/lib/solargraph/pin.rb +4 -1
  50. data/lib/solargraph/position.rb +7 -0
  51. data/lib/solargraph/range.rb +9 -4
  52. data/lib/solargraph/rbs_map/conversions.rb +77 -38
  53. data/lib/solargraph/rbs_map/core_fills.rb +6 -6
  54. data/lib/solargraph/rbs_map.rb +1 -0
  55. data/lib/solargraph/shell.rb +19 -2
  56. data/lib/solargraph/source/chain/array.rb +7 -6
  57. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  58. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  59. data/lib/solargraph/source/chain/call.rb +90 -55
  60. data/lib/solargraph/source/chain/hash.rb +5 -0
  61. data/lib/solargraph/source/chain/if.rb +5 -0
  62. data/lib/solargraph/source/chain/link.rb +26 -5
  63. data/lib/solargraph/source/chain/literal.rb +5 -0
  64. data/lib/solargraph/source/chain/or.rb +1 -1
  65. data/lib/solargraph/source/chain.rb +68 -30
  66. data/lib/solargraph/source/cursor.rb +3 -2
  67. data/lib/solargraph/source.rb +104 -86
  68. data/lib/solargraph/source_map/clip.rb +5 -5
  69. data/lib/solargraph/source_map/data.rb +30 -0
  70. data/lib/solargraph/source_map.rb +28 -16
  71. data/lib/solargraph/type_checker/rules.rb +6 -1
  72. data/lib/solargraph/type_checker.rb +15 -15
  73. data/lib/solargraph/version.rb +1 -1
  74. data/lib/solargraph/views/environment.erb +3 -5
  75. data/lib/solargraph/workspace/config.rb +7 -3
  76. data/lib/solargraph/workspace.rb +1 -1
  77. data/lib/solargraph/yard_map/mapper/to_constant.rb +1 -0
  78. data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
  79. data/lib/solargraph/yard_map/mapper.rb +1 -0
  80. data/lib/solargraph/yardoc.rb +1 -1
  81. data/lib/solargraph.rb +1 -0
  82. data/solargraph.gemspec +5 -5
  83. metadata +29 -25
@@ -5,10 +5,17 @@ require 'solargraph/source/chain/link'
5
5
 
6
6
  module Solargraph
7
7
  class Source
8
- # A chain of constants, variables, and method calls for inferring types of
9
- # values.
8
+ #
9
+ # Represents an expression as a single call chain at the parse
10
+ # tree level, made up of constants, variables, and method calls,
11
+ # each represented as a Link object.
12
+ #
13
+ # Computes Pins and/or ComplexTypes representing the interpreted
14
+ # expression.
10
15
  #
11
16
  class Chain
17
+ include Equality
18
+
12
19
  autoload :Link, 'solargraph/source/chain/link'
13
20
  autoload :Call, 'solargraph/source/chain/call'
14
21
  autoload :QCall, 'solargraph/source/chain/q_call'
@@ -40,6 +47,11 @@ module Solargraph
40
47
 
41
48
  attr_reader :node
42
49
 
50
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
51
+ protected def equality_fields
52
+ [links, node]
53
+ end
54
+
43
55
  # @param node [Parser::AST::Node, nil]
44
56
  # @param links [::Array<Chain::Link>]
45
57
  # @param splat [Boolean]
@@ -61,13 +73,31 @@ module Solargraph
61
73
  @base ||= Chain.new(links[0..-2])
62
74
  end
63
75
 
76
+ # Determine potential Pins returned by this chain of words
77
+ #
64
78
  # @param api_map [ApiMap]
65
- # @param name_pin [Pin::Base]
66
- # @param locals [::Enumerable<Pin::LocalVariable>]
79
+ # @param name_pin [Pin::Closure] the surrounding closure pin for
80
+ # the statement represented by this chain for type resolution
81
+ # and method pin lookup.
82
+ #
83
+ # For method calls (Chain::Call objects) as the first element
84
+ # in the chain, 'name_pin.binder' should return the
85
+ # ComplexType representing the LHS / "self type" of the call.
67
86
  #
68
- # @return [::Array<Pin::Base>]
87
+ # @param locals [::Enumerable<Pin::LocalVariable>] Any local
88
+ # variables / method parameters etc visible by the statement
89
+ #
90
+ # @return [::Array<Pin::Base>] Pins representing possible return
91
+ # types of this method.
69
92
  def define api_map, name_pin, locals
70
93
  return [] if undefined?
94
+
95
+ # working_pin is the surrounding closure pin for the link
96
+ # being processed, whose #binder method will provide the LHS /
97
+ # 'self type' of the next link (same as the #return_type method
98
+ # --the type of the result so far).
99
+ #
100
+ # @todo ProxyType uses 'type' for the binder, but '
71
101
  working_pin = name_pin
72
102
  links[0..-2].each do |link|
73
103
  pins = link.resolve(api_map, working_pin, locals)
@@ -75,37 +105,34 @@ module Solargraph
75
105
  return [] if type.undefined?
76
106
  working_pin = Pin::ProxyType.anonymous(type)
77
107
  end
78
- links.last.last_context = name_pin
108
+ links.last.last_context = working_pin
79
109
  links.last.resolve(api_map, working_pin, locals)
80
110
  end
81
111
 
82
112
  # @param api_map [ApiMap]
83
113
  # @param name_pin [Pin::Base]
84
- # @param locals [::Enumerable<Pin::LocalVariable>]
114
+ # @param locals [::Array<Pin::LocalVariable>]
85
115
  # @return [ComplexType]
86
116
  # @sg-ignore
87
117
  def infer api_map, name_pin, locals
88
- out = nil
89
- cached = @@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] unless node.nil?
90
- return cached if cached && @@inference_invalidation_key == api_map.hash
91
- out = infer_uncached api_map, name_pin, locals
92
- if @@inference_invalidation_key != api_map.hash
93
- @@inference_cache = {}
118
+ cache_key = [node, node&.location, links, name_pin&.return_type, locals]
119
+ if @@inference_invalidation_key == api_map.hash
120
+ cached = @@inference_cache[cache_key]
121
+ return cached if cached
122
+ else
94
123
  @@inference_invalidation_key = api_map.hash
124
+ @@inference_cache = {}
95
125
  end
96
- @@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] = out unless node.nil?
97
- out
126
+ out = infer_uncached api_map, name_pin, locals
127
+ logger.debug { "Chain#infer() - caching result - cache_key_hash=#{cache_key.hash}, links.map(&:hash)=#{links.map(&:hash)}, links=#{links}, cache_key.map(&:hash) = #{cache_key.map(&:hash)}, cache_key=#{cache_key}" }
128
+ @@inference_cache[cache_key] = out
98
129
  end
99
130
 
100
131
  # @param api_map [ApiMap]
101
132
  # @param name_pin [Pin::Base]
102
- # @param locals [::Enumerable<Pin::LocalVariable>]
133
+ # @param locals [::Array<Pin::LocalVariable>]
103
134
  # @return [ComplexType]
104
135
  def infer_uncached api_map, name_pin, locals
105
- from_here = base.infer(api_map, name_pin, locals) unless links.length == 1
106
- if from_here
107
- name_pin = name_pin.proxy(from_here)
108
- end
109
136
  pins = define(api_map, name_pin, locals)
110
137
  type = infer_first_defined(pins, links.last.last_context, api_map, locals)
111
138
  maybe_nil(type)
@@ -137,6 +164,16 @@ module Solargraph
137
164
  links.any?(&:nullable?)
138
165
  end
139
166
 
167
+ include Logging
168
+
169
+ def desc
170
+ links.map(&:desc).to_s
171
+ end
172
+
173
+ def to_s
174
+ desc
175
+ end
176
+
140
177
  private
141
178
 
142
179
  # @param pins [::Array<Pin::Base>]
@@ -151,9 +188,9 @@ module Solargraph
151
188
  # @param pin [Pin::Base]
152
189
  pins.each do |pin|
153
190
  # Avoid infinite recursion
154
- next if @@inference_stack.include?(pin.identity)
191
+ next if @@inference_stack.include?(pin)
155
192
 
156
- @@inference_stack.push pin.identity
193
+ @@inference_stack.push pin
157
194
  type = pin.typify(api_map)
158
195
  @@inference_stack.pop
159
196
  if type.defined?
@@ -161,7 +198,7 @@ module Solargraph
161
198
  # @todo even at strong, no typechecking complaint
162
199
  # happens when a [Pin::Base,nil] is passed into a method
163
200
  # that accepts only [Pin::Namespace] as an argument
164
- type = type.resolve_generics(pin.closure, context.return_type)
201
+ type = type.resolve_generics(pin.closure, context.binder)
165
202
  end
166
203
  if type.defined?
167
204
  possibles.push type
@@ -177,9 +214,9 @@ module Solargraph
177
214
  # @param pin [Pin::Base]
178
215
  pins.each do |pin|
179
216
  # Avoid infinite recursion
180
- next if @@inference_stack.include?(pin.identity)
217
+ next if @@inference_stack.include?(pin)
181
218
 
182
- @@inference_stack.push pin.identity
219
+ @@inference_stack.push pin
183
220
  type = pin.probe(api_map)
184
221
  @@inference_stack.pop
185
222
  if type.defined?
@@ -192,14 +229,15 @@ module Solargraph
192
229
  return ComplexType::UNDEFINED if possibles.empty?
193
230
 
194
231
  type = if possibles.length > 1
195
- sorted = possibles.map { |t| t.rooted? ? "::#{t}" : t.to_s }.sort { |a, _| a == 'nil' ? 1 : 0 }
196
- ComplexType.parse(*sorted)
232
+ # Move nil to the end by convention
233
+ sorted = possibles.sort { |a, _| a.tag == 'nil' ? 1 : 0 }
234
+ ComplexType.new(sorted.uniq)
197
235
  else
198
- ComplexType.parse(possibles.map(&:to_s).join(', '))
236
+ ComplexType.new(possibles)
199
237
  end
200
238
  return type if context.nil? || context.return_type.undefined?
201
239
 
202
- type.self_to(context.return_type.tag)
240
+ type.self_to_type(context.return_type)
203
241
  end
204
242
 
205
243
  # @param type [ComplexType]
@@ -207,7 +245,7 @@ module Solargraph
207
245
  def maybe_nil type
208
246
  return type if type.undefined? || type.void? || type.nullable?
209
247
  return type unless nullable?
210
- ComplexType.try_parse("#{type}, nil")
248
+ ComplexType.new(type.items + [ComplexType::NIL])
211
249
  end
212
250
  end
213
251
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Solargraph
4
4
  class Source
5
- # Information about a position in a source, including the word located
6
- # there.
5
+ # Information about a single Position in a Source, including the
6
+ # word located there.
7
7
  #
8
8
  class Cursor
9
9
  # @return [Position]
@@ -35,6 +35,7 @@ module Solargraph
35
35
  # The part of the word before the current position. Given the text
36
36
  # `foo.bar`, the start_of_word at position(0, 6) is `ba`.
37
37
  #
38
+ # @sg-ignore Improve resolution of String#match below
38
39
  # @return [String]
39
40
  def start_of_word
40
41
  @start_of_word ||= begin
@@ -19,13 +19,22 @@ module Solargraph
19
19
  attr_reader :filename
20
20
 
21
21
  # @return [String]
22
- attr_reader :code
22
+ def code
23
+ finalize
24
+ @code
25
+ end
23
26
 
24
- # @return [Parser::AST::Node]
25
- attr_reader :node
27
+ # @return [Parser::AST::Node, nil]
28
+ def node
29
+ finalize
30
+ @node
31
+ end
26
32
 
27
33
  # @return [Hash{Integer => Array<String>}]
28
- attr_reader :comments
34
+ def comments
35
+ finalize
36
+ @comments
37
+ end
29
38
 
30
39
  # @todo Deprecate?
31
40
  # @return [Integer]
@@ -39,17 +48,6 @@ module Solargraph
39
48
  @repaired = code
40
49
  @filename = filename
41
50
  @version = version
42
- @domains = []
43
- begin
44
- @node, @comments = Solargraph::Parser.parse_with_comments(@code, filename)
45
- @parsed = true
46
- rescue Parser::SyntaxError, EncodingError => e
47
- @node = nil
48
- @comments = {}
49
- @parsed = false
50
- ensure
51
- @code.freeze
52
- end
53
51
  end
54
52
 
55
53
  # @param range [Solargraph::Range]
@@ -64,9 +62,9 @@ module Solargraph
64
62
  # @param c2 [Integer]
65
63
  # @return [String]
66
64
  def from_to l1, c1, l2, c2
67
- b = Solargraph::Position.line_char_to_offset(@code, l1, c1)
68
- e = Solargraph::Position.line_char_to_offset(@code, l2, c2)
69
- @code[b..e-1]
65
+ b = Solargraph::Position.line_char_to_offset(code, l1, c1)
66
+ e = Solargraph::Position.line_char_to_offset(code, l2, c2)
67
+ code[b..e-1]
70
68
  end
71
69
 
72
70
  # Get the nearest node that contains the specified index.
@@ -85,10 +83,9 @@ module Solargraph
85
83
  # @param column [Integer]
86
84
  # @return [Array<AST::Node>]
87
85
  def tree_at(line, column)
88
- # offset = Position.line_char_to_offset(@code, line, column)
89
86
  position = Position.new(line, column)
90
87
  stack = []
91
- inner_tree_at @node, position, stack
88
+ inner_tree_at node, position, stack
92
89
  stack
93
90
  end
94
91
 
@@ -104,68 +101,53 @@ module Solargraph
104
101
  @version = updater.version
105
102
  return self
106
103
  end
107
- synced = Source.new(real_code, filename)
108
- if synced.parsed?
109
- synced.version = updater.version
110
- return synced
104
+ Source.new(@code, filename, updater.version).tap do |src|
105
+ src.repaired = @repaired
106
+ src.error_ranges.concat error_ranges
107
+ src.changes.concat(changes + updater.changes)
111
108
  end
112
- incr_code = updater.repair(@repaired)
113
- synced = Source.new(incr_code, filename)
114
- synced.error_ranges.concat (error_ranges + updater.changes.map(&:range))
115
- synced.code = real_code
116
- synced.version = updater.version
117
- synced
118
109
  end
119
110
 
120
111
  # @param position [Position, Array(Integer, Integer)]
121
112
  # @return [Source::Cursor]
122
113
  def cursor_at position
114
+ finalize
123
115
  Cursor.new(self, position)
124
116
  end
125
117
 
126
118
  # @return [Boolean]
127
119
  def parsed?
120
+ finalize
128
121
  @parsed
129
122
  end
130
123
 
131
124
  def repaired?
132
- @is_repaired ||= (@code != @repaired)
125
+ code != @repaired
133
126
  end
134
127
 
135
128
  # @param position [Position]
136
129
  # @return [Boolean]
137
130
  def string_at? position
138
- if Parser.rubyvm?
139
- string_ranges.each do |range|
140
- if synchronized?
141
- return true if range.include?(position) || range.ending == position
142
- else
143
- return true if last_updater && last_updater.changes.one? && range.contain?(last_updater.changes.first.range.start)
144
- end
145
- end
146
- false
147
- else
148
- return false if Position.to_offset(code, position) >= code.length
149
- string_nodes.each do |node|
150
- range = Range.from_node(node)
151
- next if range.ending.line < position.line
152
- break if range.ending.line > position.line
153
- return true if node.type == :str && range.include?(position) && range.start != position
154
- return true if [:STR, :str].include?(node.type) && range.include?(position) && range.start != position
155
- if node.type == :dstr
156
- inner = node_at(position.line, position.column)
157
- next if inner.nil?
158
- inner_range = Range.from_node(inner)
159
- next unless range.include?(inner_range.ending)
160
- return true if inner.type == :str
161
- inner_code = at(Solargraph::Range.new(inner_range.start, position))
162
- return true if (inner.type == :dstr && inner_range.ending.character <= position.character) && !inner_code.end_with?('}') ||
163
- (inner.type != :dstr && inner_range.ending.line == position.line && position.character <= inner_range.ending.character && inner_code.end_with?('}'))
164
- end
165
- break if range.ending.line > position.line
131
+ return false if Position.to_offset(code, position) >= code.length
132
+ string_nodes.each do |node|
133
+ range = Range.from_node(node)
134
+ next if range.ending.line < position.line
135
+ break if range.ending.line > position.line
136
+ return true if node.type == :str && range.include?(position) && range.start != position
137
+ return true if [:STR, :str].include?(node.type) && range.include?(position) && range.start != position
138
+ if node.type == :dstr
139
+ inner = node_at(position.line, position.column)
140
+ next if inner.nil?
141
+ inner_range = Range.from_node(inner)
142
+ next unless range.include?(inner_range.ending)
143
+ return true if inner.type == :str
144
+ inner_code = at(Solargraph::Range.new(inner_range.start, position))
145
+ return true if (inner.type == :dstr && inner_range.ending.character <= position.character) && !inner_code.end_with?('}') ||
146
+ (inner.type != :dstr && inner_range.ending.line == position.line && position.character <= inner_range.ending.character && inner_code.end_with?('}'))
166
147
  end
167
- false
148
+ break if range.ending.line > position.line
168
149
  end
150
+ false
169
151
  end
170
152
 
171
153
  # @return [::Array<Range>]
@@ -199,8 +181,8 @@ module Solargraph
199
181
  # @return [String]
200
182
  def code_for(node)
201
183
  rng = Range.from_node(node)
202
- b = Position.line_char_to_offset(@code, rng.start.line, rng.start.column)
203
- e = Position.line_char_to_offset(@code, rng.ending.line, rng.ending.column)
184
+ b = Position.line_char_to_offset(code, rng.start.line, rng.start.column)
185
+ e = Position.line_char_to_offset(code, rng.ending.line, rng.ending.column)
204
186
  frag = code[b..e-1].to_s
205
187
  frag.strip.gsub(/,$/, '')
206
188
  end
@@ -225,15 +207,9 @@ module Solargraph
225
207
  Location.new(filename, range)
226
208
  end
227
209
 
228
- FOLDING_NODE_TYPES = if Parser.rubyvm?
229
- %i[
230
- CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR HASH ARRAY LIST
231
- ].freeze
232
- else
233
- %i[
210
+ FOLDING_NODE_TYPES = %i[
234
211
  class sclass module def defs if str dstr array while unless kwbegin hash block
235
212
  ].freeze
236
- end
237
213
 
238
214
  # Get an array of ranges that can be folded, e.g., the range of a class
239
215
  # definition or an if condition.
@@ -251,8 +227,7 @@ module Solargraph
251
227
  end
252
228
 
253
229
  def synchronized?
254
- @synchronized = true if @synchronized.nil?
255
- @synchronized
230
+ true
256
231
  end
257
232
 
258
233
  # Get a hash of comments grouped by the line numbers of the associated code.
@@ -262,8 +237,9 @@ module Solargraph
262
237
  @associated_comments ||= begin
263
238
  result = {}
264
239
  buffer = String.new('')
240
+ # @type [Integer, nil]
265
241
  last = nil
266
- @comments.each_pair do |num, snip|
242
+ comments.each_pair do |num, snip|
267
243
  if !last || num == last + 1
268
244
  buffer.concat "#{snip.text}\n"
269
245
  else
@@ -295,12 +271,9 @@ module Solargraph
295
271
  def inner_folding_ranges top, result = [], parent = nil
296
272
  return unless Parser.is_ast_node?(top)
297
273
  if FOLDING_NODE_TYPES.include?(top.type)
298
- # @todo Smelly exception for hash's first-level array in RubyVM
299
- unless [:ARRAY, :LIST].include?(top.type) && parent == :HASH
300
- range = Range.from_node(top)
301
- if result.empty? || range.start.line > result.last.start.line
302
- result.push range unless range.ending.line - range.start.line < 2
303
- end
274
+ range = Range.from_node(top)
275
+ if result.empty? || range.start.line > result.last.start.line
276
+ result.push range unless range.ending.line - range.start.line < 2
304
277
  end
305
278
  end
306
279
  top.children.each do |child|
@@ -334,19 +307,19 @@ module Solargraph
334
307
 
335
308
  # A hash of line numbers and their associated comments.
336
309
  #
337
- # @return [Hash{Integer => Array<String>}]
310
+ # @return [Hash{Integer => Array<String>, nil}]
338
311
  def stringified_comments
339
312
  @stringified_comments ||= {}
340
313
  end
341
314
 
342
315
  # @return [Array<Parser::AST::Node>]
343
316
  def string_nodes
344
- @string_nodes ||= string_nodes_in(@node)
317
+ @string_nodes ||= string_nodes_in(node)
345
318
  end
346
319
 
347
320
  # @return [Array<Range>]
348
321
  def comment_ranges
349
- @comment_ranges ||= @comments.values.map(&:range)
322
+ @comment_ranges ||= comments.values.map(&:range)
350
323
  end
351
324
 
352
325
  # Get an array of foldable comment block ranges. Blocks are excluded if
@@ -402,16 +375,59 @@ module Solargraph
402
375
 
403
376
  protected
404
377
 
378
+ # @return [Array<Change>]
379
+ def changes
380
+ @changes ||= []
381
+ end
382
+
405
383
  # @return [String]
406
384
  attr_writer :filename
407
385
 
408
386
  # @return [Integer]
409
387
  attr_writer :version
410
388
 
389
+ def finalize
390
+ return if @finalized && changes.empty?
391
+
392
+ changes.each do |change|
393
+ @code = change.write(@code)
394
+ end
395
+ @finalized = true
396
+ begin
397
+ @node, @comments = Solargraph::Parser.parse_with_comments(@code, filename)
398
+ @parsed = true
399
+ @repaired = @code
400
+ rescue Parser::SyntaxError, EncodingError => e
401
+ @node = nil
402
+ @comments = {}
403
+ @parsed = false
404
+ ensure
405
+ @code.freeze
406
+ end
407
+ if !@parsed && !changes.empty?
408
+ changes.each do |change|
409
+ @repaired = change.repair(@repaired)
410
+ end
411
+ error_ranges.concat(changes.map(&:range))
412
+ begin
413
+ @node, @comments = Solargraph::Parser.parse_with_comments(@repaired, filename)
414
+ @parsed = true
415
+ rescue Parser::SyntaxError, EncodingError => e
416
+ @node = nil
417
+ @comments = {}
418
+ @parsed = false
419
+ end
420
+ elsif @parsed
421
+ error_ranges.clear
422
+ end
423
+ changes.clear
424
+ end
425
+
411
426
  # @param val [String]
412
427
  # @return [String]
413
428
  def code=(val)
414
- @code_lines= nil
429
+ @code_lines = nil
430
+ @finalized = false
415
431
  @code = val
416
432
  end
417
433
 
@@ -422,7 +438,12 @@ module Solargraph
422
438
  attr_writer :error_ranges
423
439
 
424
440
  # @return [String]
425
- attr_accessor :repaired
441
+ attr_writer :repaired
442
+
443
+ def repaired
444
+ finalize
445
+ @repaired
446
+ end
426
447
 
427
448
  # @return [Boolean]
428
449
  attr_writer :parsed
@@ -433,9 +454,6 @@ module Solargraph
433
454
  # @return [Boolean]
434
455
  attr_writer :synchronized
435
456
 
436
- # @return [Source::Updater]
437
- attr_accessor :last_updater
438
-
439
457
  private
440
458
 
441
459
  # @return [Array<String>]
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Solargraph
4
4
  class SourceMap
5
- # A static analysis tool for obtaining definitions, completions,
6
- # signatures, and type inferences from a cursor.
5
+ # A static analysis tool for obtaining definitions, Completions,
6
+ # signatures, and type inferences from a Cursor.
7
7
  #
8
8
  class Clip
9
9
  # @param api_map [ApiMap]
@@ -40,7 +40,7 @@ module Solargraph
40
40
  end
41
41
  end
42
42
 
43
- # @return [Array<Pin::Base>]
43
+ # @return [Array<Pin::Method>]
44
44
  def signify
45
45
  return [] unless cursor.argument?
46
46
  chain = Parser.chain(cursor.recipient_node, cursor.filename)
@@ -53,10 +53,10 @@ module Solargraph
53
53
  if result.tag == 'Class'
54
54
  # HACK: Exception to return BasicObject from Class#new
55
55
  dfn = cursor.chain.define(api_map, block, locals).first
56
- return ComplexType.try_parse('BasicObject') if dfn && dfn.path == 'Class#new'
56
+ return ComplexType.try_parse('::BasicObject') if dfn && dfn.path == 'Class#new'
57
57
  end
58
58
  return result unless result.tag == 'self'
59
- ComplexType.try_parse(cursor.chain.base.infer(api_map, block, locals).tag)
59
+ cursor.chain.base.infer(api_map, block, locals)
60
60
  end
61
61
 
62
62
  # Get an array of all the locals that are visible from the cursors's
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class SourceMap
5
+ class Data
6
+ def initialize source
7
+ @source = source
8
+ end
9
+
10
+ def pins
11
+ generate
12
+ @pins || []
13
+ end
14
+
15
+ def locals
16
+ generate
17
+ @locals || []
18
+ end
19
+
20
+ private
21
+
22
+ def generate
23
+ return if @generated
24
+
25
+ @generated = true
26
+ @pins, @locals = Mapper.map(@source)
27
+ end
28
+ end
29
+ end
30
+ end