ruby-lsp 0.17.2 → 0.17.4

Sign up to get free protection for your applications and to get access to all the features.
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: