ruby-lsp 0.23.20 → 0.26.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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +10 -4
  4. data/exe/ruby-lsp-check +0 -4
  5. data/exe/ruby-lsp-launcher +25 -11
  6. data/exe/ruby-lsp-test-exec +6 -0
  7. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +0 -1
  8. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +0 -1
  9. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +7 -1
  10. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +1 -4
  11. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +10 -19
  12. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +29 -7
  13. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +2 -2
  14. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +12 -8
  15. data/lib/ruby_indexer/test/configuration_test.rb +1 -2
  16. data/lib/ruby_indexer/test/index_test.rb +39 -0
  17. data/lib/ruby_indexer/test/instance_variables_test.rb +24 -0
  18. data/lib/ruby_indexer/test/method_test.rb +17 -0
  19. data/lib/ruby_indexer/test/rbs_indexer_test.rb +2 -2
  20. data/lib/ruby_indexer/test/reference_finder_test.rb +79 -14
  21. data/lib/ruby_lsp/addon.rb +44 -15
  22. data/lib/ruby_lsp/base_server.rb +34 -26
  23. data/lib/ruby_lsp/document.rb +162 -52
  24. data/lib/ruby_lsp/erb_document.rb +8 -3
  25. data/lib/ruby_lsp/global_state.rb +21 -0
  26. data/lib/ruby_lsp/internal.rb +0 -2
  27. data/lib/ruby_lsp/listeners/completion.rb +14 -3
  28. data/lib/ruby_lsp/listeners/hover.rb +7 -0
  29. data/lib/ruby_lsp/listeners/inlay_hints.rb +5 -3
  30. data/lib/ruby_lsp/listeners/spec_style.rb +126 -67
  31. data/lib/ruby_lsp/listeners/test_discovery.rb +18 -15
  32. data/lib/ruby_lsp/listeners/test_style.rb +56 -23
  33. data/lib/ruby_lsp/requests/code_action_resolve.rb +3 -3
  34. data/lib/ruby_lsp/requests/code_lens.rb +14 -5
  35. data/lib/ruby_lsp/requests/completion.rb +1 -1
  36. data/lib/ruby_lsp/requests/definition.rb +1 -1
  37. data/lib/ruby_lsp/requests/discover_tests.rb +2 -2
  38. data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
  39. data/lib/ruby_lsp/requests/hover.rb +1 -1
  40. data/lib/ruby_lsp/requests/inlay_hints.rb +3 -3
  41. data/lib/ruby_lsp/requests/on_type_formatting.rb +1 -1
  42. data/lib/ruby_lsp/requests/prepare_rename.rb +1 -1
  43. data/lib/ruby_lsp/requests/references.rb +10 -6
  44. data/lib/ruby_lsp/requests/rename.rb +8 -6
  45. data/lib/ruby_lsp/requests/request.rb +6 -7
  46. data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
  47. data/lib/ruby_lsp/requests/show_syntax_tree.rb +1 -1
  48. data/lib/ruby_lsp/requests/signature_help.rb +1 -1
  49. data/lib/ruby_lsp/requests/support/common.rb +1 -3
  50. data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
  51. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +2 -2
  52. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +13 -3
  53. data/lib/ruby_lsp/response_builders/response_builder.rb +6 -8
  54. data/lib/ruby_lsp/ruby_document.rb +10 -5
  55. data/lib/ruby_lsp/server.rb +95 -110
  56. data/lib/ruby_lsp/setup_bundler.rb +59 -25
  57. data/lib/ruby_lsp/static_docs.rb +1 -0
  58. data/lib/ruby_lsp/store.rb +0 -10
  59. data/lib/ruby_lsp/test_helper.rb +1 -4
  60. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +18 -7
  61. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +54 -7
  62. data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +0 -1
  63. data/lib/ruby_lsp/utils.rb +47 -11
  64. data/static_docs/break.md +103 -0
  65. metadata +7 -19
  66. data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -100,7 +100,7 @@ module RubyLsp
100
100
 
101
101
  # Find the closest statements node, so that we place the refactor in a valid position
102
102
  node_context = RubyDocument
103
- .locate(@document.parse_result.value,
103
+ .locate(@document.ast,
104
104
  start_index,
105
105
  node_types: [
106
106
  Prism::StatementsNode,
@@ -207,7 +207,7 @@ module RubyLsp
207
207
 
208
208
  # Find the closest method declaration node, so that we place the refactor in a valid position
209
209
  node_context = RubyDocument.locate(
210
- @document.parse_result.value,
210
+ @document.ast,
211
211
  start_index,
212
212
  node_types: [Prism::DefNode],
213
213
  code_units_cache: @document.code_units_cache,
@@ -365,7 +365,7 @@ module RubyLsp
365
365
  end
366
366
  end
367
367
 
368
- node = node #: as Prism::InstanceVariableAndWriteNode | Prism::InstanceVariableOperatorWriteNode | Prism::InstanceVariableOrWriteNode | Prism::InstanceVariableReadNode | Prism::InstanceVariableTargetNode | Prism::InstanceVariableWriteNode # rubocop:disable Layout/LineLength
368
+ node = node #: as Prism::InstanceVariableAndWriteNode | Prism::InstanceVariableOperatorWriteNode | Prism::InstanceVariableOrWriteNode | Prism::InstanceVariableReadNode | Prism::InstanceVariableTargetNode | Prism::InstanceVariableWriteNode
369
369
 
370
370
  node_context = @document.locate_node(
371
371
  {
@@ -18,17 +18,25 @@ module RubyLsp
18
18
  end
19
19
  end
20
20
 
21
- #: (GlobalState global_state, URI::Generic uri, Prism::Dispatcher dispatcher) -> void
22
- def initialize(global_state, uri, dispatcher)
21
+ #: (GlobalState, RubyDocument | ERBDocument, Prism::Dispatcher) -> void
22
+ def initialize(global_state, document, dispatcher)
23
23
  @response_builder = ResponseBuilders::CollectionResponseBuilder
24
24
  .new #: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens]
25
25
  super()
26
26
 
27
+ @document = document
27
28
  @test_builder = ResponseBuilders::TestCollection.new #: ResponseBuilders::TestCollection
29
+ uri = document.uri
30
+ file_path = uri.full_path
31
+ code_lens_config = global_state.feature_configuration(:codeLens)
32
+ test_lenses_enabled = (!code_lens_config || code_lens_config.enabled?(:enableTestCodeLens)) &&
33
+ file_path && File.fnmatch?(TEST_PATH_PATTERN, file_path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
28
34
 
29
35
  if global_state.enabled_feature?(:fullTestDiscovery)
30
- Listeners::TestStyle.new(@test_builder, global_state, dispatcher, uri)
31
- Listeners::SpecStyle.new(@test_builder, global_state, dispatcher, uri)
36
+ if test_lenses_enabled
37
+ Listeners::TestStyle.new(@test_builder, global_state, dispatcher, uri)
38
+ Listeners::SpecStyle.new(@test_builder, global_state, dispatcher, uri)
39
+ end
32
40
  else
33
41
  Listeners::CodeLens.new(@response_builder, global_state, uri, dispatcher)
34
42
  end
@@ -36,7 +44,7 @@ module RubyLsp
36
44
  Addon.addons.each do |addon|
37
45
  addon.create_code_lens_listener(@response_builder, uri, dispatcher)
38
46
 
39
- if global_state.enabled_feature?(:fullTestDiscovery)
47
+ if global_state.enabled_feature?(:fullTestDiscovery) && test_lenses_enabled
40
48
  addon.create_discover_tests_listener(@test_builder, dispatcher, uri)
41
49
  end
42
50
  end
@@ -45,6 +53,7 @@ module RubyLsp
45
53
  # @override
46
54
  #: -> Array[Interface::CodeLens]
47
55
  def perform
56
+ @document.cache_set("rubyLsp/discoverTests", @test_builder.response)
48
57
  @response_builder.response + @test_builder.code_lens
49
58
  end
50
59
  end
@@ -33,7 +33,7 @@ module RubyLsp
33
33
  delegate_request_if_needed!(global_state, document, char_position)
34
34
 
35
35
  node_context = RubyDocument.locate(
36
- document.parse_result.value,
36
+ document.ast,
37
37
  char_position,
38
38
  node_types: [
39
39
  Prism::CallNode,
@@ -20,7 +20,7 @@ module RubyLsp
20
20
  delegate_request_if_needed!(global_state, document, char_position)
21
21
 
22
22
  node_context = RubyDocument.locate(
23
- document.parse_result.value,
23
+ document.ast,
24
24
  char_position,
25
25
  node_types: [
26
26
  Prism::CallNode,
@@ -43,7 +43,7 @@ module RubyLsp
43
43
  addon.create_discover_tests_listener(@response_builder, @dispatcher, @document.uri)
44
44
  end
45
45
 
46
- @dispatcher.visit(@document.parse_result.value)
46
+ @dispatcher.visit(@document.ast)
47
47
  else
48
48
  @global_state.synchronize do
49
49
  RubyIndexer::DeclarationListener.new(
@@ -64,7 +64,7 @@ module RubyLsp
64
64
  # Dispatch the events both for indexing the test file and discovering the tests. The order here is
65
65
  # important because we need the index to be aware of the existing classes/modules/methods before the test
66
66
  # listeners can do their work
67
- @dispatcher.visit(@document.parse_result.value)
67
+ @dispatcher.visit(@document.ast)
68
68
  end
69
69
  end
70
70
 
@@ -20,7 +20,7 @@ module RubyLsp
20
20
  delegate_request_if_needed!(global_state, document, char_position)
21
21
 
22
22
  node_context = RubyDocument.locate(
23
- document.parse_result.value,
23
+ document.ast,
24
24
  char_position,
25
25
  code_units_cache: document.code_units_cache,
26
26
  )
@@ -24,7 +24,7 @@ module RubyLsp
24
24
  delegate_request_if_needed!(global_state, document, char_position)
25
25
 
26
26
  node_context = RubyDocument.locate(
27
- document.parse_result.value,
27
+ document.ast,
28
28
  char_position,
29
29
  node_types: Listeners::Hover::ALLOWED_TARGETS,
30
30
  code_units_cache: document.code_units_cache,
@@ -16,13 +16,13 @@ module RubyLsp
16
16
  end
17
17
  end
18
18
 
19
- #: ((RubyDocument | ERBDocument) document, RequestConfig hints_configuration, Prism::Dispatcher dispatcher) -> void
20
- def initialize(document, hints_configuration, dispatcher)
19
+ #: (GlobalState, (RubyDocument | ERBDocument), Prism::Dispatcher) -> void
20
+ def initialize(global_state, document, dispatcher)
21
21
  super()
22
22
 
23
23
  @response_builder = ResponseBuilders::CollectionResponseBuilder
24
24
  .new #: ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint]
25
- Listeners::InlayHints.new(@response_builder, hints_configuration, dispatcher)
25
+ Listeners::InlayHints.new(global_state, @response_builder, dispatcher)
26
26
  end
27
27
 
28
28
  # @override
@@ -162,7 +162,7 @@ module RubyLsp
162
162
 
163
163
  #: (Integer line, Integer character) -> void
164
164
  def move_cursor_to(line, character)
165
- return unless /Visual Studio Code|Cursor|VSCodium/.match?(@client_name)
165
+ return unless /Visual Studio Code|Cursor|VSCodium|Windsurf/.match?(@client_name)
166
166
 
167
167
  position = Interface::Position.new(
168
168
  line: line,
@@ -22,7 +22,7 @@ module RubyLsp
22
22
  char_position, _ = @document.find_index_by_position(@position)
23
23
 
24
24
  node_context = RubyDocument.locate(
25
- @document.parse_result.value,
25
+ @document.ast,
26
26
  char_position,
27
27
  node_types: [Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode],
28
28
  code_units_cache: @document.code_units_cache,
@@ -26,7 +26,7 @@ module RubyLsp
26
26
  char_position, _ = @document.find_index_by_position(position)
27
27
 
28
28
  node_context = RubyDocument.locate(
29
- @document.parse_result.value,
29
+ @document.ast,
30
30
  char_position,
31
31
  node_types: [
32
32
  Prism::ConstantReadNode,
@@ -55,7 +55,7 @@ module RubyLsp
55
55
  )
56
56
  end
57
57
 
58
- target = target #: as Prism::ConstantReadNode | Prism::ConstantPathNode | Prism::ConstantPathTargetNode | Prism::InstanceVariableAndWriteNode | Prism::InstanceVariableOperatorWriteNode | Prism::InstanceVariableOrWriteNode | Prism::InstanceVariableReadNode | Prism::InstanceVariableTargetNode | Prism::InstanceVariableWriteNode | Prism::CallNode | Prism::DefNode, # rubocop:disable Layout/LineLength
58
+ target = target #: as Prism::ConstantReadNode | Prism::ConstantPathNode | Prism::ConstantPathTargetNode | Prism::InstanceVariableAndWriteNode | Prism::InstanceVariableOperatorWriteNode | Prism::InstanceVariableOrWriteNode | Prism::InstanceVariableReadNode | Prism::InstanceVariableTargetNode | Prism::InstanceVariableWriteNode | Prism::CallNode | Prism::DefNode,
59
59
 
60
60
  reference_target = create_reference_target(target, node_context)
61
61
  return @locations unless reference_target
@@ -66,7 +66,7 @@ module RubyLsp
66
66
  # of reading from disk
67
67
  next if @store.key?(uri)
68
68
 
69
- parse_result = Prism.parse_file(path)
69
+ parse_result = Prism.parse_lex_file(path)
70
70
  collect_references(reference_target, parse_result, uri)
71
71
  rescue Errno::EISDIR, Errno::ENOENT
72
72
  # If `path` is a directory, just ignore it and continue. If the file doesn't exist, then we also ignore it.
@@ -101,13 +101,17 @@ module RubyLsp
101
101
  Prism::InstanceVariableReadNode,
102
102
  Prism::InstanceVariableTargetNode,
103
103
  Prism::InstanceVariableWriteNode
104
- RubyIndexer::ReferenceFinder::InstanceVariableTarget.new(target_node.name.to_s)
104
+ receiver_type = @global_state.type_inferrer.infer_receiver_type(node_context)
105
+ return unless receiver_type
106
+
107
+ ancestors = @global_state.index.linearized_ancestors_of(receiver_type.name)
108
+ RubyIndexer::ReferenceFinder::InstanceVariableTarget.new(target_node.name.to_s, ancestors)
105
109
  when Prism::CallNode, Prism::DefNode
106
110
  RubyIndexer::ReferenceFinder::MethodTarget.new(target_node.name.to_s)
107
111
  end
108
112
  end
109
113
 
110
- #: (RubyIndexer::ReferenceFinder::Target target, Prism::ParseResult parse_result, URI::Generic uri) -> void
114
+ #: (RubyIndexer::ReferenceFinder::Target target, Prism::LexResult parse_result, URI::Generic uri) -> void
111
115
  def collect_references(target, parse_result, uri)
112
116
  dispatcher = Prism::Dispatcher.new
113
117
  finder = RubyIndexer::ReferenceFinder.new(
@@ -117,7 +121,7 @@ module RubyLsp
117
121
  uri,
118
122
  include_declarations: @params.dig(:context, :includeDeclaration) || true,
119
123
  )
120
- dispatcher.visit(parse_result.value)
124
+ dispatcher.visit(parse_result.value.first)
121
125
 
122
126
  finder.references.each do |reference|
123
127
  @locations << Interface::Location.new(
@@ -34,7 +34,7 @@ module RubyLsp
34
34
  char_position, _ = @document.find_index_by_position(@position)
35
35
 
36
36
  node_context = RubyDocument.locate(
37
- @document.parse_result.value,
37
+ @document.ast,
38
38
  char_position,
39
39
  node_types: [Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode],
40
40
  code_units_cache: @document.code_units_cache,
@@ -136,25 +136,27 @@ module RubyLsp
136
136
  next if @store.key?(uri)
137
137
 
138
138
  parse_result = Prism.parse_file(path)
139
- edits = collect_changes(target, parse_result, name, uri)
139
+ edits = collect_changes(target, parse_result.value, name, uri)
140
140
  changes[uri.to_s] = edits unless edits.empty?
141
141
  rescue Errno::EISDIR, Errno::ENOENT
142
142
  # If `path` is a directory, just ignore it and continue. If the file doesn't exist, then we also ignore it.
143
143
  end
144
144
 
145
145
  @store.each do |uri, document|
146
- edits = collect_changes(target, document.parse_result, name, document.uri)
146
+ next unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
147
+
148
+ edits = collect_changes(target, document.ast, name, document.uri)
147
149
  changes[uri] = edits unless edits.empty?
148
150
  end
149
151
 
150
152
  changes
151
153
  end
152
154
 
153
- #: (RubyIndexer::ReferenceFinder::Target target, Prism::ParseResult parse_result, String name, URI::Generic uri) -> Array[Interface::TextEdit]
154
- def collect_changes(target, parse_result, name, uri)
155
+ #: (RubyIndexer::ReferenceFinder::Target target, Prism::Node ast, String name, URI::Generic uri) -> Array[Interface::TextEdit]
156
+ def collect_changes(target, ast, name, uri)
155
157
  dispatcher = Prism::Dispatcher.new
156
158
  finder = RubyIndexer::ReferenceFinder.new(target, @global_state.index, dispatcher, uri)
157
- dispatcher.visit(parse_result.value)
159
+ dispatcher.visit(ast)
158
160
 
159
161
  finder.references.map do |reference|
160
162
  adjust_reference_for_edit(name, reference)
@@ -3,16 +3,15 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
+ # @abstract
6
7
  class Request
7
- extend T::Helpers
8
- extend T::Sig
9
-
10
8
  class InvalidFormatter < StandardError; end
11
9
 
12
- abstract!
13
-
14
- sig { abstract.returns(T.anything) }
15
- def perform; end
10
+ # @abstract
11
+ #: -> untyped
12
+ def perform
13
+ raise AbstractMethodInvokedError
14
+ end
16
15
 
17
16
  private
18
17
 
@@ -25,7 +25,7 @@ module RubyLsp
25
25
  #: -> (Array[Support::SelectionRange] & Object)
26
26
  def perform
27
27
  # [node, parent]
28
- queue = [[@document.parse_result.value, nil]]
28
+ queue = [[@document.ast, nil]]
29
29
 
30
30
  until queue.empty?
31
31
  node, parent = queue.shift
@@ -12,7 +12,7 @@ module RubyLsp
12
12
  super()
13
13
  @document = document
14
14
  @range = range
15
- @tree = document.parse_result.value #: Prism::ProgramNode
15
+ @tree = document.ast #: Prism::ProgramNode
16
16
  end
17
17
 
18
18
  # @override
@@ -27,7 +27,7 @@ module RubyLsp
27
27
  delegate_request_if_needed!(global_state, document, char_position)
28
28
 
29
29
  node_context = RubyDocument.locate(
30
- document.parse_result.value,
30
+ document.ast,
31
31
  char_position,
32
32
  node_types: [Prism::CallNode],
33
33
  code_units_cache: document.code_units_cache,
@@ -4,13 +4,11 @@
4
4
  module RubyLsp
5
5
  module Requests
6
6
  module Support
7
+ # @requires_ancestor: Kernel
7
8
  module Common
8
9
  # WARNING: Methods in this class may be used by Ruby LSP add-ons such as
9
10
  # https://github.com/Shopify/ruby-lsp-rails, or add-ons by created by developers outside of Shopify, so be
10
11
  # cautious of changing anything.
11
- extend T::Helpers
12
-
13
- requires_ancestor { Kernel }
14
12
 
15
13
  #: (Prism::Node node) -> Interface::Range
16
14
  def range_from_node(node)
@@ -4,25 +4,26 @@
4
4
  module RubyLsp
5
5
  module Requests
6
6
  module Support
7
+ # Empty module to avoid the runtime component. This is an interface defined in sorbet/rbi/shims/ruby_lsp.rbi
8
+ # @interface
7
9
  module Formatter
8
- extend T::Sig
9
- extend T::Helpers
10
-
11
- interface!
12
-
13
- sig { abstract.params(uri: URI::Generic, document: RubyDocument).returns(T.nilable(String)) }
14
- def run_formatting(uri, document); end
10
+ # @abstract
11
+ #: (URI::Generic, RubyLsp::RubyDocument) -> String?
12
+ def run_formatting(uri, document)
13
+ raise AbstractMethodInvokedError
14
+ end
15
15
 
16
- sig { abstract.params(uri: URI::Generic, source: String, base_indentation: Integer).returns(T.nilable(String)) }
17
- def run_range_formatting(uri, source, base_indentation); end
16
+ # @abstract
17
+ #: (URI::Generic, String, Integer) -> String?
18
+ def run_range_formatting(uri, source, base_indentation)
19
+ raise AbstractMethodInvokedError
20
+ end
18
21
 
19
- sig do
20
- abstract.params(
21
- uri: URI::Generic,
22
- document: RubyDocument,
23
- ).returns(T.nilable(T::Array[Interface::Diagnostic]))
22
+ # @abstract
23
+ #: (URI::Generic, RubyLsp::RubyDocument) -> Array[Interface::Diagnostic]?
24
+ def run_diagnostic(uri, document)
25
+ raise AbstractMethodInvokedError
24
26
  end
25
- def run_diagnostic(uri, document); end
26
27
  end
27
28
  end
28
29
  end
@@ -24,7 +24,7 @@ module RubyLsp
24
24
  filename = uri.to_standardized_path || uri.opaque #: as !nil
25
25
 
26
26
  # Invoke RuboCop with just this file in `paths`
27
- @format_runner.run(filename, document.source)
27
+ @format_runner.run(filename, document.source, document.parse_result)
28
28
  @format_runner.formatted_source
29
29
  end
30
30
 
@@ -40,7 +40,7 @@ module RubyLsp
40
40
  def run_diagnostic(uri, document)
41
41
  filename = uri.to_standardized_path || uri.opaque #: as !nil
42
42
  # Invoke RuboCop with just this file in `paths`
43
- @diagnostic_runner.run(filename, document.source)
43
+ @diagnostic_runner.run(filename, document.source, document.parse_result)
44
44
 
45
45
  @diagnostic_runner.offenses.map do |offense|
46
46
  Support::RuboCopDiagnostic.new(
@@ -81,6 +81,7 @@ module RubyLsp
81
81
  @offenses = [] #: Array[::RuboCop::Cop::Offense]
82
82
  @errors = [] #: Array[String]
83
83
  @warnings = [] #: Array[String]
84
+ # @prism_result = nil #: Prism::ParseLexResult?
84
85
 
85
86
  args += DEFAULT_ARGS
86
87
  rubocop_options = ::RuboCop::Options.new.parse(args).first
@@ -92,8 +93,8 @@ module RubyLsp
92
93
  super(rubocop_options, config_store)
93
94
  end
94
95
 
95
- #: (String path, String contents) -> void
96
- def run(path, contents)
96
+ #: (String, String, Prism::ParseLexResult) -> void
97
+ def run(path, contents, prism_result)
97
98
  # Clear Runner state between runs since we get a single instance of this class
98
99
  # on every use site.
99
100
  @errors = []
@@ -101,6 +102,11 @@ module RubyLsp
101
102
  @offenses = []
102
103
  @options[:stdin] = contents
103
104
 
105
+ # Setting the Prism result before running the RuboCop runner makes it reuse the existing AST and avoids
106
+ # double-parsing. Unfortunately, this leads to a bunch of cops failing to execute properly under LSP mode.
107
+ # Uncomment this once reusing the Prism result is more stable
108
+ # @prism_result = prism_result
109
+
104
110
  super([path])
105
111
 
106
112
  # RuboCop rescues interrupts and then sets the `@aborting` variable to true. We don't want them to be rescued,
@@ -111,7 +117,11 @@ module RubyLsp
111
117
  rescue ::RuboCop::ValidationError => error
112
118
  raise ConfigurationError, error.message
113
119
  rescue StandardError => error
114
- raise InternalRuboCopError, error
120
+ # Maintain the original backtrace so that debugging cops that are breaking is easier, but re-raise as a
121
+ # different error class
122
+ internal_error = InternalRuboCopError.new(error)
123
+ internal_error.set_backtrace(error.backtrace)
124
+ raise internal_error
115
125
  end
116
126
 
117
127
  #: -> String
@@ -3,15 +3,13 @@
3
3
 
4
4
  module RubyLsp
5
5
  module ResponseBuilders
6
+ # @abstract
6
7
  class ResponseBuilder
7
- extend T::Sig
8
- extend T::Helpers
9
- extend T::Generic
10
-
11
- abstract!
12
-
13
- sig { abstract.returns(T.anything) }
14
- def response; end
8
+ # @abstract
9
+ #: -> top
10
+ def response
11
+ raise AbstractMethodInvokedError
12
+ end
15
13
  end
16
14
  end
17
15
  end
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
5
- #: [ParseResultType = Prism::ParseResult]
5
+ #: [ParseResultType = Prism::ParseLexResult]
6
6
  class RubyDocument < Document
7
7
  METHODS_THAT_CHANGE_DECLARATIONS = [
8
8
  :private_constant,
@@ -26,7 +26,7 @@ module RubyLsp
26
26
  queue = node.child_nodes.compact #: Array[Prism::Node?]
27
27
  closest = node
28
28
  parent = nil #: Prism::Node?
29
- nesting_nodes = [] #: Array[(Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode | Prism::DefNode | Prism::BlockNode | Prism::LambdaNode | Prism::ProgramNode)] # rubocop:disable Layout/LineLength
29
+ nesting_nodes = [] #: Array[(Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode | Prism::DefNode | Prism::BlockNode | Prism::LambdaNode | Prism::ProgramNode)]
30
30
 
31
31
  nesting_nodes << node if node.is_a?(Prism::ProgramNode)
32
32
  call_node = nil #: Prism::CallNode?
@@ -129,11 +129,16 @@ module RubyLsp
129
129
  return false unless @needs_parsing
130
130
 
131
131
  @needs_parsing = false
132
- @parse_result = Prism.parse(@source)
132
+ @parse_result = Prism.parse_lex(@source)
133
133
  @code_units_cache = @parse_result.code_units_cache(@encoding)
134
134
  true
135
135
  end
136
136
 
137
+ #: -> Prism::ProgramNode
138
+ def ast
139
+ @parse_result.value.first
140
+ end
141
+
137
142
  # @override
138
143
  #: -> bool
139
144
  def syntax_error?
@@ -151,7 +156,7 @@ module RubyLsp
151
156
  start_position, end_position = find_index_by_position(range[:start], range[:end])
152
157
 
153
158
  desired_range = (start_position...end_position)
154
- queue = @parse_result.value.child_nodes.compact #: Array[Prism::Node?]
159
+ queue = ast.child_nodes.compact #: Array[Prism::Node?]
155
160
 
156
161
  until queue.empty?
157
162
  candidate = queue.shift
@@ -179,7 +184,7 @@ module RubyLsp
179
184
  char_position, _ = find_index_by_position(position)
180
185
 
181
186
  RubyDocument.locate(
182
- @parse_result.value,
187
+ ast,
183
188
  char_position,
184
189
  code_units_cache: @code_units_cache,
185
190
  node_types: node_types,