ruby-lsp 0.23.11 → 0.26.4

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +10 -4
  5. data/exe/ruby-lsp-check +0 -4
  6. data/exe/ruby-lsp-launcher +45 -22
  7. data/exe/ruby-lsp-test-exec +6 -0
  8. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -2
  9. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -6
  10. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +82 -116
  11. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +140 -183
  12. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +10 -14
  13. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +107 -236
  14. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +188 -285
  15. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
  16. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +23 -27
  17. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +25 -57
  18. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +58 -68
  19. data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
  20. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +7 -11
  21. data/lib/ruby_indexer/test/class_variables_test.rb +14 -14
  22. data/lib/ruby_indexer/test/classes_and_modules_test.rb +65 -40
  23. data/lib/ruby_indexer/test/configuration_test.rb +49 -9
  24. data/lib/ruby_indexer/test/constant_test.rb +34 -34
  25. data/lib/ruby_indexer/test/enhancements_test.rb +1 -1
  26. data/lib/ruby_indexer/test/index_test.rb +225 -135
  27. data/lib/ruby_indexer/test/instance_variables_test.rb +61 -37
  28. data/lib/ruby_indexer/test/method_test.rb +166 -123
  29. data/lib/ruby_indexer/test/prefix_tree_test.rb +21 -21
  30. data/lib/ruby_indexer/test/rbs_indexer_test.rb +70 -75
  31. data/lib/ruby_indexer/test/reference_finder_test.rb +79 -14
  32. data/lib/ruby_indexer/test/test_case.rb +9 -3
  33. data/lib/ruby_indexer/test/uri_test.rb +15 -2
  34. data/lib/ruby_lsp/addon.rb +88 -86
  35. data/lib/ruby_lsp/base_server.rb +79 -65
  36. data/lib/ruby_lsp/client_capabilities.rb +16 -13
  37. data/lib/ruby_lsp/document.rb +205 -104
  38. data/lib/ruby_lsp/erb_document.rb +45 -47
  39. data/lib/ruby_lsp/global_state.rb +73 -57
  40. data/lib/ruby_lsp/internal.rb +8 -3
  41. data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
  42. data/lib/ruby_lsp/listeners/completion.rb +81 -76
  43. data/lib/ruby_lsp/listeners/definition.rb +44 -58
  44. data/lib/ruby_lsp/listeners/document_highlight.rb +149 -151
  45. data/lib/ruby_lsp/listeners/document_link.rb +94 -82
  46. data/lib/ruby_lsp/listeners/document_symbol.rb +38 -52
  47. data/lib/ruby_lsp/listeners/folding_ranges.rb +40 -43
  48. data/lib/ruby_lsp/listeners/hover.rb +107 -115
  49. data/lib/ruby_lsp/listeners/inlay_hints.rb +8 -13
  50. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
  51. data/lib/ruby_lsp/listeners/signature_help.rb +12 -27
  52. data/lib/ruby_lsp/listeners/spec_style.rb +231 -0
  53. data/lib/ruby_lsp/listeners/test_discovery.rb +107 -0
  54. data/lib/ruby_lsp/listeners/test_style.rb +207 -95
  55. data/lib/ruby_lsp/node_context.rb +12 -39
  56. data/lib/ruby_lsp/rbs_document.rb +10 -11
  57. data/lib/ruby_lsp/requests/code_action_resolve.rb +65 -61
  58. data/lib/ruby_lsp/requests/code_actions.rb +14 -26
  59. data/lib/ruby_lsp/requests/code_lens.rb +31 -21
  60. data/lib/ruby_lsp/requests/completion.rb +8 -21
  61. data/lib/ruby_lsp/requests/completion_resolve.rb +6 -6
  62. data/lib/ruby_lsp/requests/definition.rb +8 -20
  63. data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
  64. data/lib/ruby_lsp/requests/discover_tests.rb +20 -7
  65. data/lib/ruby_lsp/requests/document_highlight.rb +6 -16
  66. data/lib/ruby_lsp/requests/document_link.rb +6 -17
  67. data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
  68. data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
  69. data/lib/ruby_lsp/requests/formatting.rb +6 -9
  70. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +139 -0
  71. data/lib/ruby_lsp/requests/hover.rb +12 -25
  72. data/lib/ruby_lsp/requests/inlay_hints.rb +8 -19
  73. data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
  74. data/lib/ruby_lsp/requests/prepare_rename.rb +5 -10
  75. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +5 -15
  76. data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
  77. data/lib/ruby_lsp/requests/references.rb +17 -57
  78. data/lib/ruby_lsp/requests/rename.rb +27 -51
  79. data/lib/ruby_lsp/requests/request.rb +13 -25
  80. data/lib/ruby_lsp/requests/selection_ranges.rb +7 -7
  81. data/lib/ruby_lsp/requests/semantic_highlighting.rb +16 -35
  82. data/lib/ruby_lsp/requests/show_syntax_tree.rb +7 -8
  83. data/lib/ruby_lsp/requests/signature_help.rb +9 -27
  84. data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
  85. data/lib/ruby_lsp/requests/support/common.rb +23 -61
  86. data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
  87. data/lib/ruby_lsp/requests/support/package_url.rb +414 -0
  88. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
  89. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +13 -16
  90. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +34 -36
  91. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
  92. data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
  93. data/lib/ruby_lsp/requests/support/source_uri.rb +20 -32
  94. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
  95. data/lib/ruby_lsp/requests/support/test_item.rb +16 -14
  96. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
  97. data/lib/ruby_lsp/requests/workspace_symbol.rb +24 -16
  98. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +6 -9
  99. data/lib/ruby_lsp/response_builders/document_symbol.rb +15 -21
  100. data/lib/ruby_lsp/response_builders/hover.rb +12 -18
  101. data/lib/ruby_lsp/response_builders/response_builder.rb +6 -7
  102. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +62 -91
  103. data/lib/ruby_lsp/response_builders/signature_help.rb +6 -8
  104. data/lib/ruby_lsp/response_builders/test_collection.rb +35 -13
  105. data/lib/ruby_lsp/ruby_document.rb +32 -98
  106. data/lib/ruby_lsp/scope.rb +7 -11
  107. data/lib/ruby_lsp/scripts/compose_bundle.rb +6 -4
  108. data/lib/ruby_lsp/server.rb +305 -198
  109. data/lib/ruby_lsp/setup_bundler.rb +131 -82
  110. data/lib/ruby_lsp/static_docs.rb +12 -7
  111. data/lib/ruby_lsp/store.rb +21 -49
  112. data/lib/ruby_lsp/test_helper.rb +3 -16
  113. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +241 -0
  114. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +145 -0
  115. data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +92 -0
  116. data/lib/ruby_lsp/type_inferrer.rb +13 -14
  117. data/lib/ruby_lsp/utils.rb +138 -93
  118. data/static_docs/break.md +103 -0
  119. metadata +15 -20
  120. data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -6,12 +6,8 @@ module RubyLsp
6
6
  # The [on type formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_onTypeFormatting)
7
7
  # request formats code as the user is typing. For example, automatically adding `end` to class definitions.
8
8
  class OnTypeFormatting < Request
9
- extend T::Sig
10
-
11
9
  class << self
12
- extend T::Sig
13
-
14
- sig { returns(Interface::DocumentOnTypeFormattingRegistrationOptions) }
10
+ #: -> Interface::DocumentOnTypeFormattingRegistrationOptions
15
11
  def provider
16
12
  Interface::DocumentOnTypeFormattingRegistrationOptions.new(
17
13
  document_selector: nil,
@@ -21,38 +17,29 @@ module RubyLsp
21
17
  end
22
18
  end
23
19
 
24
- END_REGEXES = T.let(
25
- [
26
- /\b(if|unless|for|while|until)\b($|\s|\()/,
27
- /\b(class|module|def|case)\b($|\s)/,
28
- /.*\s\bdo\b($|\s)/,
29
- ],
30
- T::Array[Regexp],
31
- )
32
-
33
- sig do
34
- params(
35
- document: RubyDocument,
36
- position: T::Hash[Symbol, T.untyped],
37
- trigger_character: String,
38
- client_name: String,
39
- ).void
40
- end
20
+ END_REGEXES = [
21
+ /\b(if|unless|for|while|until)\b($|\s|\()/,
22
+ /\b(class|module|def|case)\b($|\s)/,
23
+ /.*\s\bdo\b($|\s)/,
24
+ ] #: Array[Regexp]
25
+
26
+ #: (RubyDocument document, Hash[Symbol, untyped] position, String trigger_character, String client_name) -> void
41
27
  def initialize(document, position, trigger_character, client_name)
42
28
  super()
43
29
  @document = document
44
- @lines = T.let(@document.source.lines, T::Array[String])
30
+ @lines = @document.source.lines #: Array[String]
45
31
  line = @lines[[position[:line] - 1, 0].max]
46
32
 
47
- @indentation = T.let(line ? find_indentation(line) : 0, Integer)
48
- @previous_line = T.let(line ? line.strip.chomp : "", String)
33
+ @indentation = line ? find_indentation(line) : 0 #: Integer
34
+ @previous_line = line ? line.strip.chomp : "" #: String
49
35
  @position = position
50
- @edits = T.let([], T::Array[Interface::TextEdit])
36
+ @edits = [] #: Array[Interface::TextEdit]
51
37
  @trigger_character = trigger_character
52
38
  @client_name = client_name
53
39
  end
54
40
 
55
- sig { override.returns(T.all(T::Array[Interface::TextEdit], Object)) }
41
+ # @override
42
+ #: -> (Array[Interface::TextEdit] & Object)
56
43
  def perform
57
44
  case @trigger_character
58
45
  when "{"
@@ -60,8 +47,13 @@ module RubyLsp
60
47
  when "|"
61
48
  handle_pipe if @document.syntax_error?
62
49
  when "\n"
63
- if (comment_match = @previous_line.match(/^#(\s*)/))
64
- handle_comment_line(T.must(comment_match[1]))
50
+ # If the previous line is a simple comment, we'll add a comment continuation
51
+ # But if it's a RBS signature starting with `#:`, we'll ignore it
52
+ # so users can immediately continue typing the method definition
53
+ if (comment_match = @previous_line.match(/^#(?!:)(\s*)/))
54
+ handle_comment_line(
55
+ comment_match[1], #: as !nil
56
+ )
65
57
  elsif @document.syntax_error?
66
58
  match = /(<<((-|~)?))(?<quote>['"`]?)(?<delimiter>\w+)\k<quote>/.match(@previous_line)
67
59
  heredoc_delimiter = match && match.named_captures["delimiter"]
@@ -81,12 +73,12 @@ module RubyLsp
81
73
 
82
74
  private
83
75
 
84
- sig { void }
76
+ #: -> void
85
77
  def handle_pipe
86
78
  current_line = @lines[@position[:line]]
87
79
  return unless /((?<=do)|(?<={))\s+\|/.match?(current_line)
88
80
 
89
- line = T.must(current_line)
81
+ line = current_line #: as !nil
90
82
 
91
83
  # If the user inserts the closing pipe manually to the end of the block argument, we need to avoid adding
92
84
  # an additional one and remove the previous one. This also helps to remove the user who accidentally
@@ -112,7 +104,7 @@ module RubyLsp
112
104
  move_cursor_to(@position[:line], @position[:character])
113
105
  end
114
106
 
115
- sig { void }
107
+ #: -> void
116
108
  def handle_curly_brace
117
109
  return unless /".*#\{/.match?(@previous_line)
118
110
 
@@ -120,7 +112,7 @@ module RubyLsp
120
112
  move_cursor_to(@position[:line], @position[:character])
121
113
  end
122
114
 
123
- sig { void }
115
+ #: -> void
124
116
  def handle_statement_end
125
117
  # If a keyword occurs in a line which appears be a comment or a string, we will not try to format it, since
126
118
  # it could be a coincidental match. This approach is not perfect, but it should cover most cases.
@@ -142,7 +134,7 @@ module RubyLsp
142
134
  end
143
135
  end
144
136
 
145
- sig { params(delimiter: String).void }
137
+ #: (String delimiter) -> void
146
138
  def handle_heredoc_end(delimiter)
147
139
  indents = " " * @indentation
148
140
  add_edit_with_text("\n")
@@ -150,12 +142,12 @@ module RubyLsp
150
142
  move_cursor_to(@position[:line], @indentation + 2)
151
143
  end
152
144
 
153
- sig { params(spaces: String).void }
145
+ #: (String spaces) -> void
154
146
  def handle_comment_line(spaces)
155
147
  add_edit_with_text("##{spaces}")
156
148
  end
157
149
 
158
- sig { params(text: String, position: T::Hash[Symbol, T.untyped]).void }
150
+ #: (String text, ?Hash[Symbol, untyped] position) -> void
159
151
  def add_edit_with_text(text, position = @position)
160
152
  pos = Interface::Position.new(
161
153
  line: position[:line],
@@ -168,9 +160,9 @@ module RubyLsp
168
160
  )
169
161
  end
170
162
 
171
- sig { params(line: Integer, character: Integer).void }
163
+ #: (Integer line, Integer character) -> void
172
164
  def move_cursor_to(line, character)
173
- return unless /Visual Studio Code|Cursor/.match?(@client_name)
165
+ return unless /Visual Studio Code|Cursor|VSCodium|Windsurf/.match?(@client_name)
174
166
 
175
167
  position = Interface::Position.new(
176
168
  line: line,
@@ -189,7 +181,7 @@ module RubyLsp
189
181
  )
190
182
  end
191
183
 
192
- sig { params(line: String).returns(Integer) }
184
+ #: (String line) -> Integer
193
185
  def find_indentation(line)
194
186
  count = 0
195
187
 
@@ -202,7 +194,7 @@ module RubyLsp
202
194
  count
203
195
  end
204
196
 
205
- sig { void }
197
+ #: -> void
206
198
  def auto_indent_after_end_keyword
207
199
  current_line = @lines[@position[:line]]
208
200
  return unless current_line && current_line.strip == "end"
@@ -7,27 +7,22 @@ module RubyLsp
7
7
  # [prepare_rename](https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareRename)
8
8
  # # request checks the validity of a rename operation at a given location.
9
9
  class PrepareRename < Request
10
- extend T::Sig
11
10
  include Support::Common
12
11
 
13
- sig do
14
- params(
15
- document: RubyDocument,
16
- position: T::Hash[Symbol, T.untyped],
17
- ).void
18
- end
12
+ #: (RubyDocument document, Hash[Symbol, untyped] position) -> void
19
13
  def initialize(document, position)
20
14
  super()
21
15
  @document = document
22
- @position = T.let(position, T::Hash[Symbol, Integer])
16
+ @position = position #: Hash[Symbol, Integer]
23
17
  end
24
18
 
25
- sig { override.returns(T.nilable(Interface::Range)) }
19
+ # @override
20
+ #: -> Interface::Range?
26
21
  def perform
27
22
  char_position, _ = @document.find_index_by_position(@position)
28
23
 
29
24
  node_context = RubyDocument.locate(
30
- @document.parse_result.value,
25
+ @document.ast,
31
26
  char_position,
32
27
  node_types: [Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode],
33
28
  code_units_cache: @document.code_units_cache,
@@ -9,26 +9,16 @@ module RubyLsp
9
9
  #
10
10
  # Currently only supports supertypes due to a limitation of the index.
11
11
  class PrepareTypeHierarchy < Request
12
- extend T::Sig
13
-
14
12
  include Support::Common
15
13
 
16
14
  class << self
17
- extend T::Sig
18
-
19
- sig { returns(Interface::TypeHierarchyOptions) }
15
+ #: -> Interface::TypeHierarchyOptions
20
16
  def provider
21
17
  Interface::TypeHierarchyOptions.new
22
18
  end
23
19
  end
24
20
 
25
- sig do
26
- params(
27
- document: T.any(RubyDocument, ERBDocument),
28
- index: RubyIndexer::Index,
29
- position: T::Hash[Symbol, T.untyped],
30
- ).void
31
- end
21
+ #: ((RubyDocument | ERBDocument) document, RubyIndexer::Index index, Hash[Symbol, untyped] position) -> void
32
22
  def initialize(document, index, position)
33
23
  super()
34
24
 
@@ -37,7 +27,8 @@ module RubyLsp
37
27
  @position = position
38
28
  end
39
29
 
40
- sig { override.returns(T.nilable(T::Array[Interface::TypeHierarchyItem])) }
30
+ # @override
31
+ #: -> Array[Interface::TypeHierarchyItem]?
41
32
  def perform
42
33
  context = @document.locate_node(
43
34
  @position,
@@ -58,8 +49,7 @@ module RubyLsp
58
49
 
59
50
  # While the spec allows for multiple entries, VSCode seems to only support one
60
51
  # We'll just return the first one for now
61
- first_entry = T.must(entries.first)
62
-
52
+ first_entry = entries.first #: as !nil
63
53
  range = range_from_location(first_entry.location)
64
54
 
65
55
  [
@@ -6,18 +6,17 @@ module RubyLsp
6
6
  # The [range formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_rangeFormatting)
7
7
  # is used to format a selection or to format on paste.
8
8
  class RangeFormatting < Request
9
- extend T::Sig
10
-
11
- sig { params(global_state: GlobalState, document: RubyDocument, params: T::Hash[Symbol, T.untyped]).void }
9
+ #: (GlobalState global_state, RubyDocument document, Hash[Symbol, untyped] params) -> void
12
10
  def initialize(global_state, document, params)
13
11
  super()
14
12
  @document = document
15
- @uri = T.let(document.uri, URI::Generic)
13
+ @uri = document.uri #: URI::Generic
16
14
  @params = params
17
- @active_formatter = T.let(global_state.active_formatter, T.nilable(Support::Formatter))
15
+ @active_formatter = global_state.active_formatter #: Support::Formatter?
18
16
  end
19
17
 
20
- sig { override.returns(T.nilable(T::Array[Interface::TextEdit])) }
18
+ # @override
19
+ #: -> Array[Interface::TextEdit]?
21
20
  def perform
22
21
  return unless @active_formatter
23
22
  return if @document.syntax_error?
@@ -7,33 +7,26 @@ module RubyLsp
7
7
  # [references](https://microsoft.github.io/language-server-protocol/specification#textDocument_references)
8
8
  # request finds all references for the selected symbol.
9
9
  class References < Request
10
- extend T::Sig
11
10
  include Support::Common
12
11
 
13
- sig do
14
- params(
15
- global_state: GlobalState,
16
- store: Store,
17
- document: T.any(RubyDocument, ERBDocument),
18
- params: T::Hash[Symbol, T.untyped],
19
- ).void
20
- end
12
+ #: (GlobalState global_state, Store store, (RubyDocument | ERBDocument) document, Hash[Symbol, untyped] params) -> void
21
13
  def initialize(global_state, store, document, params)
22
14
  super()
23
15
  @global_state = global_state
24
16
  @store = store
25
17
  @document = document
26
18
  @params = params
27
- @locations = T.let([], T::Array[Interface::Location])
19
+ @locations = [] #: Array[Interface::Location]
28
20
  end
29
21
 
30
- sig { override.returns(T::Array[Interface::Location]) }
22
+ # @override
23
+ #: -> Array[Interface::Location]
31
24
  def perform
32
25
  position = @params[:position]
33
26
  char_position, _ = @document.find_index_by_position(position)
34
27
 
35
28
  node_context = RubyDocument.locate(
36
- @document.parse_result.value,
29
+ @document.ast,
37
30
  char_position,
38
31
  node_types: [
39
32
  Prism::ConstantReadNode,
@@ -62,22 +55,7 @@ module RubyLsp
62
55
  )
63
56
  end
64
57
 
65
- target = T.cast(
66
- target,
67
- T.any(
68
- Prism::ConstantReadNode,
69
- Prism::ConstantPathNode,
70
- Prism::ConstantPathTargetNode,
71
- Prism::InstanceVariableAndWriteNode,
72
- Prism::InstanceVariableOperatorWriteNode,
73
- Prism::InstanceVariableOrWriteNode,
74
- Prism::InstanceVariableReadNode,
75
- Prism::InstanceVariableTargetNode,
76
- Prism::InstanceVariableWriteNode,
77
- Prism::CallNode,
78
- Prism::DefNode,
79
- ),
80
- )
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,
81
59
 
82
60
  reference_target = create_reference_target(target, node_context)
83
61
  return @locations unless reference_target
@@ -88,7 +66,7 @@ module RubyLsp
88
66
  # of reading from disk
89
67
  next if @store.key?(uri)
90
68
 
91
- parse_result = Prism.parse_file(path)
69
+ parse_result = Prism.parse_lex_file(path)
92
70
  collect_references(reference_target, parse_result, uri)
93
71
  rescue Errno::EISDIR, Errno::ENOENT
94
72
  # If `path` is a directory, just ignore it and continue. If the file doesn't exist, then we also ignore it.
@@ -103,24 +81,7 @@ module RubyLsp
103
81
 
104
82
  private
105
83
 
106
- sig do
107
- params(
108
- target_node: T.any(
109
- Prism::ConstantReadNode,
110
- Prism::ConstantPathNode,
111
- Prism::ConstantPathTargetNode,
112
- Prism::InstanceVariableAndWriteNode,
113
- Prism::InstanceVariableOperatorWriteNode,
114
- Prism::InstanceVariableOrWriteNode,
115
- Prism::InstanceVariableReadNode,
116
- Prism::InstanceVariableTargetNode,
117
- Prism::InstanceVariableWriteNode,
118
- Prism::CallNode,
119
- Prism::DefNode,
120
- ),
121
- node_context: NodeContext,
122
- ).returns(T.nilable(RubyIndexer::ReferenceFinder::Target))
123
- end
84
+ #: ((Prism::ConstantReadNode | Prism::ConstantPathNode | Prism::ConstantPathTargetNode | Prism::InstanceVariableAndWriteNode | Prism::InstanceVariableOperatorWriteNode | Prism::InstanceVariableOrWriteNode | Prism::InstanceVariableReadNode | Prism::InstanceVariableTargetNode | Prism::InstanceVariableWriteNode | Prism::CallNode | Prism::DefNode) target_node, NodeContext node_context) -> RubyIndexer::ReferenceFinder::Target?
124
85
  def create_reference_target(target_node, node_context)
125
86
  case target_node
126
87
  when Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode
@@ -130,7 +91,8 @@ module RubyLsp
130
91
  entries = @global_state.index.resolve(name, node_context.nesting)
131
92
  return unless entries
132
93
 
133
- fully_qualified_name = T.must(entries.first).name
94
+ fully_qualified_name = entries.first #: as !nil
95
+ .name
134
96
  RubyIndexer::ReferenceFinder::ConstTarget.new(fully_qualified_name)
135
97
  when
136
98
  Prism::InstanceVariableAndWriteNode,
@@ -139,19 +101,17 @@ module RubyLsp
139
101
  Prism::InstanceVariableReadNode,
140
102
  Prism::InstanceVariableTargetNode,
141
103
  Prism::InstanceVariableWriteNode
142
- 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)
143
109
  when Prism::CallNode, Prism::DefNode
144
110
  RubyIndexer::ReferenceFinder::MethodTarget.new(target_node.name.to_s)
145
111
  end
146
112
  end
147
113
 
148
- sig do
149
- params(
150
- target: RubyIndexer::ReferenceFinder::Target,
151
- parse_result: Prism::ParseResult,
152
- uri: URI::Generic,
153
- ).void
154
- end
114
+ #: (RubyIndexer::ReferenceFinder::Target target, Prism::LexResult parse_result, URI::Generic uri) -> void
155
115
  def collect_references(target, parse_result, uri)
156
116
  dispatcher = Prism::Dispatcher.new
157
117
  finder = RubyIndexer::ReferenceFinder.new(
@@ -161,7 +121,7 @@ module RubyLsp
161
121
  uri,
162
122
  include_declarations: @params.dig(:context, :includeDeclaration) || true,
163
123
  )
164
- dispatcher.visit(parse_result.value)
124
+ dispatcher.visit(parse_result.value.first)
165
125
 
166
126
  finder.references.each do |reference|
167
127
  @locations << Interface::Location.new(
@@ -7,43 +7,34 @@ module RubyLsp
7
7
  # [rename](https://microsoft.github.io/language-server-protocol/specification#textDocument_rename)
8
8
  # request renames all instances of a symbol in a document.
9
9
  class Rename < Request
10
- extend T::Sig
11
10
  include Support::Common
12
11
 
13
12
  class InvalidNameError < StandardError; end
14
13
 
15
14
  class << self
16
- extend T::Sig
17
-
18
- sig { returns(Interface::RenameOptions) }
15
+ #: -> Interface::RenameOptions
19
16
  def provider
20
17
  Interface::RenameOptions.new(prepare_provider: true)
21
18
  end
22
19
  end
23
20
 
24
- sig do
25
- params(
26
- global_state: GlobalState,
27
- store: Store,
28
- document: T.any(RubyDocument, ERBDocument),
29
- params: T::Hash[Symbol, T.untyped],
30
- ).void
31
- end
21
+ #: (GlobalState global_state, Store store, (RubyDocument | ERBDocument) document, Hash[Symbol, untyped] params) -> void
32
22
  def initialize(global_state, store, document, params)
33
23
  super()
34
24
  @global_state = global_state
35
25
  @store = store
36
26
  @document = document
37
- @position = T.let(params[:position], T::Hash[Symbol, Integer])
38
- @new_name = T.let(params[:newName], String)
27
+ @position = params[:position] #: Hash[Symbol, Integer]
28
+ @new_name = params[:newName] #: String
39
29
  end
40
30
 
41
- sig { override.returns(T.nilable(Interface::WorkspaceEdit)) }
31
+ # @override
32
+ #: -> Interface::WorkspaceEdit?
42
33
  def perform
43
34
  char_position, _ = @document.find_index_by_position(@position)
44
35
 
45
36
  node_context = RubyDocument.locate(
46
- @document.parse_result.value,
37
+ @document.ast,
47
38
  char_position,
48
39
  node_types: [Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode],
49
40
  code_units_cache: @document.code_units_cache,
@@ -60,10 +51,7 @@ module RubyLsp
60
51
  )
61
52
  end
62
53
 
63
- target = T.cast(
64
- target,
65
- T.any(Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode),
66
- )
54
+ target = target #: as Prism::ConstantReadNode | Prism::ConstantPathNode | Prism::ConstantPathTargetNode
67
55
 
68
56
  name = RubyIndexer::Index.constant_name(target)
69
57
  return unless name
@@ -72,10 +60,11 @@ module RubyLsp
72
60
  return unless entries
73
61
 
74
62
  if (conflict_entries = @global_state.index.resolve(@new_name, node_context.nesting))
75
- raise InvalidNameError, "The new name is already in use by #{T.must(conflict_entries.first).name}"
63
+ raise InvalidNameError, "The new name is already in use by #{conflict_entries.first&.name}"
76
64
  end
77
65
 
78
- fully_qualified_name = T.must(entries.first).name
66
+ fully_qualified_name = entries.first #: as !nil
67
+ .name
79
68
  reference_target = RubyIndexer::ReferenceFinder::ConstTarget.new(fully_qualified_name)
80
69
  changes = collect_text_edits(reference_target, name)
81
70
 
@@ -100,20 +89,15 @@ module RubyLsp
100
89
 
101
90
  private
102
91
 
103
- sig do
104
- params(
105
- fully_qualified_name: String,
106
- document_changes: T::Array[T.any(Interface::RenameFile, Interface::TextDocumentEdit)],
107
- ).void
108
- end
92
+ #: (String fully_qualified_name, Array[(Interface::RenameFile | Interface::TextDocumentEdit)] document_changes) -> void
109
93
  def collect_file_renames(fully_qualified_name, document_changes)
110
94
  # Check if the declarations of the symbol being renamed match the file name. In case they do, we automatically
111
95
  # rename the files for the user.
112
96
  #
113
97
  # We also look for an associated test file and rename it too
114
- short_name = T.must(fully_qualified_name.split("::").last)
98
+ short_name = fully_qualified_name.split("::").last #: as !nil
115
99
 
116
- T.must(@global_state.index[fully_qualified_name]).each do |entry|
100
+ @global_state.index[fully_qualified_name]&.each do |entry|
117
101
  # Do not rename files that are not part of the workspace
118
102
  uri = entry.uri
119
103
  file_path = uri.full_path
@@ -126,7 +110,9 @@ module RubyLsp
126
110
  file_name = file_from_constant_name(short_name)
127
111
 
128
112
  if "#{file_name}.rb" == entry.file_name
129
- new_file_name = file_from_constant_name(T.must(@new_name.split("::").last))
113
+ new_file_name = file_from_constant_name(
114
+ @new_name.split("::").last, #: as !nil
115
+ )
130
116
 
131
117
  new_uri = URI::Generic.from_path(path: File.join(
132
118
  File.dirname(file_path),
@@ -139,12 +125,7 @@ module RubyLsp
139
125
  end
140
126
  end
141
127
 
142
- sig do
143
- params(
144
- target: RubyIndexer::ReferenceFinder::Target,
145
- name: String,
146
- ).returns(T::Hash[String, T::Array[Interface::TextEdit]])
147
- end
128
+ #: (RubyIndexer::ReferenceFinder::Target target, String name) -> Hash[String, Array[Interface::TextEdit]]
148
129
  def collect_text_edits(target, name)
149
130
  changes = {}
150
131
 
@@ -155,39 +136,34 @@ module RubyLsp
155
136
  next if @store.key?(uri)
156
137
 
157
138
  parse_result = Prism.parse_file(path)
158
- edits = collect_changes(target, parse_result, name, uri)
139
+ edits = collect_changes(target, parse_result.value, name, uri)
159
140
  changes[uri.to_s] = edits unless edits.empty?
160
141
  rescue Errno::EISDIR, Errno::ENOENT
161
142
  # If `path` is a directory, just ignore it and continue. If the file doesn't exist, then we also ignore it.
162
143
  end
163
144
 
164
145
  @store.each do |uri, document|
165
- 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)
166
149
  changes[uri] = edits unless edits.empty?
167
150
  end
168
151
 
169
152
  changes
170
153
  end
171
154
 
172
- sig do
173
- params(
174
- target: RubyIndexer::ReferenceFinder::Target,
175
- parse_result: Prism::ParseResult,
176
- name: String,
177
- uri: URI::Generic,
178
- ).returns(T::Array[Interface::TextEdit])
179
- end
180
- 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)
181
157
  dispatcher = Prism::Dispatcher.new
182
158
  finder = RubyIndexer::ReferenceFinder.new(target, @global_state.index, dispatcher, uri)
183
- dispatcher.visit(parse_result.value)
159
+ dispatcher.visit(ast)
184
160
 
185
161
  finder.references.map do |reference|
186
162
  adjust_reference_for_edit(name, reference)
187
163
  end
188
164
  end
189
165
 
190
- sig { params(name: String, reference: RubyIndexer::ReferenceFinder::Reference).returns(Interface::TextEdit) }
166
+ #: (String name, RubyIndexer::ReferenceFinder::Reference reference) -> Interface::TextEdit
191
167
  def adjust_reference_for_edit(name, reference)
192
168
  # The reference may include a namespace in front. We need to check if the rename new name includes namespaces
193
169
  # and then adjust both the text and the location to produce the correct edit
@@ -197,7 +173,7 @@ module RubyLsp
197
173
  Interface::TextEdit.new(range: range_from_location(location), new_text: new_text)
198
174
  end
199
175
 
200
- sig { params(constant_name: String).returns(String) }
176
+ #: (String constant_name) -> String
201
177
  def file_from_constant_name(constant_name)
202
178
  constant_name
203
179
  .gsub(/([a-z])([A-Z])|([A-Z])([A-Z][a-z])/, '\1\3_\2\4')
@@ -3,28 +3,21 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
+ # @abstract
6
7
  class Request
7
- extend T::Sig
8
- extend T::Generic
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
 
19
18
  # Signals to the client that the request should be delegated to the language server server for the host language
20
19
  # in ERB files
21
- sig do
22
- params(
23
- global_state: GlobalState,
24
- document: Document[T.untyped],
25
- char_position: Integer,
26
- ).void
27
- end
20
+ #: (GlobalState global_state, Document[untyped] document, Integer char_position) -> void
28
21
  def delegate_request_if_needed!(global_state, document, char_position)
29
22
  if global_state.client_capabilities.supports_request_delegation &&
30
23
  document.is_a?(ERBDocument) &&
@@ -34,7 +27,7 @@ module RubyLsp
34
27
  end
35
28
 
36
29
  # Checks if a location covers a position
37
- sig { params(location: Prism::Location, position: T.untyped).returns(T::Boolean) }
30
+ #: (Prism::Location location, untyped position) -> bool
38
31
  def cover?(location, position)
39
32
  start_covered =
40
33
  location.start_line - 1 < position[:line] ||
@@ -61,18 +54,13 @@ module RubyLsp
61
54
  # # ^ Going to definition here should go to Foo::Bar
62
55
  # #^ Going to definition here should go to Foo
63
56
  # ```
64
- sig do
65
- params(
66
- target: Prism::Node,
67
- parent: Prism::Node,
68
- position: T::Hash[Symbol, Integer],
69
- ).returns(Prism::Node)
70
- end
57
+ #: (Prism::Node target, Prism::Node parent, Hash[Symbol, Integer] position) -> Prism::Node
71
58
  def determine_target(target, parent, position)
72
59
  return target unless parent.is_a?(Prism::ConstantPathNode)
73
60
 
74
- target = T.let(parent, Prism::Node)
75
- parent = T.let(T.cast(target, Prism::ConstantPathNode).parent, T.nilable(Prism::Node))
61
+ target = parent #: Prism::Node
62
+ parent = target #: as Prism::ConstantPathNode
63
+ .parent #: Prism::Node?
76
64
 
77
65
  while parent && cover?(parent.location, position)
78
66
  target = parent
@@ -83,7 +71,7 @@ module RubyLsp
83
71
  end
84
72
 
85
73
  # Checks if a given location covers the position requested
86
- sig { params(location: T.nilable(Prism::Location), position: T::Hash[Symbol, T.untyped]).returns(T::Boolean) }
74
+ #: (Prism::Location? location, Hash[Symbol, untyped] position) -> bool
87
75
  def covers_position?(location, position)
88
76
  return false unless location
89
77