solargraph 0.43.1 → 0.44.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -1
  3. data/lib/solargraph/complex_type.rb +4 -0
  4. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
  5. data/lib/solargraph/documentor.rb +10 -12
  6. data/lib/solargraph/language_server/host/message_worker.rb +10 -7
  7. data/lib/solargraph/language_server/host.rb +32 -34
  8. data/lib/solargraph/language_server/message/initialize.rb +7 -0
  9. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  10. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +16 -0
  11. data/lib/solargraph/language_server/message/text_document.rb +18 -18
  12. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +1 -0
  13. data/lib/solargraph/language_server/message.rb +2 -1
  14. data/lib/solargraph/library.rb +23 -20
  15. data/lib/solargraph/parser/legacy/node_chainer.rb +17 -0
  16. data/lib/solargraph/parser/legacy/node_methods.rb +7 -0
  17. data/lib/solargraph/parser/legacy/node_processors/block_node.rb +25 -1
  18. data/lib/solargraph/parser/rubyvm/class_methods.rb +7 -2
  19. data/lib/solargraph/parser/rubyvm/node_chainer.rb +5 -0
  20. data/lib/solargraph/parser/rubyvm/node_methods.rb +23 -14
  21. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +25 -1
  22. data/lib/solargraph/pin/block.rb +19 -9
  23. data/lib/solargraph/pin/documenting.rb +1 -1
  24. data/lib/solargraph/pin/local_variable.rb +1 -13
  25. data/lib/solargraph/source/chain/link.rb +4 -0
  26. data/lib/solargraph/source/chain/q_call.rb +11 -0
  27. data/lib/solargraph/source/chain.rb +14 -1
  28. data/lib/solargraph/source.rb +0 -3
  29. data/lib/solargraph/source_map/clip.rb +5 -5
  30. data/lib/solargraph/source_map/mapper.rb +4 -4
  31. data/lib/solargraph/version.rb +1 -1
  32. data/lib/solargraph/workspace.rb +14 -10
  33. data/lib/solargraph/yard_map.rb +6 -2
  34. data/solargraph.gemspec +1 -1
  35. metadata +8 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48b532bf77bb72b9d2d111605cc86e97a21c372319a041ef5c4dfbd03a2b98d1
4
- data.tar.gz: da953eea90b1215a794783723898277abe33a4b74e585eeb710f231b824321b7
3
+ metadata.gz: 346926f891270e103d6c7170fe5897587c1d5da45ea33b2a7f4238914b38b236
4
+ data.tar.gz: 451b09bf70dc9d760ebfdeb726821e6e653f196bd867da8c7638888803e33a72
5
5
  SHA512:
6
- metadata.gz: c3f55a7eb1f0b08247d70f7a2c28422b6444e5102a96c7c9da88b5b9b5f558732f97dc186e6dc53650bd5af20747066dbf53272a15527f000607fca17583e6da
7
- data.tar.gz: 7224059b6b2c757049bf27c4140c54063b035b13eeaf93f30c521393c5e8c863b72843c28edbfb9cbe2980fe28f79006195926f9c8bf79b204dd08a9895ec1e8
6
+ metadata.gz: 624d1de49ef2762477d7a413adf282a058143a71689ea8cdfcc91177db94c765b997fca00fefd8d0d4915e44e6cd4ae1867297671611ba6d119d610116c5b80a
7
+ data.tar.gz: 9f146a371e075407cb8be7b96de08ff24583cf18eb1a29310c1a711c1bd347715d07b0ff6603e9a98b71be7406148e17c907abdcf3bd1a2aba58bd5aeff14685
data/CHANGELOG.md CHANGED
@@ -1,4 +1,24 @@
1
- ## 0.43.1
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
+
8
+ ## 0.44.0 - September 27, 2021
9
+ - Allow opening parenthesis, space, and comma when using Diff::LCS (#465)
10
+ - Support textDocument/documentHighlight
11
+ - Library#references_from performs shallow matches
12
+
13
+ ## 0.43.3 - September 25, 2021
14
+ - Avoid Dir.chdir in Bundler processes (#481)
15
+ - Check stdlib for gems with empty yardocs
16
+ - Library#maybe_map checks for source in workspace
17
+
18
+ ## 0.43.2 - September 23, 2021
19
+ - Synchronize server requests (#461)
20
+
21
+ ## 0.43.1 - September 20, 2021
2
22
  - Complete nested namespaces in open gates
3
23
  - SourceMap::Mapper reports filename for encoding errors (#474)
4
24
  - Handle request on a specific thread, and cancel completion when there has newer completion request (#459)
@@ -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
@@ -59,18 +59,16 @@ module Solargraph
59
59
  # @return [Hash]
60
60
  def self.specs_from_bundle directory
61
61
  Solargraph.with_clean_env do
62
- Dir.chdir directory do
63
- cmd = [
64
- 'bundle', 'exec', 'ruby', '-e',
65
- "require 'bundler'; require 'json'; puts Bundler.definition.specs_for([:default]).map { |spec| [spec.name, spec.version] }.to_h.to_json"
66
- ]
67
- o, e, s = Open3.capture3(*cmd)
68
- if s.success?
69
- o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
70
- else
71
- Solargraph.logger.warn e
72
- raise BundleNotFoundError, "Failed to load gems from bundle at #{directory}"
73
- end
62
+ cmd = [
63
+ 'ruby', '-e',
64
+ "require 'bundler'; require 'json'; Dir.chdir('#{directory}') { puts Bundler.definition.specs_for([:default]).map { |spec| [spec.name, spec.version] }.to_h.to_json }"
65
+ ]
66
+ o, e, s = Open3.capture3(*cmd)
67
+ if s.success?
68
+ o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
69
+ else
70
+ Solargraph.logger.warn e
71
+ raise BundleNotFoundError, "Failed to load gems from bundle at #{directory}"
74
72
  end
75
73
  end
76
74
  end
@@ -23,16 +23,18 @@ module Solargraph
23
23
  def stopped?
24
24
  @stopped
25
25
  end
26
+
26
27
  def stop
27
28
  @stopped = true
28
29
  end
29
30
 
30
- # @param message the message should be handle. will pass back to Host#receive
31
+ # @param message [Hash] The message should be handle. will pass back to Host#receive
32
+ # @return [void]
31
33
  def queue(message)
32
- @mutex.synchronize {
34
+ @mutex.synchronize do
33
35
  messages.push(message)
34
36
  @resource.signal
35
- }
37
+ end
36
38
  end
37
39
 
38
40
  def start
@@ -42,13 +44,14 @@ module Solargraph
42
44
  tick until stopped?
43
45
  end
44
46
  end
47
+
45
48
  def tick
46
- message = @mutex.synchronize {
49
+ message = @mutex.synchronize do
47
50
  @resource.wait(@mutex) if messages.empty?
48
51
  messages.shift
49
- }
50
- message = @host.receive(message)
51
- message && message.send_response
52
+ end
53
+ handler = @host.receive(message)
54
+ handler && handler.send_response
52
55
  end
53
56
  end
54
57
  end
@@ -18,7 +18,6 @@ module Solargraph
18
18
  autoload :Dispatch, 'solargraph/language_server/host/dispatch'
19
19
  autoload :MessageWorker, 'solargraph/language_server/host/message_worker'
20
20
 
21
-
22
21
  include UriHelpers
23
22
  include Logging
24
23
  include Dispatch
@@ -29,7 +28,7 @@ module Solargraph
29
28
  def initialize
30
29
  @cancel_semaphore = Mutex.new
31
30
  @buffer_semaphore = Mutex.new
32
- @register_semaphore = Mutex.new
31
+ @request_mutex = Mutex.new
33
32
  @cancel = []
34
33
  @buffer = String.new
35
34
  @stopped = true
@@ -92,7 +91,9 @@ module Solargraph
92
91
  @cancel_semaphore.synchronize { @cancel.delete id }
93
92
  end
94
93
 
95
- # called by adapter, to handle the request
94
+ # Called by adapter, to handle the request
95
+ # @param request [Hash]
96
+ # @return [void]
96
97
  def process request
97
98
  message_worker.queue(request)
98
99
  end
@@ -363,19 +364,21 @@ module Solargraph
363
364
  # @yieldparam [Hash] The result sent by the client
364
365
  # @return [void]
365
366
  def send_request method, params, &block
366
- message = {
367
- jsonrpc: "2.0",
368
- method: method,
369
- params: params,
370
- id: @next_request_id
371
- }
372
- json = message.to_json
373
- requests[@next_request_id] = Request.new(@next_request_id, &block)
374
- envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
375
- queue envelope
376
- @next_request_id += 1
377
- logger.info "Server sent #{method}"
378
- logger.debug params
367
+ @request_mutex.synchronize do
368
+ message = {
369
+ jsonrpc: "2.0",
370
+ method: method,
371
+ params: params,
372
+ id: @next_request_id
373
+ }
374
+ json = message.to_json
375
+ requests[@next_request_id] = Request.new(@next_request_id, &block)
376
+ envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
377
+ queue envelope
378
+ @next_request_id += 1
379
+ logger.info "Server sent #{method}"
380
+ logger.debug params
381
+ end
379
382
  end
380
383
 
381
384
  # Register the methods as capabilities with the client.
@@ -386,20 +389,16 @@ module Solargraph
386
389
  # @return [void]
387
390
  def register_capabilities methods
388
391
  logger.debug "Registering capabilities: #{methods}"
389
- registrations = methods.select{|m| can_register?(m) and !registered?(m)}.map { |m|
392
+ registrations = methods.select { |m| can_register?(m) and !registered?(m) }.map do |m|
390
393
  @registered_capabilities.add m
391
394
  {
392
395
  id: m,
393
396
  method: m,
394
397
  registerOptions: dynamic_capability_options[m]
395
398
  }
396
- }
397
- return if registrations.empty?
398
- @register_semaphore.synchronize do
399
- send_request 'client/registerCapability', {
400
- registrations: registrations
401
- }
402
399
  end
400
+ return if registrations.empty?
401
+ send_request 'client/registerCapability', { registrations: registrations }
403
402
  end
404
403
 
405
404
  # Unregister the methods with the client.
@@ -418,11 +417,7 @@ module Solargraph
418
417
  }
419
418
  }
420
419
  return if unregisterations.empty?
421
- @register_semaphore.synchronize do
422
- send_request 'client/unregisterCapability', {
423
- unregisterations: unregisterations
424
- }
425
- end
420
+ send_request 'client/unregisterCapability', { unregisterations: unregisterations }
426
421
  end
427
422
 
428
423
  # Flag a method as available for dynamic registration.
@@ -430,9 +425,7 @@ module Solargraph
430
425
  # @param method [String] The method name, e.g., 'textDocument/completion'
431
426
  # @return [void]
432
427
  def allow_registration method
433
- @register_semaphore.synchronize do
434
- @dynamic_capabilities.add method
435
- end
428
+ @dynamic_capabilities.add method
436
429
  end
437
430
 
438
431
  # True if the specified LSP method can be dynamically registered.
@@ -549,10 +542,11 @@ module Solargraph
549
542
  # @param line [Integer]
550
543
  # @param column [Integer]
551
544
  # @param strip [Boolean] Strip special characters from variable names
545
+ # @param only [Boolean] If true, search current file only
552
546
  # @return [Array<Solargraph::Range>]
553
- def references_from uri, line, column, strip: true
547
+ def references_from uri, line, column, strip: true, only: false
554
548
  library = library_for(uri)
555
- library.references_from(uri_to_file(uri), line, column, strip: strip)
549
+ library.references_from(uri_to_file(uri), line, column, strip: strip, only: only)
556
550
  end
557
551
 
558
552
  # @param query [String]
@@ -638,6 +632,7 @@ module Solargraph
638
632
  'diagnostics' => false,
639
633
  'formatting' => false,
640
634
  'folding' => true,
635
+ 'highlights' => true,
641
636
  'logLevel' => 'warn'
642
637
  }
643
638
  end
@@ -722,7 +717,7 @@ module Solargraph
722
717
  return change if diffs.length.zero? || diffs.length > 1 || diffs.first.length > 1
723
718
  # @type [Diff::LCS::Change]
724
719
  diff = diffs.first.first
725
- return change unless diff.adding? && ['.', ':'].include?(diff.element)
720
+ return change unless diff.adding? && ['.', ':', '(', ',', ' '].include?(diff.element)
726
721
  position = Solargraph::Position.from_offset(source.code, diff.position)
727
722
  {
728
723
  'range' => {
@@ -790,6 +785,9 @@ module Solargraph
790
785
  },
791
786
  'textDocument/codeAction' => {
792
787
  codeActionProvider: true
788
+ },
789
+ 'textDocument/documentHighlight' => {
790
+ documentHighlightProvider: true
793
791
  }
794
792
  }
795
793
  end
@@ -36,6 +36,7 @@ module Solargraph
36
36
  result[:capabilities].merge! static_references unless dynamic_registration_for?('textDocument', 'references')
37
37
  result[:capabilities].merge! static_workspace_symbols unless dynamic_registration_for?('workspace', 'symbol')
38
38
  result[:capabilities].merge! static_folding_range unless dynamic_registration_for?('textDocument', 'foldingRange')
39
+ result[:capabilities].merge! static_highlights unless dynamic_registration_for?('textDocument', 'documentHighlight')
39
40
  # @todo Temporarily disabled
40
41
  # result[:capabilities].merge! static_code_action unless dynamic_registration_for?('textDocument', 'codeAction')
41
42
  set_result result
@@ -138,6 +139,12 @@ module Solargraph
138
139
  }
139
140
  end
140
141
 
142
+ def static_highlights
143
+ {
144
+ documentHighlightProvider: true
145
+ }
146
+ end
147
+
141
148
  # @param section [String]
142
149
  # @param capability [String]
143
150
  # @return [Boolean]
@@ -17,6 +17,7 @@ module Solargraph
17
17
  textDocument/rename
18
18
  textDocument/prepareRename
19
19
  textDocument/foldingRange
20
+ textDocument/documentHighlight
20
21
  workspace/symbol
21
22
  ]
22
23
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph::LanguageServer::Message::TextDocument
4
+ class DocumentHighlight < Base
5
+ def process
6
+ locs = host.references_from(params['textDocument']['uri'], params['position']['line'], params['position']['character'], strip: true, only: true)
7
+ result = locs.map do |loc|
8
+ {
9
+ range: loc.range.to_hash,
10
+ kind: 1
11
+ }
12
+ end
13
+ set_result result
14
+ end
15
+ end
16
+ end
@@ -4,24 +4,24 @@ module Solargraph
4
4
  module LanguageServer
5
5
  module Message
6
6
  module TextDocument
7
- autoload :Base, 'solargraph/language_server/message/text_document/base'
8
- autoload :Completion, 'solargraph/language_server/message/text_document/completion'
9
- autoload :DidOpen, 'solargraph/language_server/message/text_document/did_open'
10
- autoload :DidChange, 'solargraph/language_server/message/text_document/did_change'
11
- autoload :DidClose, 'solargraph/language_server/message/text_document/did_close'
12
- autoload :DidSave, 'solargraph/language_server/message/text_document/did_save'
13
- autoload :Hover, 'solargraph/language_server/message/text_document/hover'
14
- autoload :SignatureHelp, 'solargraph/language_server/message/text_document/signature_help'
15
- autoload :DiagnosticsQueue, 'solargraph/language_server/message/text_document/diagnostics_queue'
16
- autoload :OnTypeFormatting, 'solargraph/language_server/message/text_document/on_type_formatting'
17
- autoload :Definition, 'solargraph/language_server/message/text_document/definition'
18
- autoload :DocumentSymbol, 'solargraph/language_server/message/text_document/document_symbol'
19
- autoload :Formatting, 'solargraph/language_server/message/text_document/formatting'
20
- autoload :References, 'solargraph/language_server/message/text_document/references'
21
- autoload :Rename, 'solargraph/language_server/message/text_document/rename'
22
- autoload :PrepareRename, 'solargraph/language_server/message/text_document/prepare_rename'
23
- autoload :FoldingRange, 'solargraph/language_server/message/text_document/folding_range'
24
- autoload :CodeAction, 'solargraph/language_server/message/text_document/code_action'
7
+ autoload :Base, 'solargraph/language_server/message/text_document/base'
8
+ autoload :Completion, 'solargraph/language_server/message/text_document/completion'
9
+ autoload :DidOpen, 'solargraph/language_server/message/text_document/did_open'
10
+ autoload :DidChange, 'solargraph/language_server/message/text_document/did_change'
11
+ autoload :DidClose, 'solargraph/language_server/message/text_document/did_close'
12
+ autoload :DidSave, 'solargraph/language_server/message/text_document/did_save'
13
+ autoload :Hover, 'solargraph/language_server/message/text_document/hover'
14
+ autoload :SignatureHelp, 'solargraph/language_server/message/text_document/signature_help'
15
+ autoload :DiagnosticsQueue, 'solargraph/language_server/message/text_document/diagnostics_queue'
16
+ autoload :OnTypeFormatting, 'solargraph/language_server/message/text_document/on_type_formatting'
17
+ autoload :Definition, 'solargraph/language_server/message/text_document/definition'
18
+ autoload :DocumentSymbol, 'solargraph/language_server/message/text_document/document_symbol'
19
+ autoload :Formatting, 'solargraph/language_server/message/text_document/formatting'
20
+ autoload :References, 'solargraph/language_server/message/text_document/references'
21
+ autoload :Rename, 'solargraph/language_server/message/text_document/rename'
22
+ autoload :PrepareRename, 'solargraph/language_server/message/text_document/prepare_rename'
23
+ autoload :FoldingRange, 'solargraph/language_server/message/text_document/folding_range'
24
+ autoload :DocumentHighlight, 'solargraph/language_server/message/text_document/document_highlight'
25
25
  end
26
26
  end
27
27
  end
@@ -22,6 +22,7 @@ module Solargraph::LanguageServer::Message::Workspace
22
22
  (host.options['definitions'] ? y : n).push('textDocument/definition')
23
23
  (host.options['references'] ? y : n).push('textDocument/references')
24
24
  (host.options['folding'] ? y : n).push('textDocument/folding')
25
+ (host.options['highlights'] ? y : n).push('textDocument/documentHighlight')
25
26
  host.register_capabilities y
26
27
  host.unregister_capabilities n
27
28
  end
@@ -73,7 +73,8 @@ module Solargraph
73
73
  register 'textDocument/rename', TextDocument::Rename
74
74
  register 'textDocument/prepareRename', TextDocument::PrepareRename
75
75
  register 'textDocument/foldingRange', TextDocument::FoldingRange
76
- register 'textDocument/codeAction', TextDocument::CodeAction
76
+ # register 'textDocument/codeAction', TextDocument::CodeAction
77
+ register 'textDocument/documentHighlight', TextDocument::DocumentHighlight
77
78
  register 'workspace/didChangeWatchedFiles', Workspace::DidChangeWatchedFiles
78
79
  register 'workspace/didChangeConfiguration', Workspace::DidChangeConfiguration
79
80
  register 'workspace/didChangeWorkspaceFolders', Workspace::DidChangeWorkspaceFolders
@@ -216,33 +216,35 @@ module Solargraph
216
216
  # @param line [Integer]
217
217
  # @param column [Integer]
218
218
  # @param strip [Boolean] Strip special characters from variable names
219
+ # @param only [Boolean] Search for references in the current file only
219
220
  # @return [Array<Solargraph::Range>]
220
221
  # @todo Take a Location instead of filename/line/column
221
- def references_from filename, line, column, strip: false
222
+ def references_from filename, line, column, strip: false, only: false
222
223
  cursor = api_map.cursor_at(filename, Position.new(line, column))
223
224
  clip = api_map.clip(cursor)
224
- pins = clip.define
225
- return [] if pins.empty?
225
+ pin = clip.define.first
226
+ return [] unless pin
226
227
  result = []
227
- pins.uniq.each do |pin|
228
- (workspace.sources + (@current ? [@current] : [])).uniq(&:filename).each do |source|
229
- found = source.references(pin.name)
230
- found.select! do |loc|
231
- referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character)
232
- # HACK: The additional location comparison is necessary because
233
- # Clip#define can return proxies for parameter pins
234
- referenced.any? { |r| r == pin || r.location == pin.location }
235
- end
236
- # HACK: for language clients that exclude special characters from the start of variable names
237
- if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
238
- found.map! do |loc|
239
- Solargraph::Location.new(loc.filename, Solargraph::Range.from_to(loc.range.start.line, loc.range.start.column + match[0].length, loc.range.ending.line, loc.range.ending.column))
240
- end
228
+ files = if only
229
+ [api_map.source_map(filename)]
230
+ else
231
+ (workspace.sources + (@current ? [@current] : []))
232
+ end
233
+ files.uniq(&:filename).each do |source|
234
+ found = source.references(pin.name)
235
+ found.select! do |loc|
236
+ referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character).first
237
+ referenced && referenced.path == pin.path
238
+ end
239
+ # HACK: for language clients that exclude special characters from the start of variable names
240
+ if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
241
+ found.map! do |loc|
242
+ Solargraph::Location.new(loc.filename, Solargraph::Range.from_to(loc.range.start.line, loc.range.start.column + match[0].length, loc.range.ending.line, loc.range.ending.column))
241
243
  end
242
- result.concat(found.sort do |a, b|
243
- a.range.start.line <=> b.range.start.line
244
- end)
245
244
  end
245
+ result.concat(found.sort do |a, b|
246
+ a.range.start.line <=> b.range.start.line
247
+ end)
246
248
  end
247
249
  result.uniq
248
250
  end
@@ -518,6 +520,7 @@ module Solargraph
518
520
 
519
521
  def maybe_map source
520
522
  return unless source
523
+ return unless @current == source || workspace.has_file?(source.filename)
521
524
  if source_map_hash.key?(source.filename)
522
525
  return if source_map_hash[source.filename].code == source.code &&
523
526
  source_map_hash[source.filename].source.synchronized? &&
@@ -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
@@ -178,6 +178,7 @@ module Solargraph
178
178
 
179
179
  # @param cursor [Solargraph::Source::Cursor]
180
180
  def find_recipient_node cursor
181
+ return repaired_find_recipient_node(cursor) if cursor.source.repaired? && cursor.source.code[cursor.offset - 1] == '('
181
182
  source = cursor.source
182
183
  position = cursor.position
183
184
  offset = cursor.offset
@@ -210,6 +211,12 @@ module Solargraph
210
211
  nil
211
212
  end
212
213
 
214
+ def repaired_find_recipient_node cursor
215
+ cursor = cursor.source.cursor_at([cursor.position.line, cursor.position.column - 1])
216
+ node = cursor.source.tree_at(cursor.position.line, cursor.position.column).first
217
+ return node if node && node.type == :send
218
+ end
219
+
213
220
  module DeepInference
214
221
  class << self
215
222
  CONDITIONAL = [:if, :unless]
@@ -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))
@@ -141,36 +141,45 @@ module Solargraph
141
141
  class << self
142
142
  protected
143
143
 
144
+ # @param cursor [Source::Cursor]
145
+ # @return [RubyVM::AbstractSyntaxTree::Node, nil]
144
146
  def synchronized_find_recipient_node cursor
147
+ cursor = maybe_adjust_cursor(cursor)
145
148
  source = cursor.source
146
149
  position = cursor.position
147
150
  offset = cursor.offset
148
151
  tree = source.tree_at(position.line, position.column)
149
- tree.shift while tree.first && [:FCALL, :VCALL, :CALL].include?(tree.first.type) && !source.code_for(tree.first).strip.end_with?(')')
152
+ .select { |n| [:FCALL, :VCALL, :CALL].include?(n.type) }
153
+ unless source.repaired?
154
+ tree.shift while tree.first && !source.code_for(tree.first).strip.end_with?(')')
155
+ end
156
+ return tree.first if source.repaired? || source.code[0..offset-1] =~ /\(\s*$/
150
157
  tree.each do |node|
151
- if [:FCALL, :VCALL, :CALL].include?(node.type)
152
- args = node.children.find { |c| Parser.is_ast_node?(c) && [:ARRAY, :ZARRAY, :LIST].include?(c.type) }
153
- if args
154
- match = source.code[0..offset-1].match(/,[^\)]*\z/)
155
- rng = Solargraph::Range.from_node(args)
156
- if match
157
- rng = Solargraph::Range.new(rng.start, position)
158
- end
159
- return node if rng.contain?(position)
160
- elsif source.code[0..offset-1] =~ /\(\s*$/
161
- break unless source.code_for(node).strip.end_with?(')')
162
- return node
158
+ args = node.children.find { |c| Parser.is_ast_node?(c) && [:ARRAY, :ZARRAY, :LIST].include?(c.type) }
159
+ if args
160
+ match = source.code[0..offset-1].match(/,[^\)]*\z/)
161
+ rng = Solargraph::Range.from_node(args)
162
+ if match
163
+ rng = Solargraph::Range.new(rng.start, position)
163
164
  end
165
+ return node if rng.contain?(position)
164
166
  end
165
167
  end
166
168
  nil
167
169
  end
168
170
 
171
+ # @param cursor [Source::Cursor]
172
+ # @return [Source::Cursor]
173
+ def maybe_adjust_cursor cursor
174
+ return cursor unless (cursor.source.repaired? && cursor.source.code[cursor.offset - 1] == '(') || [',', ' '].include?(cursor.source.code[cursor.offset - 1])
175
+ cursor.source.cursor_at([cursor.position.line, cursor.position.column - 1])
176
+ end
177
+
169
178
  def unsynchronized_find_recipient_node cursor
170
179
  source = cursor.source
171
180
  position = cursor.position
172
181
  offset = cursor.offset
173
- if source.code[0..offset-1] =~ /\([A-Zaz0-9_\s]*\z$/ #&& source.code[offset] == ')'
182
+ if source.code[0..offset-1] =~ /\([A-Zaz0-9_\s]*\z$/
174
183
  tree = source.tree_at(position.line, position.column - 1)
175
184
  if tree.first && [:FCALL, :VCALL, :CALL].include?(tree.first.type)
176
185
  return tree.first
@@ -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.43.1'
4
+ VERSION = '0.44.1'
5
5
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'open3'
4
+ require 'rubygems'
5
+
3
6
  module Solargraph
4
7
  # A workspace consists of the files in a project's directory and the
5
8
  # project's configuration. It provides a Source for each file to be used
@@ -168,19 +171,20 @@ module Solargraph
168
171
  # HACK: Evaluating gemspec files violates the goal of not running
169
172
  # workspace code, but this is how Gem::Specification.load does it
170
173
  # anyway.
171
- Dir.chdir base do
174
+ cmd = ['ruby', '-e', "require 'rubygems'; require 'json'; spec = eval(File.read('#{file}'), TOPLEVEL_BINDING, '#{file}'); return unless Gem::Specification === spec; puts({name: spec.name, paths: spec.require_paths}.to_json)"]
175
+ o, e, s = Open3.capture3(*cmd)
176
+ if s.success?
172
177
  begin
173
- # @type [Gem::Specification]
174
- spec = eval(File.read(file), TOPLEVEL_BINDING, file)
175
- next unless Gem::Specification === spec
176
- @gemnames.push spec.name
177
- result.concat(spec.require_paths.map { |path| File.join(base, path) })
178
- rescue RuntimeError, ScriptError, Errno::ENOENT => e
179
- # Don't die if we have an error during eval-ing a gem spec.
180
- # Concat the default lib directory instead.
178
+ hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
179
+ next if hash.empty?
180
+ @gemnames.push hash['name']
181
+ result.concat(hash['paths'].map { |path| File.join(base, path) })
182
+ rescue StandardError => e
181
183
  Solargraph.logger.warn "Error reading #{file}: [#{e.class}] #{e.message}"
182
- result.push File.join(base, 'lib')
183
184
  end
185
+ else
186
+ Solargraph.logger.warn "Error reading #{file}"
187
+ Solargraph.logger.warn e
184
188
  end
185
189
  end
186
190
  result.concat(config.require_paths.map { |p| File.join(directory, p) })
@@ -10,6 +10,8 @@ module Solargraph
10
10
  # stdlib, and gems.
11
11
  #
12
12
  class YardMap
13
+ class NoYardocError < StandardError; end
14
+
13
15
  autoload :Cache, 'solargraph/yard_map/cache'
14
16
  autoload :CoreDocs, 'solargraph/yard_map/core_docs'
15
17
  autoload :CoreGen, 'solargraph/yard_map/core_gen'
@@ -86,7 +88,7 @@ module Solargraph
86
88
  @rebindable_method_names ||= pins_by_class(Pin::Method)
87
89
  .select { |pin| pin.comments && pin.comments.include?('@yieldself') }
88
90
  .map(&:name)
89
- .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'])
90
92
  .to_set
91
93
  end
92
94
 
@@ -224,7 +226,7 @@ module Solargraph
224
226
  result.concat process_yardoc yd, spec
225
227
  result.concat add_gem_dependencies(spec) if with_dependencies?
226
228
  end
227
- rescue Gem::LoadError => e
229
+ rescue Gem::LoadError, NoYardocError => e
228
230
  base = r.split('/').first
229
231
  next if from_std.include?(base)
230
232
  from_std.push base
@@ -299,6 +301,7 @@ module Solargraph
299
301
  result = Marshal.load(dump)
300
302
  return result unless result.nil? || result.empty?
301
303
  Solargraph.logger.warn "Empty cache for #{spec.name} #{spec.version}. Reloading"
304
+ File.unlink ser
302
305
  rescue StandardError => e
303
306
  Solargraph.logger.warn "Error loading pin cache: [#{e.class}] #{e.message}"
304
307
  File.unlink ser
@@ -315,6 +318,7 @@ module Solargraph
315
318
  Solargraph.logger.info "Loading #{spec.name} #{spec.version} from #{y}"
316
319
  load_yardoc y
317
320
  result = Mapper.new(YARD::Registry.all, spec).map
321
+ raise NoYardocError, "Yardoc at #{y} is empty" if result.empty?
318
322
  if spec
319
323
  ser = File.join(CoreDocs.cache_dir, 'gems', "#{spec.name}-#{spec.version}.ser")
320
324
  file = File.open(ser, 'wb')
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.43.1
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-20 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
@@ -381,6 +381,7 @@ files:
381
381
  - lib/solargraph/language_server/message/text_document/did_close.rb
382
382
  - lib/solargraph/language_server/message/text_document/did_open.rb
383
383
  - lib/solargraph/language_server/message/text_document/did_save.rb
384
+ - lib/solargraph/language_server/message/text_document/document_highlight.rb
384
385
  - lib/solargraph/language_server/message/text_document/document_symbol.rb
385
386
  - lib/solargraph/language_server/message/text_document/folding_range.rb
386
387
  - lib/solargraph/language_server/message/text_document/formatting.rb
@@ -509,6 +510,7 @@ files:
509
510
  - lib/solargraph/source/chain/link.rb
510
511
  - lib/solargraph/source/chain/literal.rb
511
512
  - lib/solargraph/source/chain/or.rb
513
+ - lib/solargraph/source/chain/q_call.rb
512
514
  - lib/solargraph/source/chain/variable.rb
513
515
  - lib/solargraph/source/chain/z_super.rb
514
516
  - lib/solargraph/source/change.rb