ruby-lsp 0.22.1 → 0.23.10

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +12 -11
  5. data/exe/ruby-lsp-check +5 -5
  6. data/exe/ruby-lsp-launcher +41 -15
  7. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
  8. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +191 -100
  9. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
  10. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +174 -61
  11. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +12 -0
  12. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
  13. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +82 -61
  14. data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
  15. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +36 -0
  16. data/lib/ruby_indexer/ruby_indexer.rb +2 -1
  17. data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
  18. data/lib/ruby_indexer/test/classes_and_modules_test.rb +30 -6
  19. data/lib/ruby_indexer/test/configuration_test.rb +116 -51
  20. data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
  21. data/lib/ruby_indexer/test/index_test.rb +143 -44
  22. data/lib/ruby_indexer/test/instance_variables_test.rb +20 -0
  23. data/lib/ruby_indexer/test/method_test.rb +86 -8
  24. data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
  25. data/lib/ruby_indexer/test/reference_finder_test.rb +90 -2
  26. data/lib/ruby_indexer/test/test_case.rb +2 -2
  27. data/lib/ruby_indexer/test/uri_test.rb +72 -0
  28. data/lib/ruby_lsp/addon.rb +9 -0
  29. data/lib/ruby_lsp/base_server.rb +17 -18
  30. data/lib/ruby_lsp/client_capabilities.rb +7 -1
  31. data/lib/ruby_lsp/document.rb +72 -10
  32. data/lib/ruby_lsp/erb_document.rb +5 -3
  33. data/lib/ruby_lsp/global_state.rb +42 -3
  34. data/lib/ruby_lsp/internal.rb +3 -1
  35. data/lib/ruby_lsp/listeners/code_lens.rb +9 -5
  36. data/lib/ruby_lsp/listeners/completion.rb +78 -6
  37. data/lib/ruby_lsp/listeners/definition.rb +80 -19
  38. data/lib/ruby_lsp/listeners/document_highlight.rb +3 -2
  39. data/lib/ruby_lsp/listeners/document_link.rb +21 -3
  40. data/lib/ruby_lsp/listeners/document_symbol.rb +12 -1
  41. data/lib/ruby_lsp/listeners/folding_ranges.rb +1 -1
  42. data/lib/ruby_lsp/listeners/hover.rb +59 -2
  43. data/lib/ruby_lsp/load_sorbet.rb +3 -3
  44. data/lib/ruby_lsp/rbs_document.rb +2 -2
  45. data/lib/ruby_lsp/requests/code_action_resolve.rb +90 -6
  46. data/lib/ruby_lsp/requests/code_actions.rb +57 -1
  47. data/lib/ruby_lsp/requests/completion.rb +8 -1
  48. data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
  49. data/lib/ruby_lsp/requests/definition.rb +7 -1
  50. data/lib/ruby_lsp/requests/diagnostics.rb +1 -1
  51. data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
  52. data/lib/ruby_lsp/requests/folding_ranges.rb +2 -6
  53. data/lib/ruby_lsp/requests/formatting.rb +2 -6
  54. data/lib/ruby_lsp/requests/hover.rb +1 -1
  55. data/lib/ruby_lsp/requests/on_type_formatting.rb +2 -2
  56. data/lib/ruby_lsp/requests/prepare_rename.rb +51 -0
  57. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
  58. data/lib/ruby_lsp/requests/references.rb +29 -2
  59. data/lib/ruby_lsp/requests/rename.rb +17 -7
  60. data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
  61. data/lib/ruby_lsp/requests/show_syntax_tree.rb +1 -4
  62. data/lib/ruby_lsp/requests/signature_help.rb +1 -1
  63. data/lib/ruby_lsp/requests/support/common.rb +2 -9
  64. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +3 -3
  65. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +13 -13
  66. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
  67. data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -3
  68. data/lib/ruby_lsp/ruby_document.rb +80 -6
  69. data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
  70. data/lib/ruby_lsp/server.rb +205 -61
  71. data/lib/ruby_lsp/setup_bundler.rb +50 -43
  72. data/lib/ruby_lsp/store.rb +7 -7
  73. data/lib/ruby_lsp/test_helper.rb +45 -11
  74. data/lib/ruby_lsp/type_inferrer.rb +60 -31
  75. data/lib/ruby_lsp/utils.rb +63 -3
  76. metadata +8 -8
  77. data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
@@ -13,63 +13,62 @@ module RubyIndexer
13
13
 
14
14
  def test_load_configuration_executes_configure_block
15
15
  @config.apply_config({ "excluded_patterns" => ["**/fixtures/**/*.rb"] })
16
- indexables = @config.indexables
16
+ uris = @config.indexable_uris
17
17
 
18
- assert(indexables.none? { |indexable| indexable.full_path.include?("test/fixtures") })
19
- assert(indexables.none? { |indexable| indexable.full_path.include?("minitest-reporters") })
20
- assert(indexables.none? { |indexable| indexable.full_path.include?("ansi") })
21
- assert(indexables.any? { |indexable| indexable.full_path.include?("sorbet-runtime") })
22
- assert(indexables.none? { |indexable| indexable.full_path == __FILE__ })
18
+ bundle_path = Bundler.bundle_path.join("gems")
19
+
20
+ assert(uris.none? { |uri| uri.full_path.include?("test/fixtures") })
21
+ assert(uris.none? { |uri| uri.full_path.include?(bundle_path.join("minitest-reporters").to_s) })
22
+ assert(uris.none? { |uri| uri.full_path.include?(bundle_path.join("ansi").to_s) })
23
+ assert(uris.any? { |uri| uri.full_path.include?(bundle_path.join("sorbet-runtime").to_s) })
24
+ assert(uris.none? { |uri| uri.full_path == __FILE__ })
23
25
  end
24
26
 
25
- def test_indexables_have_expanded_full_paths
27
+ def test_indexable_uris_have_expanded_full_paths
26
28
  @config.apply_config({ "included_patterns" => ["**/*.rb"] })
27
- indexables = @config.indexables
29
+ uris = @config.indexable_uris
28
30
 
29
31
  # All paths should be expanded
30
- assert(indexables.all? { |indexable| File.absolute_path?(indexable.full_path) })
32
+ assert(uris.all? { |uri| File.absolute_path?(uri.full_path) })
31
33
  end
32
34
 
33
- def test_indexables_only_includes_gem_require_paths
34
- indexables = @config.indexables
35
+ def test_indexable_uris_only_includes_gem_require_paths
36
+ uris = @config.indexable_uris
35
37
 
36
38
  Bundler.locked_gems.specs.each do |lazy_spec|
37
39
  next if lazy_spec.name == "ruby-lsp"
38
40
 
39
41
  spec = Gem::Specification.find_by_name(lazy_spec.name)
40
- assert(indexables.none? { |indexable| indexable.full_path.start_with?("#{spec.full_gem_path}/test/") })
42
+ assert(uris.none? { |uri| uri.full_path.start_with?("#{spec.full_gem_path}/test/") })
41
43
  rescue Gem::MissingSpecError
42
44
  # Transitive dependencies might be missing when running tests on Windows
43
45
  end
44
46
  end
45
47
 
46
- def test_indexables_does_not_include_default_gem_path_when_in_bundle
47
- indexables = @config.indexables
48
-
49
- assert(
50
- indexables.none? { |indexable| indexable.full_path.start_with?("#{RbConfig::CONFIG["rubylibdir"]}/psych") },
51
- )
48
+ def test_indexable_uris_does_not_include_default_gem_path_when_in_bundle
49
+ uris = @config.indexable_uris
50
+ assert(uris.none? { |uri| uri.full_path.start_with?("#{RbConfig::CONFIG["rubylibdir"]}/psych") })
52
51
  end
53
52
 
54
- def test_indexables_includes_default_gems
55
- indexables = @config.indexables.map(&:full_path)
53
+ def test_indexable_uris_includes_default_gems
54
+ paths = @config.indexable_uris.map(&:full_path)
56
55
 
57
- assert_includes(indexables, "#{RbConfig::CONFIG["rubylibdir"]}/pathname.rb")
58
- assert_includes(indexables, "#{RbConfig::CONFIG["rubylibdir"]}/ipaddr.rb")
59
- assert_includes(indexables, "#{RbConfig::CONFIG["rubylibdir"]}/erb.rb")
56
+ assert_includes(paths, "#{RbConfig::CONFIG["rubylibdir"]}/pathname.rb")
57
+ assert_includes(paths, "#{RbConfig::CONFIG["rubylibdir"]}/ipaddr.rb")
58
+ assert_includes(paths, "#{RbConfig::CONFIG["rubylibdir"]}/erb.rb")
60
59
  end
61
60
 
62
- def test_indexables_includes_project_files
63
- indexables = @config.indexables.map(&:full_path)
61
+ def test_indexable_uris_includes_project_files
62
+ paths = @config.indexable_uris.map(&:full_path)
64
63
 
65
64
  Dir.glob("#{Dir.pwd}/lib/**/*.rb").each do |path|
66
65
  next if path.end_with?("_test.rb")
67
66
 
68
- assert_includes(indexables, path)
67
+ assert_includes(paths, path)
69
68
  end
70
69
  end
71
70
 
72
- def test_indexables_avoids_duplicates_if_bundle_path_is_inside_project
71
+ def test_indexable_uris_avoids_duplicates_if_bundle_path_is_inside_project
73
72
  Bundler.settings.temporary(path: "vendor/bundle") do
74
73
  config = Configuration.new
75
74
 
@@ -77,33 +76,32 @@ module RubyIndexer
77
76
  end
78
77
  end
79
78
 
80
- def test_indexables_does_not_include_gems_own_installed_files
81
- indexables = @config.indexables
82
- indexables_inside_bundled_lsp = indexables.select do |indexable|
83
- indexable.full_path.start_with?(Bundler.bundle_path.join("gems", "ruby-lsp").to_s)
79
+ def test_indexable_uris_does_not_include_gems_own_installed_files
80
+ uris = @config.indexable_uris
81
+ uris_inside_bundled_lsp = uris.select do |uri|
82
+ uri.full_path.start_with?(Bundler.bundle_path.join("gems", "ruby-lsp").to_s)
84
83
  end
85
84
 
86
85
  assert_empty(
87
- indexables_inside_bundled_lsp,
88
- "Indexables should not include files from the gem currently being worked on. " \
89
- "Included: #{indexables_inside_bundled_lsp.map(&:full_path)}",
86
+ uris_inside_bundled_lsp,
87
+ "Indexable URIs should not include files from the gem currently being worked on. " \
88
+ "Included: #{uris_inside_bundled_lsp.map(&:full_path)}",
90
89
  )
91
90
  end
92
91
 
93
- def test_indexables_does_not_include_non_ruby_files_inside_rubylibdir
92
+ def test_indexable_uris_does_not_include_non_ruby_files_inside_rubylibdir
94
93
  path = Pathname.new(RbConfig::CONFIG["rubylibdir"]).join("extra_file.txt").to_s
95
94
  FileUtils.touch(path)
96
- indexables = @config.indexables
97
95
 
98
- assert(indexables.none? { |indexable| indexable.full_path == path })
96
+ uris = @config.indexable_uris
97
+ assert(uris.none? { |uri| uri.full_path == path })
99
98
  ensure
100
99
  FileUtils.rm(T.must(path))
101
100
  end
102
101
 
103
102
  def test_paths_are_unique
104
- indexables = @config.indexables
105
-
106
- assert_equal(indexables.uniq.length, indexables.length)
103
+ uris = @config.indexable_uris
104
+ assert_equal(uris.uniq.length, uris.length)
107
105
  end
108
106
 
109
107
  def test_configuration_raises_for_unknown_keys
@@ -132,7 +130,7 @@ module RubyIndexer
132
130
  end
133
131
  end
134
132
 
135
- def test_indexables_respect_given_workspace_path
133
+ def test_indexable_uris_respect_given_workspace_path
136
134
  Dir.mktmpdir do |dir|
137
135
  FileUtils.mkdir(File.join(dir, "ignore"))
138
136
  FileUtils.touch(File.join(dir, "ignore", "file0.rb"))
@@ -141,21 +139,21 @@ module RubyIndexer
141
139
 
142
140
  @config.apply_config({ "excluded_patterns" => ["ignore/**/*.rb"] })
143
141
  @config.workspace_path = dir
144
- indexables = @config.indexables
145
142
 
146
- assert(indexables.none? { |indexable| indexable.full_path.start_with?(File.join(dir, "ignore")) })
143
+ uris = @config.indexable_uris
144
+ assert(uris.none? { |uri| uri.full_path.start_with?(File.join(dir, "ignore")) })
147
145
 
148
- # After switching the workspace path, all indexables will be found in one of these places:
146
+ # After switching the workspace path, all indexable URIs will be found in one of these places:
149
147
  # - The new workspace path
150
148
  # - The Ruby LSP's own code (because Bundler is requiring the dependency from source)
151
149
  # - Bundled gems
152
150
  # - Default gems
153
151
  assert(
154
- indexables.all? do |i|
155
- i.full_path.start_with?(dir) ||
156
- i.full_path.start_with?(File.join(Dir.pwd, "lib")) ||
157
- i.full_path.start_with?(Bundler.bundle_path.to_s) ||
158
- i.full_path.start_with?(RbConfig::CONFIG["rubylibdir"])
152
+ uris.all? do |u|
153
+ u.full_path.start_with?(dir) ||
154
+ u.full_path.start_with?(File.join(Dir.pwd, "lib")) ||
155
+ u.full_path.start_with?(Bundler.bundle_path.to_s) ||
156
+ u.full_path.start_with?(RbConfig::CONFIG["rubylibdir"])
159
157
  end,
160
158
  )
161
159
  end
@@ -166,8 +164,75 @@ module RubyIndexer
166
164
  FileUtils.touch(File.join(dir, "find_me.rb"))
167
165
  @config.workspace_path = dir
168
166
 
169
- indexables = @config.indexables
170
- assert(indexables.find { |i| File.basename(i.full_path) == "find_me.rb" })
167
+ uris = @config.indexable_uris
168
+ assert(uris.find { |u| File.basename(u.full_path) == "find_me.rb" })
169
+ end
170
+ end
171
+
172
+ def test_transitive_dependencies_for_non_dev_gems_are_not_excluded
173
+ Dir.mktmpdir do |dir|
174
+ Dir.chdir(dir) do
175
+ # Both IRB and debug depend on reline. Since IRB is in the default group, reline should not be excluded
176
+ File.write(File.join(dir, "Gemfile"), <<~RUBY)
177
+ source "https://rubygems.org"
178
+ gem "irb"
179
+ gem "ruby-lsp", path: "#{Bundler.root}"
180
+
181
+ group :development do
182
+ gem "debug"
183
+ end
184
+ RUBY
185
+
186
+ Bundler.with_unbundled_env do
187
+ capture_subprocess_io do
188
+ system("bundle install")
189
+ end
190
+
191
+ stdout, _stderr = capture_subprocess_io do
192
+ script = [
193
+ "require \"ruby_lsp/internal\"",
194
+ "print RubyIndexer::Configuration.new.instance_variable_get(:@excluded_gems).join(\",\")",
195
+ ].join(";")
196
+ system("bundle exec ruby -e '#{script}'")
197
+ end
198
+
199
+ excluded_gems = stdout.split(",")
200
+ assert_includes(excluded_gems, "debug")
201
+ refute_includes(excluded_gems, "reline")
202
+ refute_includes(excluded_gems, "irb")
203
+ end
204
+ end
205
+ end
206
+ end
207
+
208
+ def test_does_not_fail_if_there_are_missing_specs_due_to_platform_constraints
209
+ Dir.mktmpdir do |dir|
210
+ Dir.chdir(dir) do
211
+ File.write(File.join(dir, "Gemfile"), <<~RUBY)
212
+ source "https://rubygems.org"
213
+ gem "ruby-lsp", path: "#{Bundler.root}"
214
+
215
+ platforms :windows do
216
+ gem "tzinfo"
217
+ gem "tzinfo-data"
218
+ end
219
+ RUBY
220
+
221
+ Bundler.with_unbundled_env do
222
+ capture_subprocess_io { system("bundle install") }
223
+
224
+ _stdout, stderr = capture_subprocess_io do
225
+ script = [
226
+ "require \"ruby_lsp/internal\"",
227
+ "RubyIndexer::Configuration.new.indexable_uris",
228
+ ].join(";")
229
+
230
+ system("bundle exec ruby -e '#{script}'")
231
+ end
232
+
233
+ assert_empty(stderr)
234
+ end
235
+ end
171
236
  end
172
237
  end
173
238
  end
@@ -172,7 +172,7 @@ module RubyIndexer
172
172
  end
173
173
 
174
174
  assert_match(
175
- %r{Indexing error in /fake/path/foo\.rb with 'TestEnhancement' on call node enter enhancement},
175
+ %r{Indexing error in file:///fake/path/foo\.rb with 'TestEnhancement' on call node enter enhancement},
176
176
  stderr,
177
177
  )
178
178
  # The module should still be indexed
@@ -205,7 +205,7 @@ module RubyIndexer
205
205
  end
206
206
 
207
207
  assert_match(
208
- %r{Indexing error in /fake/path/foo\.rb with 'TestEnhancement' on call node leave enhancement},
208
+ %r{Indexing error in file:///fake/path/foo\.rb with 'TestEnhancement' on call node leave enhancement},
209
209
  stderr,
210
210
  )
211
211
  # The module should still be indexed