ruby-lsp 0.17.2 → 0.17.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/VERSION +1 -1
  4. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +280 -74
  5. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +102 -102
  6. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +234 -56
  7. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +147 -0
  8. data/lib/ruby_indexer/ruby_indexer.rb +1 -0
  9. data/lib/ruby_indexer/test/classes_and_modules_test.rb +49 -2
  10. data/lib/ruby_indexer/test/configuration_test.rb +1 -1
  11. data/lib/ruby_indexer/test/constant_test.rb +1 -1
  12. data/lib/ruby_indexer/test/index_test.rb +702 -71
  13. data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
  14. data/lib/ruby_indexer/test/method_test.rb +74 -24
  15. data/lib/ruby_indexer/test/rbs_indexer_test.rb +67 -0
  16. data/lib/ruby_indexer/test/test_case.rb +7 -0
  17. data/lib/ruby_lsp/document.rb +37 -8
  18. data/lib/ruby_lsp/global_state.rb +43 -18
  19. data/lib/ruby_lsp/internal.rb +2 -0
  20. data/lib/ruby_lsp/listeners/code_lens.rb +2 -2
  21. data/lib/ruby_lsp/listeners/completion.rb +53 -14
  22. data/lib/ruby_lsp/listeners/definition.rb +11 -7
  23. data/lib/ruby_lsp/listeners/hover.rb +14 -7
  24. data/lib/ruby_lsp/listeners/signature_help.rb +5 -2
  25. data/lib/ruby_lsp/node_context.rb +6 -1
  26. data/lib/ruby_lsp/requests/completion.rb +5 -4
  27. data/lib/ruby_lsp/requests/completion_resolve.rb +8 -0
  28. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +88 -0
  29. data/lib/ruby_lsp/requests/support/common.rb +19 -1
  30. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +12 -4
  31. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +91 -0
  32. data/lib/ruby_lsp/requests/workspace_symbol.rb +1 -21
  33. data/lib/ruby_lsp/requests.rb +2 -0
  34. data/lib/ruby_lsp/server.rb +54 -4
  35. data/lib/ruby_lsp/test_helper.rb +1 -1
  36. data/lib/ruby_lsp/type_inferrer.rb +86 -0
  37. metadata +29 -4
@@ -68,6 +68,12 @@ module RubyLsp
68
68
  text_document_signature_help(message)
69
69
  when "textDocument/definition"
70
70
  text_document_definition(message)
71
+ when "textDocument/prepareTypeHierarchy"
72
+ text_document_prepare_type_hierarchy(message)
73
+ when "typeHierarchy/supertypes"
74
+ type_hierarchy_supertypes(message)
75
+ when "typeHierarchy/subtypes"
76
+ type_hierarchy_subtypes(message)
71
77
  when "workspace/didChangeWatchedFiles"
72
78
  workspace_did_change_watched_files(message)
73
79
  when "workspace/symbol"
@@ -76,6 +82,16 @@ module RubyLsp
76
82
  text_document_show_syntax_tree(message)
77
83
  when "rubyLsp/workspace/dependencies"
78
84
  workspace_dependencies(message)
85
+ when "rubyLsp/workspace/addons"
86
+ send_message(
87
+ Result.new(
88
+ id: message[:id],
89
+ response:
90
+ Addon.addons.map do |addon|
91
+ { name: addon.name, errored: addon.error? }
92
+ end,
93
+ ),
94
+ )
79
95
  when "$/cancelRequest"
80
96
  @mutex.synchronize { @cancelled_requests << message[:params][:id] }
81
97
  end
@@ -104,7 +120,7 @@ module RubyLsp
104
120
  ),
105
121
  )
106
122
 
107
- $stderr.puts(errored_addons.map(&:errors_details).join("\n\n"))
123
+ $stderr.puts(errored_addons.map(&:errors_details).join("\n\n")) unless @test_mode
108
124
  end
109
125
  end
110
126
 
@@ -152,6 +168,7 @@ module RubyLsp
152
168
  inlay_hint_provider = Requests::InlayHints.provider if enabled_features["inlayHint"]
153
169
  completion_provider = Requests::Completion.provider if enabled_features["completion"]
154
170
  signature_help_provider = Requests::SignatureHelp.provider if enabled_features["signatureHelp"]
171
+ type_hierarchy_provider = Requests::PrepareTypeHierarchy.provider if enabled_features["typeHierarchy"]
155
172
 
156
173
  response = {
157
174
  capabilities: Interface::ServerCapabilities.new(
@@ -175,8 +192,12 @@ module RubyLsp
175
192
  completion_provider: completion_provider,
176
193
  code_lens_provider: code_lens_provider,
177
194
  definition_provider: enabled_features["definition"],
178
- workspace_symbol_provider: enabled_features["workspaceSymbol"] && !@global_state.typechecker,
195
+ workspace_symbol_provider: enabled_features["workspaceSymbol"] && !@global_state.has_type_checker,
179
196
  signature_help_provider: signature_help_provider,
197
+ type_hierarchy_provider: type_hierarchy_provider,
198
+ experimental: {
199
+ addon_detection: true,
200
+ },
180
201
  ),
181
202
  serverInfo: {
182
203
  name: "Ruby LSP",
@@ -449,7 +470,7 @@ module RubyLsp
449
470
 
450
471
  sig { params(document: Document).returns(T::Boolean) }
451
472
  def typechecker_enabled?(document)
452
- @global_state.typechecker && document.sorbet_sigil_is_true_or_higher
473
+ @global_state.has_type_checker && document.sorbet_sigil_is_true_or_higher
453
474
  end
454
475
 
455
476
  sig { params(message: T::Hash[Symbol, T.untyped]).void }
@@ -551,7 +572,7 @@ module RubyLsp
551
572
  response: Requests::Completion.new(
552
573
  document,
553
574
  @global_state,
554
- params[:position],
575
+ params,
555
576
  typechecker_enabled?(document),
556
577
  dispatcher,
557
578
  ).perform,
@@ -660,6 +681,33 @@ module RubyLsp
660
681
  send_message(Result.new(id: message[:id], response: response))
661
682
  end
662
683
 
684
+ sig { params(message: T::Hash[Symbol, T.untyped]).void }
685
+ def text_document_prepare_type_hierarchy(message)
686
+ params = message[:params]
687
+ response = Requests::PrepareTypeHierarchy.new(
688
+ @store.get(params.dig(:textDocument, :uri)),
689
+ @global_state.index,
690
+ params[:position],
691
+ ).perform
692
+ send_message(Result.new(id: message[:id], response: response))
693
+ end
694
+
695
+ sig { params(message: T::Hash[Symbol, T.untyped]).void }
696
+ def type_hierarchy_supertypes(message)
697
+ response = Requests::TypeHierarchySupertypes.new(
698
+ @global_state.index,
699
+ message.dig(:params, :item),
700
+ ).perform
701
+ send_message(Result.new(id: message[:id], response: response))
702
+ end
703
+
704
+ sig { params(message: T::Hash[Symbol, T.untyped]).void }
705
+ def type_hierarchy_subtypes(message)
706
+ # TODO: implement subtypes
707
+ # The current index representation doesn't allow us to find the children of an entry.
708
+ send_message(Result.new(id: message[:id], response: nil))
709
+ end
710
+
663
711
  sig { params(message: T::Hash[Symbol, T.untyped]).void }
664
712
  def workspace_dependencies(message)
665
713
  response = begin
@@ -696,6 +744,8 @@ module RubyLsp
696
744
 
697
745
  Thread.new do
698
746
  begin
747
+ RubyIndexer::RBSIndexer.new(@global_state.index).index_ruby_core
748
+
699
749
  @global_state.index.index_all do |percentage|
700
750
  progress("indexing-progress", percentage)
701
751
  true
@@ -20,7 +20,7 @@ module RubyLsp
20
20
  def with_server(source = nil, uri = Kernel.URI("file:///fake.rb"), stub_no_typechecker: false, load_addons: true,
21
21
  &block)
22
22
  server = RubyLsp::Server.new(test_mode: true)
23
- server.global_state.stubs(:typechecker).returns(false) if stub_no_typechecker
23
+ server.global_state.stubs(:has_type_checker).returns(false) if stub_no_typechecker
24
24
  server.global_state.apply_options({})
25
25
 
26
26
  if source
@@ -0,0 +1,86 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ # A minimalistic type checker to try to resolve types that can be inferred without requiring a type system or
6
+ # annotations
7
+ class TypeInferrer
8
+ extend T::Sig
9
+
10
+ sig { params(index: RubyIndexer::Index).void }
11
+ def initialize(index)
12
+ @index = index
13
+ end
14
+
15
+ sig { params(node_context: NodeContext).returns(T.nilable(String)) }
16
+ def infer_receiver_type(node_context)
17
+ node = node_context.node
18
+
19
+ case node
20
+ when Prism::CallNode
21
+ infer_receiver_for_call_node(node, node_context)
22
+ when Prism::InstanceVariableReadNode, Prism::InstanceVariableAndWriteNode, Prism::InstanceVariableWriteNode,
23
+ Prism::InstanceVariableOperatorWriteNode, Prism::InstanceVariableOrWriteNode, Prism::InstanceVariableTargetNode
24
+ nesting = node_context.nesting
25
+ # If we're at the top level, then the invocation is happening on `<main>`, which is a special singleton that
26
+ # inherits from Object
27
+ return "Object" if nesting.empty?
28
+
29
+ fully_qualified_name = node_context.fully_qualified_name
30
+ return fully_qualified_name if node_context.surrounding_method
31
+
32
+ "#{fully_qualified_name}::<Class:#{nesting.last}>"
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ sig { params(node: Prism::CallNode, node_context: NodeContext).returns(T.nilable(String)) }
39
+ def infer_receiver_for_call_node(node, node_context)
40
+ receiver = node.receiver
41
+
42
+ case receiver
43
+ when Prism::SelfNode, nil
44
+ nesting = node_context.nesting
45
+ # If we're at the top level, then the invocation is happening on `<main>`, which is a special singleton that
46
+ # inherits from Object
47
+ return "Object" if nesting.empty?
48
+ return node_context.fully_qualified_name if node_context.surrounding_method
49
+
50
+ # If we're not inside a method, then we're inside the body of a class or module, which is a singleton
51
+ # context
52
+ "#{nesting.join("::")}::<Class:#{nesting.last}>"
53
+ when Prism::ConstantPathNode, Prism::ConstantReadNode
54
+ # When the receiver is a constant reference, we have to try to resolve it to figure out the right
55
+ # receiver. But since the invocation is directly on the constant, that's the singleton context of that
56
+ # class/module
57
+ receiver_name = constant_name(receiver)
58
+ return unless receiver_name
59
+
60
+ resolved_receiver = @index.resolve(receiver_name, node_context.nesting)
61
+ name = resolved_receiver&.first&.name
62
+ return unless name
63
+
64
+ *parts, last = name.split("::")
65
+ return "#{last}::<Class:#{last}>" if parts.empty?
66
+
67
+ "#{parts.join("::")}::#{last}::<Class:#{last}>"
68
+ end
69
+ end
70
+
71
+ sig do
72
+ params(
73
+ node: T.any(
74
+ Prism::ConstantPathNode,
75
+ Prism::ConstantReadNode,
76
+ ),
77
+ ).returns(T.nilable(String))
78
+ end
79
+ def constant_name(node)
80
+ node.full_name
81
+ rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
82
+ Prism::ConstantPathNode::MissingNodesInConstantPathError
83
+ nil
84
+ end
85
+ end
86
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.2
4
+ version: 0.17.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-05 00:00:00.000000000 Z
11
+ date: 2024-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: language_server-protocol
@@ -33,7 +33,7 @@ dependencies:
33
33
  version: 0.29.0
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
- version: '0.30'
36
+ version: '0.31'
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
@@ -43,7 +43,27 @@ dependencies:
43
43
  version: 0.29.0
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.30'
46
+ version: '0.31'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rbs
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '3'
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: '4'
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '3'
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: '4'
47
67
  - !ruby/object:Gem::Dependency
48
68
  name: sorbet-runtime
49
69
  requirement: !ruby/object:Gem::Requirement
@@ -85,6 +105,7 @@ files:
85
105
  - lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb
86
106
  - lib/ruby_indexer/lib/ruby_indexer/location.rb
87
107
  - lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb
108
+ - lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb
88
109
  - lib/ruby_indexer/ruby_indexer.rb
89
110
  - lib/ruby_indexer/test/classes_and_modules_test.rb
90
111
  - lib/ruby_indexer/test/configuration_test.rb
@@ -93,6 +114,7 @@ files:
93
114
  - lib/ruby_indexer/test/instance_variables_test.rb
94
115
  - lib/ruby_indexer/test/method_test.rb
95
116
  - lib/ruby_indexer/test/prefix_tree_test.rb
117
+ - lib/ruby_indexer/test/rbs_indexer_test.rb
96
118
  - lib/ruby_indexer/test/test_case.rb
97
119
  - lib/ruby_lsp/addon.rb
98
120
  - lib/ruby_lsp/base_server.rb
@@ -130,6 +152,7 @@ files:
130
152
  - lib/ruby_lsp/requests/hover.rb
131
153
  - lib/ruby_lsp/requests/inlay_hints.rb
132
154
  - lib/ruby_lsp/requests/on_type_formatting.rb
155
+ - lib/ruby_lsp/requests/prepare_type_hierarchy.rb
133
156
  - lib/ruby_lsp/requests/request.rb
134
157
  - lib/ruby_lsp/requests/selection_ranges.rb
135
158
  - lib/ruby_lsp/requests/semantic_highlighting.rb
@@ -145,6 +168,7 @@ files:
145
168
  - lib/ruby_lsp/requests/support/sorbet.rb
146
169
  - lib/ruby_lsp/requests/support/source_uri.rb
147
170
  - lib/ruby_lsp/requests/support/syntax_tree_formatter.rb
171
+ - lib/ruby_lsp/requests/type_hierarchy_supertypes.rb
148
172
  - lib/ruby_lsp/requests/workspace_symbol.rb
149
173
  - lib/ruby_lsp/response_builders.rb
150
174
  - lib/ruby_lsp/response_builders/collection_response_builder.rb
@@ -158,6 +182,7 @@ files:
158
182
  - lib/ruby_lsp/setup_bundler.rb
159
183
  - lib/ruby_lsp/store.rb
160
184
  - lib/ruby_lsp/test_helper.rb
185
+ - lib/ruby_lsp/type_inferrer.rb
161
186
  - lib/ruby_lsp/utils.rb
162
187
  homepage: https://github.com/Shopify/ruby-lsp
163
188
  licenses: