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.
- checksums.yaml +4 -4
 - data/README.md +2 -0
 - data/VERSION +1 -1
 - data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +280 -74
 - data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +102 -102
 - data/lib/ruby_indexer/lib/ruby_indexer/index.rb +234 -56
 - data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +147 -0
 - data/lib/ruby_indexer/ruby_indexer.rb +1 -0
 - data/lib/ruby_indexer/test/classes_and_modules_test.rb +49 -2
 - data/lib/ruby_indexer/test/configuration_test.rb +1 -1
 - data/lib/ruby_indexer/test/constant_test.rb +1 -1
 - data/lib/ruby_indexer/test/index_test.rb +702 -71
 - data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
 - data/lib/ruby_indexer/test/method_test.rb +74 -24
 - data/lib/ruby_indexer/test/rbs_indexer_test.rb +67 -0
 - data/lib/ruby_indexer/test/test_case.rb +7 -0
 - data/lib/ruby_lsp/document.rb +37 -8
 - data/lib/ruby_lsp/global_state.rb +43 -18
 - data/lib/ruby_lsp/internal.rb +2 -0
 - data/lib/ruby_lsp/listeners/code_lens.rb +2 -2
 - data/lib/ruby_lsp/listeners/completion.rb +53 -14
 - data/lib/ruby_lsp/listeners/definition.rb +11 -7
 - data/lib/ruby_lsp/listeners/hover.rb +14 -7
 - data/lib/ruby_lsp/listeners/signature_help.rb +5 -2
 - data/lib/ruby_lsp/node_context.rb +6 -1
 - data/lib/ruby_lsp/requests/completion.rb +5 -4
 - data/lib/ruby_lsp/requests/completion_resolve.rb +8 -0
 - data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +88 -0
 - data/lib/ruby_lsp/requests/support/common.rb +19 -1
 - data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +12 -4
 - data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +91 -0
 - data/lib/ruby_lsp/requests/workspace_symbol.rb +1 -21
 - data/lib/ruby_lsp/requests.rb +2 -0
 - data/lib/ruby_lsp/server.rb +54 -4
 - data/lib/ruby_lsp/test_helper.rb +1 -1
 - data/lib/ruby_lsp/type_inferrer.rb +86 -0
 - metadata +29 -4
 
| 
         @@ -15,15 +15,26 @@ module RubyLsp 
     | 
|
| 
       15 
15 
     | 
    
         
             
                      typechecker_enabled: T::Boolean,
         
     | 
| 
       16 
16 
     | 
    
         
             
                      dispatcher: Prism::Dispatcher,
         
     | 
| 
       17 
17 
     | 
    
         
             
                      uri: URI::Generic,
         
     | 
| 
      
 18 
     | 
    
         
            +
                      trigger_character: T.nilable(String),
         
     | 
| 
       18 
19 
     | 
    
         
             
                    ).void
         
     | 
| 
       19 
20 
     | 
    
         
             
                  end
         
     | 
| 
       20 
     | 
    
         
            -
                  def initialize( 
     | 
| 
      
 21 
     | 
    
         
            +
                  def initialize( # rubocop:disable Metrics/ParameterLists
         
     | 
| 
      
 22 
     | 
    
         
            +
                    response_builder,
         
     | 
| 
      
 23 
     | 
    
         
            +
                    global_state,
         
     | 
| 
      
 24 
     | 
    
         
            +
                    node_context,
         
     | 
| 
      
 25 
     | 
    
         
            +
                    typechecker_enabled,
         
     | 
| 
      
 26 
     | 
    
         
            +
                    dispatcher,
         
     | 
| 
      
 27 
     | 
    
         
            +
                    uri,
         
     | 
| 
      
 28 
     | 
    
         
            +
                    trigger_character
         
     | 
| 
      
 29 
     | 
    
         
            +
                  )
         
     | 
| 
       21 
30 
     | 
    
         
             
                    @response_builder = response_builder
         
     | 
| 
       22 
31 
     | 
    
         
             
                    @global_state = global_state
         
     | 
| 
       23 
32 
     | 
    
         
             
                    @index = T.let(global_state.index, RubyIndexer::Index)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @type_inferrer = T.let(global_state.type_inferrer, TypeInferrer)
         
     | 
| 
       24 
34 
     | 
    
         
             
                    @node_context = node_context
         
     | 
| 
       25 
35 
     | 
    
         
             
                    @typechecker_enabled = typechecker_enabled
         
     | 
| 
       26 
36 
     | 
    
         
             
                    @uri = uri
         
     | 
| 
      
 37 
     | 
    
         
            +
                    @trigger_character = trigger_character
         
     | 
| 
       27 
38 
     | 
    
         | 
| 
       28 
39 
     | 
    
         
             
                    dispatcher.register(
         
     | 
| 
       29 
40 
     | 
    
         
             
                      self,
         
     | 
| 
         @@ -42,7 +53,7 @@ module RubyLsp 
     | 
|
| 
       42 
53 
     | 
    
         
             
                  # Handle completion on regular constant references (e.g. `Bar`)
         
     | 
| 
       43 
54 
     | 
    
         
             
                  sig { params(node: Prism::ConstantReadNode).void }
         
     | 
| 
       44 
55 
     | 
    
         
             
                  def on_constant_read_node_enter(node)
         
     | 
| 
       45 
     | 
    
         
            -
                    return if @global_state. 
     | 
| 
      
 56 
     | 
    
         
            +
                    return if @global_state.has_type_checker
         
     | 
| 
       46 
57 
     | 
    
         | 
| 
       47 
58 
     | 
    
         
             
                    name = constant_name(node)
         
     | 
| 
       48 
59 
     | 
    
         
             
                    return if name.nil?
         
     | 
| 
         @@ -63,7 +74,7 @@ module RubyLsp 
     | 
|
| 
       63 
74 
     | 
    
         
             
                  # Handle completion on namespaced constant references (e.g. `Foo::Bar`)
         
     | 
| 
       64 
75 
     | 
    
         
             
                  sig { params(node: Prism::ConstantPathNode).void }
         
     | 
| 
       65 
76 
     | 
    
         
             
                  def on_constant_path_node_enter(node)
         
     | 
| 
       66 
     | 
    
         
            -
                    return if @global_state. 
     | 
| 
      
 77 
     | 
    
         
            +
                    return if @global_state.has_type_checker
         
     | 
| 
       67 
78 
     | 
    
         | 
| 
       68 
79 
     | 
    
         
             
                    name = constant_name(node)
         
     | 
| 
       69 
80 
     | 
    
         
             
                    return if name.nil?
         
     | 
| 
         @@ -107,7 +118,7 @@ module RubyLsp 
     | 
|
| 
       107 
118 
     | 
    
         
             
                    when "require_relative"
         
     | 
| 
       108 
119 
     | 
    
         
             
                      complete_require_relative(node)
         
     | 
| 
       109 
120 
     | 
    
         
             
                    else
         
     | 
| 
       110 
     | 
    
         
            -
                       
     | 
| 
      
 121 
     | 
    
         
            +
                      complete_methods(node, name) unless @typechecker_enabled
         
     | 
| 
       111 
122 
     | 
    
         
             
                    end
         
     | 
| 
       112 
123 
     | 
    
         
             
                  end
         
     | 
| 
       113 
124 
     | 
    
         | 
| 
         @@ -158,7 +169,7 @@ module RubyLsp 
     | 
|
| 
       158 
169 
     | 
    
         
             
                      name.delete_suffix("::")
         
     | 
| 
       159 
170 
     | 
    
         
             
                    else
         
     | 
| 
       160 
171 
     | 
    
         
             
                      *namespace, incomplete_name = name.split("::")
         
     | 
| 
       161 
     | 
    
         
            -
                       
     | 
| 
      
 172 
     | 
    
         
            +
                      namespace.join("::")
         
     | 
| 
       162 
173 
     | 
    
         
             
                    end
         
     | 
| 
       163 
174 
     | 
    
         | 
| 
       164 
175 
     | 
    
         
             
                    nesting = @node_context.nesting
         
     | 
| 
         @@ -192,7 +203,10 @@ module RubyLsp 
     | 
|
| 
       192 
203 
     | 
    
         | 
| 
       193 
204 
     | 
    
         
             
                  sig { params(name: String, location: Prism::Location).void }
         
     | 
| 
       194 
205 
     | 
    
         
             
                  def handle_instance_variable_completion(name, location)
         
     | 
| 
       195 
     | 
    
         
            -
                    @ 
     | 
| 
      
 206 
     | 
    
         
            +
                    type = @type_inferrer.infer_receiver_type(@node_context)
         
     | 
| 
      
 207 
     | 
    
         
            +
                    return unless type
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                    @index.instance_variable_completion_candidates(name, type).each do |entry|
         
     | 
| 
       196 
210 
     | 
    
         
             
                      variable_name = entry.name
         
     | 
| 
       197 
211 
     | 
    
         | 
| 
       198 
212 
     | 
    
         
             
                      @response_builder << Interface::CompletionItem.new(
         
     | 
| 
         @@ -257,20 +271,45 @@ module RubyLsp 
     | 
|
| 
       257 
271 
     | 
    
         
             
                  end
         
     | 
| 
       258 
272 
     | 
    
         | 
| 
       259 
273 
     | 
    
         
             
                  sig { params(node: Prism::CallNode, name: String).void }
         
     | 
| 
       260 
     | 
    
         
            -
                  def  
     | 
| 
       261 
     | 
    
         
            -
                     
     | 
| 
       262 
     | 
    
         
            -
                    return unless  
     | 
| 
      
 274 
     | 
    
         
            +
                  def complete_methods(node, name)
         
     | 
| 
      
 275 
     | 
    
         
            +
                    type = @type_inferrer.infer_receiver_type(@node_context)
         
     | 
| 
      
 276 
     | 
    
         
            +
                    return unless type
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
                    # When the trigger character is a dot, Prism matches the name of the call node to whatever is next in the source
         
     | 
| 
      
 279 
     | 
    
         
            +
                    # code, leading to us searching for the wrong name. What we want to do instead is show every available method
         
     | 
| 
      
 280 
     | 
    
         
            +
                    # when dot is pressed
         
     | 
| 
      
 281 
     | 
    
         
            +
                    method_name = @trigger_character == "." ? nil : name
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
                    range = if method_name
         
     | 
| 
      
 284 
     | 
    
         
            +
                      range_from_location(T.must(node.message_loc))
         
     | 
| 
      
 285 
     | 
    
         
            +
                    else
         
     | 
| 
      
 286 
     | 
    
         
            +
                      loc = T.must(node.call_operator_loc)
         
     | 
| 
      
 287 
     | 
    
         
            +
                      Interface::Range.new(
         
     | 
| 
      
 288 
     | 
    
         
            +
                        start: Interface::Position.new(line: loc.start_line - 1, character: loc.start_column + 1),
         
     | 
| 
      
 289 
     | 
    
         
            +
                        end: Interface::Position.new(line: loc.start_line - 1, character: loc.start_column + 1),
         
     | 
| 
      
 290 
     | 
    
         
            +
                      )
         
     | 
| 
      
 291 
     | 
    
         
            +
                    end
         
     | 
| 
       263 
292 
     | 
    
         | 
| 
       264 
     | 
    
         
            -
                     
     | 
| 
      
 293 
     | 
    
         
            +
                    @index.method_completion_candidates(method_name, type).each do |entry|
         
     | 
| 
      
 294 
     | 
    
         
            +
                      entry_name = entry.name
         
     | 
| 
       265 
295 
     | 
    
         | 
| 
       266 
     | 
    
         
            -
             
     | 
| 
       267 
     | 
    
         
            -
             
     | 
| 
      
 296 
     | 
    
         
            +
                      @response_builder << Interface::CompletionItem.new(
         
     | 
| 
      
 297 
     | 
    
         
            +
                        label: entry_name,
         
     | 
| 
      
 298 
     | 
    
         
            +
                        filter_text: entry_name,
         
     | 
| 
      
 299 
     | 
    
         
            +
                        text_edit: Interface::TextEdit.new(range: range, new_text: entry_name),
         
     | 
| 
      
 300 
     | 
    
         
            +
                        kind: Constant::CompletionItemKind::METHOD,
         
     | 
| 
      
 301 
     | 
    
         
            +
                        data: {
         
     | 
| 
      
 302 
     | 
    
         
            +
                          owner_name: entry.owner&.name,
         
     | 
| 
      
 303 
     | 
    
         
            +
                        },
         
     | 
| 
      
 304 
     | 
    
         
            +
                      )
         
     | 
| 
       268 
305 
     | 
    
         
             
                    end
         
     | 
| 
      
 306 
     | 
    
         
            +
                  rescue RubyIndexer::Index::NonExistingNamespaceError
         
     | 
| 
      
 307 
     | 
    
         
            +
                    # We have not indexed this namespace, so we can't provide any completions
         
     | 
| 
       269 
308 
     | 
    
         
             
                  end
         
     | 
| 
       270 
309 
     | 
    
         | 
| 
       271 
310 
     | 
    
         
             
                  sig do
         
     | 
| 
       272 
311 
     | 
    
         
             
                    params(
         
     | 
| 
       273 
     | 
    
         
            -
                      entry: RubyIndexer::Entry::Member,
         
     | 
| 
      
 312 
     | 
    
         
            +
                      entry: T.any(RubyIndexer::Entry::Member, RubyIndexer::Entry::MethodAlias),
         
     | 
| 
       274 
313 
     | 
    
         
             
                      node: Prism::CallNode,
         
     | 
| 
       275 
314 
     | 
    
         
             
                    ).returns(Interface::CompletionItem)
         
     | 
| 
       276 
315 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -283,7 +322,7 @@ module RubyLsp 
     | 
|
| 
       283 
322 
     | 
    
         
             
                      text_edit: Interface::TextEdit.new(range: range_from_location(T.must(node.message_loc)), new_text: name),
         
     | 
| 
       284 
323 
     | 
    
         
             
                      kind: Constant::CompletionItemKind::METHOD,
         
     | 
| 
       285 
324 
     | 
    
         
             
                      label_details: Interface::CompletionItemLabelDetails.new(
         
     | 
| 
       286 
     | 
    
         
            -
                        detail:  
     | 
| 
      
 325 
     | 
    
         
            +
                        detail: entry.decorated_parameters,
         
     | 
| 
       287 
326 
     | 
    
         
             
                        description: entry.file_name,
         
     | 
| 
       288 
327 
     | 
    
         
             
                      ),
         
     | 
| 
       289 
328 
     | 
    
         
             
                      documentation: Interface::MarkupContent.new(
         
     | 
| 
         @@ -23,6 +23,7 @@ module RubyLsp 
     | 
|
| 
       23 
23 
     | 
    
         
             
                    @response_builder = response_builder
         
     | 
| 
       24 
24 
     | 
    
         
             
                    @global_state = global_state
         
     | 
| 
       25 
25 
     | 
    
         
             
                    @index = T.let(global_state.index, RubyIndexer::Index)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @type_inferrer = T.let(global_state.type_inferrer, TypeInferrer)
         
     | 
| 
       26 
27 
     | 
    
         
             
                    @uri = uri
         
     | 
| 
       27 
28 
     | 
    
         
             
                    @node_context = node_context
         
     | 
| 
       28 
29 
     | 
    
         
             
                    @typechecker_enabled = typechecker_enabled
         
     | 
| 
         @@ -48,7 +49,7 @@ module RubyLsp 
     | 
|
| 
       48 
49 
     | 
    
         
             
                    message = node.message
         
     | 
| 
       49 
50 
     | 
    
         
             
                    return unless message
         
     | 
| 
       50 
51 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
                    handle_method_definition(message,  
     | 
| 
      
 52 
     | 
    
         
            +
                    handle_method_definition(message, @type_inferrer.infer_receiver_type(@node_context))
         
     | 
| 
       52 
53 
     | 
    
         
             
                  end
         
     | 
| 
       53 
54 
     | 
    
         | 
| 
       54 
55 
     | 
    
         
             
                  sig { params(node: Prism::StringNode).void }
         
     | 
| 
         @@ -70,7 +71,7 @@ module RubyLsp 
     | 
|
| 
       70 
71 
     | 
    
         
             
                    value = expression.value
         
     | 
| 
       71 
72 
     | 
    
         
             
                    return unless value
         
     | 
| 
       72 
73 
     | 
    
         | 
| 
       73 
     | 
    
         
            -
                    handle_method_definition(value,  
     | 
| 
      
 74 
     | 
    
         
            +
                    handle_method_definition(value, nil)
         
     | 
| 
       74 
75 
     | 
    
         
             
                  end
         
     | 
| 
       75 
76 
     | 
    
         | 
| 
       76 
77 
     | 
    
         
             
                  sig { params(node: Prism::ConstantPathNode).void }
         
     | 
| 
         @@ -123,7 +124,10 @@ module RubyLsp 
     | 
|
| 
       123 
124 
     | 
    
         | 
| 
       124 
125 
     | 
    
         
             
                  sig { params(name: String).void }
         
     | 
| 
       125 
126 
     | 
    
         
             
                  def handle_instance_variable_definition(name)
         
     | 
| 
       126 
     | 
    
         
            -
                     
     | 
| 
      
 127 
     | 
    
         
            +
                    type = @type_inferrer.infer_receiver_type(@node_context)
         
     | 
| 
      
 128 
     | 
    
         
            +
                    return unless type
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    entries = @index.resolve_instance_variable(name, type)
         
     | 
| 
       127 
131 
     | 
    
         
             
                    return unless entries
         
     | 
| 
       128 
132 
     | 
    
         | 
| 
       129 
133 
     | 
    
         
             
                    entries.each do |entry|
         
     | 
| 
         @@ -141,10 +145,10 @@ module RubyLsp 
     | 
|
| 
       141 
145 
     | 
    
         
             
                    # If by any chance we haven't indexed the owner, then there's no way to find the right declaration
         
     | 
| 
       142 
146 
     | 
    
         
             
                  end
         
     | 
| 
       143 
147 
     | 
    
         | 
| 
       144 
     | 
    
         
            -
                  sig { params(message: String,  
     | 
| 
       145 
     | 
    
         
            -
                  def handle_method_definition(message,  
     | 
| 
       146 
     | 
    
         
            -
                    methods = if  
     | 
| 
       147 
     | 
    
         
            -
                      @index.resolve_method(message,  
     | 
| 
      
 148 
     | 
    
         
            +
                  sig { params(message: String, receiver_type: T.nilable(String)).void }
         
     | 
| 
      
 149 
     | 
    
         
            +
                  def handle_method_definition(message, receiver_type)
         
     | 
| 
      
 150 
     | 
    
         
            +
                    methods = if receiver_type
         
     | 
| 
      
 151 
     | 
    
         
            +
                      @index.resolve_method(message, receiver_type)
         
     | 
| 
       148 
152 
     | 
    
         
             
                    else
         
     | 
| 
       149 
153 
     | 
    
         
             
                      # If the method doesn't have a receiver, then we provide a few candidates to jump to
         
     | 
| 
       150 
154 
     | 
    
         
             
                      # But we don't want to provide too many candidates, as it can be overwhelming
         
     | 
| 
         @@ -47,6 +47,7 @@ module RubyLsp 
     | 
|
| 
       47 
47 
     | 
    
         
             
                    @response_builder = response_builder
         
     | 
| 
       48 
48 
     | 
    
         
             
                    @global_state = global_state
         
     | 
| 
       49 
49 
     | 
    
         
             
                    @index = T.let(global_state.index, RubyIndexer::Index)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    @type_inferrer = T.let(global_state.type_inferrer, TypeInferrer)
         
     | 
| 
       50 
51 
     | 
    
         
             
                    @path = T.let(uri.to_standardized_path, T.nilable(String))
         
     | 
| 
       51 
52 
     | 
    
         
             
                    @node_context = node_context
         
     | 
| 
       52 
53 
     | 
    
         
             
                    @typechecker_enabled = typechecker_enabled
         
     | 
| 
         @@ -78,14 +79,14 @@ module RubyLsp 
     | 
|
| 
       78 
79 
     | 
    
         | 
| 
       79 
80 
     | 
    
         
             
                  sig { params(node: Prism::ConstantWriteNode).void }
         
     | 
| 
       80 
81 
     | 
    
         
             
                  def on_constant_write_node_enter(node)
         
     | 
| 
       81 
     | 
    
         
            -
                    return if @global_state. 
     | 
| 
      
 82 
     | 
    
         
            +
                    return if @global_state.has_type_checker
         
     | 
| 
       82 
83 
     | 
    
         | 
| 
       83 
84 
     | 
    
         
             
                    generate_hover(node.name.to_s, node.name_loc)
         
     | 
| 
       84 
85 
     | 
    
         
             
                  end
         
     | 
| 
       85 
86 
     | 
    
         | 
| 
       86 
87 
     | 
    
         
             
                  sig { params(node: Prism::ConstantPathNode).void }
         
     | 
| 
       87 
88 
     | 
    
         
             
                  def on_constant_path_node_enter(node)
         
     | 
| 
       88 
     | 
    
         
            -
                    return if @global_state. 
     | 
| 
      
 89 
     | 
    
         
            +
                    return if @global_state.has_type_checker
         
     | 
| 
       89 
90 
     | 
    
         | 
| 
       90 
91 
     | 
    
         
             
                    name = constant_name(node)
         
     | 
| 
       91 
92 
     | 
    
         
             
                    return if name.nil?
         
     | 
| 
         @@ -95,8 +96,6 @@ module RubyLsp 
     | 
|
| 
       95 
96 
     | 
    
         | 
| 
       96 
97 
     | 
    
         
             
                  sig { params(node: Prism::CallNode).void }
         
     | 
| 
       97 
98 
     | 
    
         
             
                  def on_call_node_enter(node)
         
     | 
| 
       98 
     | 
    
         
            -
                    return unless self_receiver?(node)
         
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
99 
     | 
    
         
             
                    if @path && File.basename(@path) == GEMFILE_NAME && node.name == :gem
         
     | 
| 
       101 
100 
     | 
    
         
             
                      generate_gem_hover(node)
         
     | 
| 
       102 
101 
     | 
    
         
             
                      return
         
     | 
| 
         @@ -107,10 +106,15 @@ module RubyLsp 
     | 
|
| 
       107 
106 
     | 
    
         
             
                    message = node.message
         
     | 
| 
       108 
107 
     | 
    
         
             
                    return unless message
         
     | 
| 
       109 
108 
     | 
    
         | 
| 
       110 
     | 
    
         
            -
                     
     | 
| 
      
 109 
     | 
    
         
            +
                    type = @type_inferrer.infer_receiver_type(@node_context)
         
     | 
| 
      
 110 
     | 
    
         
            +
                    return unless type
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                    methods = @index.resolve_method(message, type)
         
     | 
| 
       111 
113 
     | 
    
         
             
                    return unless methods
         
     | 
| 
       112 
114 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
                     
     | 
| 
      
 115 
     | 
    
         
            +
                    title = "#{message}#{T.must(methods.first).decorated_parameters}"
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                    categorized_markdown_from_index_entries(title, methods).each do |category, content|
         
     | 
| 
       114 
118 
     | 
    
         
             
                      @response_builder.push(content, category: category)
         
     | 
| 
       115 
119 
     | 
    
         
             
                    end
         
     | 
| 
       116 
120 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -149,7 +153,10 @@ module RubyLsp 
     | 
|
| 
       149 
153 
     | 
    
         | 
| 
       150 
154 
     | 
    
         
             
                  sig { params(name: String).void }
         
     | 
| 
       151 
155 
     | 
    
         
             
                  def handle_instance_variable_hover(name)
         
     | 
| 
       152 
     | 
    
         
            -
                     
     | 
| 
      
 156 
     | 
    
         
            +
                    type = @type_inferrer.infer_receiver_type(@node_context)
         
     | 
| 
      
 157 
     | 
    
         
            +
                    return unless type
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                    entries = @index.resolve_instance_variable(name, type)
         
     | 
| 
       153 
160 
     | 
    
         
             
                    return unless entries
         
     | 
| 
       154 
161 
     | 
    
         | 
| 
       155 
162 
     | 
    
         
             
                    categorized_markdown_from_index_entries(name, entries).each do |category, content|
         
     | 
| 
         @@ -21,6 +21,7 @@ module RubyLsp 
     | 
|
| 
       21 
21 
     | 
    
         
             
                    @response_builder = response_builder
         
     | 
| 
       22 
22 
     | 
    
         
             
                    @global_state = global_state
         
     | 
| 
       23 
23 
     | 
    
         
             
                    @index = T.let(global_state.index, RubyIndexer::Index)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @type_inferrer = T.let(global_state.type_inferrer, TypeInferrer)
         
     | 
| 
       24 
25 
     | 
    
         
             
                    @node_context = node_context
         
     | 
| 
       25 
26 
     | 
    
         
             
                    dispatcher.register(self, :on_call_node_enter)
         
     | 
| 
       26 
27 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -28,12 +29,14 @@ module RubyLsp 
     | 
|
| 
       28 
29 
     | 
    
         
             
                  sig { params(node: Prism::CallNode).void }
         
     | 
| 
       29 
30 
     | 
    
         
             
                  def on_call_node_enter(node)
         
     | 
| 
       30 
31 
     | 
    
         
             
                    return if @typechecker_enabled
         
     | 
| 
       31 
     | 
    
         
            -
                    return unless self_receiver?(node)
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
                    message = node.message
         
     | 
| 
       34 
34 
     | 
    
         
             
                    return unless message
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
                     
     | 
| 
      
 36 
     | 
    
         
            +
                    type = @type_inferrer.infer_receiver_type(@node_context)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    return unless type
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    methods = @index.resolve_method(message, type)
         
     | 
| 
       37 
40 
     | 
    
         
             
                    return unless methods
         
     | 
| 
       38 
41 
     | 
    
         | 
| 
       39 
42 
     | 
    
         
             
                    target_method = methods.first
         
     | 
| 
         @@ -16,19 +16,24 @@ module RubyLsp 
     | 
|
| 
       16 
16 
     | 
    
         
             
                sig { returns(T.nilable(Prism::CallNode)) }
         
     | 
| 
       17 
17 
     | 
    
         
             
                attr_reader :call_node
         
     | 
| 
       18 
18 
     | 
    
         | 
| 
      
 19 
     | 
    
         
            +
                sig { returns(T.nilable(String)) }
         
     | 
| 
      
 20 
     | 
    
         
            +
                attr_reader :surrounding_method
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
       19 
22 
     | 
    
         
             
                sig do
         
     | 
| 
       20 
23 
     | 
    
         
             
                  params(
         
     | 
| 
       21 
24 
     | 
    
         
             
                    node: T.nilable(Prism::Node),
         
     | 
| 
       22 
25 
     | 
    
         
             
                    parent: T.nilable(Prism::Node),
         
     | 
| 
       23 
26 
     | 
    
         
             
                    nesting: T::Array[String],
         
     | 
| 
       24 
27 
     | 
    
         
             
                    call_node: T.nilable(Prism::CallNode),
         
     | 
| 
      
 28 
     | 
    
         
            +
                    surrounding_method: T.nilable(String),
         
     | 
| 
       25 
29 
     | 
    
         
             
                  ).void
         
     | 
| 
       26 
30 
     | 
    
         
             
                end
         
     | 
| 
       27 
     | 
    
         
            -
                def initialize(node, parent, nesting, call_node)
         
     | 
| 
      
 31 
     | 
    
         
            +
                def initialize(node, parent, nesting, call_node, surrounding_method)
         
     | 
| 
       28 
32 
     | 
    
         
             
                  @node = node
         
     | 
| 
       29 
33 
     | 
    
         
             
                  @parent = parent
         
     | 
| 
       30 
34 
     | 
    
         
             
                  @nesting = nesting
         
     | 
| 
       31 
35 
     | 
    
         
             
                  @call_node = call_node
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @surrounding_method = surrounding_method
         
     | 
| 
       32 
37 
     | 
    
         
             
                end
         
     | 
| 
       33 
38 
     | 
    
         | 
| 
       34 
39 
     | 
    
         
             
                sig { returns(String) }
         
     | 
| 
         @@ -36,7 +36,7 @@ module RubyLsp 
     | 
|
| 
       36 
36 
     | 
    
         
             
                    def provider
         
     | 
| 
       37 
37 
     | 
    
         
             
                      Interface::CompletionOptions.new(
         
     | 
| 
       38 
38 
     | 
    
         
             
                        resolve_provider: true,
         
     | 
| 
       39 
     | 
    
         
            -
                        trigger_characters: ["/", "\"", "'", ":", "@"],
         
     | 
| 
      
 39 
     | 
    
         
            +
                        trigger_characters: ["/", "\"", "'", ":", "@", "."],
         
     | 
| 
       40 
40 
     | 
    
         
             
                        completion_item: {
         
     | 
| 
       41 
41 
     | 
    
         
             
                          labelDetailsSupport: true,
         
     | 
| 
       42 
42 
     | 
    
         
             
                        },
         
     | 
| 
         @@ -48,18 +48,18 @@ module RubyLsp 
     | 
|
| 
       48 
48 
     | 
    
         
             
                    params(
         
     | 
| 
       49 
49 
     | 
    
         
             
                      document: Document,
         
     | 
| 
       50 
50 
     | 
    
         
             
                      global_state: GlobalState,
         
     | 
| 
       51 
     | 
    
         
            -
                       
     | 
| 
      
 51 
     | 
    
         
            +
                      params: T::Hash[Symbol, T.untyped],
         
     | 
| 
       52 
52 
     | 
    
         
             
                      typechecker_enabled: T::Boolean,
         
     | 
| 
       53 
53 
     | 
    
         
             
                      dispatcher: Prism::Dispatcher,
         
     | 
| 
       54 
54 
     | 
    
         
             
                    ).void
         
     | 
| 
       55 
55 
     | 
    
         
             
                  end
         
     | 
| 
       56 
     | 
    
         
            -
                  def initialize(document, global_state,  
     | 
| 
      
 56 
     | 
    
         
            +
                  def initialize(document, global_state, params, typechecker_enabled, dispatcher)
         
     | 
| 
       57 
57 
     | 
    
         
             
                    super()
         
     | 
| 
       58 
58 
     | 
    
         
             
                    @target = T.let(nil, T.nilable(Prism::Node))
         
     | 
| 
       59 
59 
     | 
    
         
             
                    @dispatcher = dispatcher
         
     | 
| 
       60 
60 
     | 
    
         
             
                    # Completion always receives the position immediately after the character that was just typed. Here we adjust it
         
     | 
| 
       61 
61 
     | 
    
         
             
                    # back by 1, so that we find the right node
         
     | 
| 
       62 
     | 
    
         
            -
                    char_position = document.create_scanner.find_char_position(position) - 1
         
     | 
| 
      
 62 
     | 
    
         
            +
                    char_position = document.create_scanner.find_char_position(params[:position]) - 1
         
     | 
| 
       63 
63 
     | 
    
         
             
                    node_context = document.locate(
         
     | 
| 
       64 
64 
     | 
    
         
             
                      document.tree,
         
     | 
| 
       65 
65 
     | 
    
         
             
                      char_position,
         
     | 
| 
         @@ -87,6 +87,7 @@ module RubyLsp 
     | 
|
| 
       87 
87 
     | 
    
         
             
                      typechecker_enabled,
         
     | 
| 
       88 
88 
     | 
    
         
             
                      dispatcher,
         
     | 
| 
       89 
89 
     | 
    
         
             
                      document.uri,
         
     | 
| 
      
 90 
     | 
    
         
            +
                      params.dig(:context, :triggerCharacter),
         
     | 
| 
       90 
91 
     | 
    
         
             
                    )
         
     | 
| 
       91 
92 
     | 
    
         | 
| 
       92 
93 
     | 
    
         
             
                    Addon.addons.each do |addon|
         
     | 
| 
         @@ -56,8 +56,16 @@ module RubyLsp 
     | 
|
| 
       56 
56 
     | 
    
         
             
                      end
         
     | 
| 
       57 
57 
     | 
    
         
             
                    end
         
     | 
| 
       58 
58 
     | 
    
         | 
| 
      
 59 
     | 
    
         
            +
                    first_entry = T.must(entries.first)
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    if first_entry.is_a?(RubyIndexer::Entry::Member)
         
     | 
| 
      
 62 
     | 
    
         
            +
                      detail = first_entry.decorated_parameters
         
     | 
| 
      
 63 
     | 
    
         
            +
                      label = "#{label}#{first_entry.decorated_parameters}"
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
       59 
66 
     | 
    
         
             
                    @item[:labelDetails] = Interface::CompletionItemLabelDetails.new(
         
     | 
| 
       60 
67 
     | 
    
         
             
                      description: entries.take(MAX_DOCUMENTATION_ENTRIES).map(&:file_name).join(","),
         
     | 
| 
      
 68 
     | 
    
         
            +
                      detail: detail,
         
     | 
| 
       61 
69 
     | 
    
         
             
                    )
         
     | 
| 
       62 
70 
     | 
    
         | 
| 
       63 
71 
     | 
    
         
             
                    @item[:documentation] = Interface::MarkupContent.new(
         
     | 
| 
         @@ -0,0 +1,88 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # typed: strict
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module RubyLsp
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Requests
         
     | 
| 
      
 6 
     | 
    
         
            +
                # 
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                # The [prepare type hierarchy
         
     | 
| 
      
 9 
     | 
    
         
            +
                # request](https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareTypeHierarchy)
         
     | 
| 
      
 10 
     | 
    
         
            +
                # displays the list of ancestors (supertypes) and descendants (subtypes) for the selected type.
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                # Currently only supports supertypes due to a limitation of the index.
         
     | 
| 
      
 13 
     | 
    
         
            +
                #
         
     | 
| 
      
 14 
     | 
    
         
            +
                # # Example
         
     | 
| 
      
 15 
     | 
    
         
            +
                #
         
     | 
| 
      
 16 
     | 
    
         
            +
                # ```ruby
         
     | 
| 
      
 17 
     | 
    
         
            +
                # class Foo; end
         
     | 
| 
      
 18 
     | 
    
         
            +
                # class Bar < Foo; end
         
     | 
| 
      
 19 
     | 
    
         
            +
                #
         
     | 
| 
      
 20 
     | 
    
         
            +
                # puts Bar # <-- right click on `Bar` and select "Show Type Hierarchy"
         
     | 
| 
      
 21 
     | 
    
         
            +
                # ```
         
     | 
| 
      
 22 
     | 
    
         
            +
                class PrepareTypeHierarchy < Request
         
     | 
| 
      
 23 
     | 
    
         
            +
                  extend T::Sig
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  include Support::Common
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 28 
     | 
    
         
            +
                    extend T::Sig
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    sig { returns(Interface::TypeHierarchyOptions) }
         
     | 
| 
      
 31 
     | 
    
         
            +
                    def provider
         
     | 
| 
      
 32 
     | 
    
         
            +
                      Interface::TypeHierarchyOptions.new
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  sig do
         
     | 
| 
      
 37 
     | 
    
         
            +
                    params(
         
     | 
| 
      
 38 
     | 
    
         
            +
                      document: Document,
         
     | 
| 
      
 39 
     | 
    
         
            +
                      index: RubyIndexer::Index,
         
     | 
| 
      
 40 
     | 
    
         
            +
                      position: T::Hash[Symbol, T.untyped],
         
     | 
| 
      
 41 
     | 
    
         
            +
                    ).void
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  def initialize(document, index, position)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    super()
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    @document = document
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @index = index
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @position = position
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  sig { override.returns(T.nilable(T::Array[Interface::TypeHierarchyItem])) }
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def perform
         
     | 
| 
      
 53 
     | 
    
         
            +
                    context = @document.locate_node(
         
     | 
| 
      
 54 
     | 
    
         
            +
                      @position,
         
     | 
| 
      
 55 
     | 
    
         
            +
                      node_types: [
         
     | 
| 
      
 56 
     | 
    
         
            +
                        Prism::ConstantReadNode,
         
     | 
| 
      
 57 
     | 
    
         
            +
                        Prism::ConstantWriteNode,
         
     | 
| 
      
 58 
     | 
    
         
            +
                        Prism::ConstantPathNode,
         
     | 
| 
      
 59 
     | 
    
         
            +
                      ],
         
     | 
| 
      
 60 
     | 
    
         
            +
                    )
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    node = context.node
         
     | 
| 
      
 63 
     | 
    
         
            +
                    parent = context.parent
         
     | 
| 
      
 64 
     | 
    
         
            +
                    return unless node && parent
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    target = determine_target(node, parent, @position)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    entries = @index.resolve(target.slice, context.nesting)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    return unless entries
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                    # While the spec allows for multiple entries, VSCode seems to only support one
         
     | 
| 
      
 71 
     | 
    
         
            +
                    # We'll just return the first one for now
         
     | 
| 
      
 72 
     | 
    
         
            +
                    first_entry = T.must(entries.first)
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    range = range_from_location(first_entry.location)
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    [
         
     | 
| 
      
 77 
     | 
    
         
            +
                      Interface::TypeHierarchyItem.new(
         
     | 
| 
      
 78 
     | 
    
         
            +
                        name: first_entry.name,
         
     | 
| 
      
 79 
     | 
    
         
            +
                        kind: kind_for_entry(first_entry),
         
     | 
| 
      
 80 
     | 
    
         
            +
                        uri: URI::Generic.from_path(path: first_entry.file_path).to_s,
         
     | 
| 
      
 81 
     | 
    
         
            +
                        range: range,
         
     | 
| 
      
 82 
     | 
    
         
            +
                        selection_range: range,
         
     | 
| 
      
 83 
     | 
    
         
            +
                      ),
         
     | 
| 
      
 84 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -26,7 +26,7 @@ module RubyLsp 
     | 
|
| 
       26 
26 
     | 
    
         
             
                      )
         
     | 
| 
       27 
27 
     | 
    
         
             
                    end
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                    sig { params(location: Prism::Location).returns(Interface::Range) }
         
     | 
| 
      
 29 
     | 
    
         
            +
                    sig { params(location: T.any(Prism::Location, RubyIndexer::Location)).returns(Interface::Range) }
         
     | 
| 
       30 
30 
     | 
    
         
             
                    def range_from_location(location)
         
     | 
| 
       31 
31 
     | 
    
         
             
                      Interface::Range.new(
         
     | 
| 
       32 
32 
     | 
    
         
             
                        start: Interface::Position.new(
         
     | 
| 
         @@ -186,6 +186,24 @@ module RubyLsp 
     | 
|
| 
       186 
186 
     | 
    
         
             
                        current = current.parent
         
     | 
| 
       187 
187 
     | 
    
         
             
                      end
         
     | 
| 
       188 
188 
     | 
    
         
             
                    end
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                    sig { params(entry: RubyIndexer::Entry).returns(T.nilable(Integer)) }
         
     | 
| 
      
 191 
     | 
    
         
            +
                    def kind_for_entry(entry)
         
     | 
| 
      
 192 
     | 
    
         
            +
                      case entry
         
     | 
| 
      
 193 
     | 
    
         
            +
                      when RubyIndexer::Entry::Class
         
     | 
| 
      
 194 
     | 
    
         
            +
                        Constant::SymbolKind::CLASS
         
     | 
| 
      
 195 
     | 
    
         
            +
                      when RubyIndexer::Entry::Module
         
     | 
| 
      
 196 
     | 
    
         
            +
                        Constant::SymbolKind::NAMESPACE
         
     | 
| 
      
 197 
     | 
    
         
            +
                      when RubyIndexer::Entry::Constant
         
     | 
| 
      
 198 
     | 
    
         
            +
                        Constant::SymbolKind::CONSTANT
         
     | 
| 
      
 199 
     | 
    
         
            +
                      when RubyIndexer::Entry::Method
         
     | 
| 
      
 200 
     | 
    
         
            +
                        entry.name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
         
     | 
| 
      
 201 
     | 
    
         
            +
                      when RubyIndexer::Entry::Accessor
         
     | 
| 
      
 202 
     | 
    
         
            +
                        Constant::SymbolKind::PROPERTY
         
     | 
| 
      
 203 
     | 
    
         
            +
                      when RubyIndexer::Entry::InstanceVariable
         
     | 
| 
      
 204 
     | 
    
         
            +
                        Constant::SymbolKind::FIELD
         
     | 
| 
      
 205 
     | 
    
         
            +
                      end
         
     | 
| 
      
 206 
     | 
    
         
            +
                    end
         
     | 
| 
       189 
207 
     | 
    
         
             
                  end
         
     | 
| 
       190 
208 
     | 
    
         
             
                end
         
     | 
| 
       191 
209 
     | 
    
         
             
              end
         
     | 
| 
         @@ -42,7 +42,7 @@ module RubyLsp 
     | 
|
| 
       42 
42 
     | 
    
         
             
                    def to_lsp_code_actions
         
     | 
| 
       43 
43 
     | 
    
         
             
                      code_actions = []
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
       45 
     | 
    
         
            -
                      code_actions << autocorrect_action if  
     | 
| 
      
 45 
     | 
    
         
            +
                      code_actions << autocorrect_action if correctable?
         
     | 
| 
       46 
46 
     | 
    
         
             
                      code_actions << disable_line_action
         
     | 
| 
       47 
47 
     | 
    
         | 
| 
       48 
48 
     | 
    
         
             
                      code_actions
         
     | 
| 
         @@ -70,7 +70,7 @@ module RubyLsp 
     | 
|
| 
       70 
70 
     | 
    
         
             
                          ),
         
     | 
| 
       71 
71 
     | 
    
         
             
                        ),
         
     | 
| 
       72 
72 
     | 
    
         
             
                        data: {
         
     | 
| 
       73 
     | 
    
         
            -
                          correctable:  
     | 
| 
      
 73 
     | 
    
         
            +
                          correctable: correctable?,
         
     | 
| 
       74 
74 
     | 
    
         
             
                          code_actions: to_lsp_code_actions,
         
     | 
| 
       75 
75 
     | 
    
         
             
                        },
         
     | 
| 
       76 
76 
     | 
    
         
             
                      )
         
     | 
| 
         @@ -81,7 +81,7 @@ module RubyLsp 
     | 
|
| 
       81 
81 
     | 
    
         
             
                    sig { returns(String) }
         
     | 
| 
       82 
82 
     | 
    
         
             
                    def message
         
     | 
| 
       83 
83 
     | 
    
         
             
                      message  = @offense.message
         
     | 
| 
       84 
     | 
    
         
            -
                      message += "\n\nThis offense is not auto-correctable.\n" unless  
     | 
| 
      
 84 
     | 
    
         
            +
                      message += "\n\nThis offense is not auto-correctable.\n" unless correctable?
         
     | 
| 
       85 
85 
     | 
    
         
             
                      message
         
     | 
| 
       86 
86 
     | 
    
         
             
                    end
         
     | 
| 
       87 
87 
     | 
    
         | 
| 
         @@ -115,7 +115,7 @@ module RubyLsp 
     | 
|
| 
       115 
115 
     | 
    
         
             
                                uri: @uri.to_s,
         
     | 
| 
       116 
116 
     | 
    
         
             
                                version: nil,
         
     | 
| 
       117 
117 
     | 
    
         
             
                              ),
         
     | 
| 
       118 
     | 
    
         
            -
                              edits:  
     | 
| 
      
 118 
     | 
    
         
            +
                              edits: correctable? ? offense_replacements : [],
         
     | 
| 
       119 
119 
     | 
    
         
             
                            ),
         
     | 
| 
       120 
120 
     | 
    
         
             
                          ],
         
     | 
| 
       121 
121 
     | 
    
         
             
                        ),
         
     | 
| 
         @@ -193,6 +193,14 @@ module RubyLsp 
     | 
|
| 
       193 
193 
     | 
    
         
             
                        line.length
         
     | 
| 
       194 
194 
     | 
    
         
             
                      end
         
     | 
| 
       195 
195 
     | 
    
         
             
                    end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                    # When `RuboCop::LSP.enable` is called, contextual autocorrect will not offer itself
         
     | 
| 
      
 198 
     | 
    
         
            +
                    # as `correctable?` to prevent annoying changes while typing. Instead check if
         
     | 
| 
      
 199 
     | 
    
         
            +
                    # a corrector is present. If it is, then that means some code transformation can be applied.
         
     | 
| 
      
 200 
     | 
    
         
            +
                    sig { returns(T::Boolean) }
         
     | 
| 
      
 201 
     | 
    
         
            +
                    def correctable?
         
     | 
| 
      
 202 
     | 
    
         
            +
                      !@offense.corrector.nil?
         
     | 
| 
      
 203 
     | 
    
         
            +
                    end
         
     | 
| 
       196 
204 
     | 
    
         
             
                  end
         
     | 
| 
       197 
205 
     | 
    
         
             
                end
         
     | 
| 
       198 
206 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,91 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # typed: strict
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module RubyLsp
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Requests
         
     | 
| 
      
 6 
     | 
    
         
            +
                # 
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                # The [type hierarchy supertypes
         
     | 
| 
      
 9 
     | 
    
         
            +
                # request](https://microsoft.github.io/language-server-protocol/specification#typeHierarchy_supertypes)
         
     | 
| 
      
 10 
     | 
    
         
            +
                # displays the list of ancestors (supertypes) for the selected type.
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                # # Example
         
     | 
| 
      
 13 
     | 
    
         
            +
                #
         
     | 
| 
      
 14 
     | 
    
         
            +
                # ```ruby
         
     | 
| 
      
 15 
     | 
    
         
            +
                # class Foo; end
         
     | 
| 
      
 16 
     | 
    
         
            +
                # class Bar < Foo; end
         
     | 
| 
      
 17 
     | 
    
         
            +
                #
         
     | 
| 
      
 18 
     | 
    
         
            +
                # puts Bar # <-- right click on `Bar` and select "Show Type Hierarchy"
         
     | 
| 
      
 19 
     | 
    
         
            +
                # ```
         
     | 
| 
      
 20 
     | 
    
         
            +
                class TypeHierarchySupertypes < Request
         
     | 
| 
      
 21 
     | 
    
         
            +
                  extend T::Sig
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  include Support::Common
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  sig { params(index: RubyIndexer::Index, item: T::Hash[Symbol, T.untyped]).void }
         
     | 
| 
      
 26 
     | 
    
         
            +
                  def initialize(index, item)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    super()
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    @index = index
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @item = item
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  sig { override.returns(T.nilable(T::Array[Interface::TypeHierarchyItem])) }
         
     | 
| 
      
 34 
     | 
    
         
            +
                  def perform
         
     | 
| 
      
 35 
     | 
    
         
            +
                    name = @item[:name]
         
     | 
| 
      
 36 
     | 
    
         
            +
                    entries = @index[name]
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    parents = T.let(Set.new, T::Set[RubyIndexer::Entry::Namespace])
         
     | 
| 
      
 39 
     | 
    
         
            +
                    return unless entries&.any?
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    entries.each do |entry|
         
     | 
| 
      
 42 
     | 
    
         
            +
                      next unless entry.is_a?(RubyIndexer::Entry::Namespace)
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                      if entry.is_a?(RubyIndexer::Entry::Class)
         
     | 
| 
      
 45 
     | 
    
         
            +
                        parent_class_name = entry.parent_class
         
     | 
| 
      
 46 
     | 
    
         
            +
                        if parent_class_name
         
     | 
| 
      
 47 
     | 
    
         
            +
                          resolved_parent_entries = @index.resolve(parent_class_name, entry.nesting)
         
     | 
| 
      
 48 
     | 
    
         
            +
                          resolved_parent_entries&.each do |entry|
         
     | 
| 
      
 49 
     | 
    
         
            +
                            next unless entry.is_a?(RubyIndexer::Entry::Class)
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                            parents << entry
         
     | 
| 
      
 52 
     | 
    
         
            +
                          end
         
     | 
| 
      
 53 
     | 
    
         
            +
                        end
         
     | 
| 
      
 54 
     | 
    
         
            +
                      end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                      entry.mixin_operations.each do |mixin_operation|
         
     | 
| 
      
 57 
     | 
    
         
            +
                        next if mixin_operation.is_a?(RubyIndexer::Entry::Extend)
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                        mixin_name = mixin_operation.module_name
         
     | 
| 
      
 60 
     | 
    
         
            +
                        resolved_mixin_entries = @index.resolve(mixin_name, entry.nesting)
         
     | 
| 
      
 61 
     | 
    
         
            +
                        next unless resolved_mixin_entries
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                        resolved_mixin_entries.each do |mixin_entry|
         
     | 
| 
      
 64 
     | 
    
         
            +
                          next unless mixin_entry.is_a?(RubyIndexer::Entry::Module)
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                          parents << mixin_entry
         
     | 
| 
      
 67 
     | 
    
         
            +
                        end
         
     | 
| 
      
 68 
     | 
    
         
            +
                      end
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    parents.map { |entry| hierarchy_item(entry) }
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  private
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  sig { params(entry: RubyIndexer::Entry).returns(Interface::TypeHierarchyItem) }
         
     | 
| 
      
 77 
     | 
    
         
            +
                  def hierarchy_item(entry)
         
     | 
| 
      
 78 
     | 
    
         
            +
                    range = range_from_location(entry.location)
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    Interface::TypeHierarchyItem.new(
         
     | 
| 
      
 81 
     | 
    
         
            +
                      name: entry.name,
         
     | 
| 
      
 82 
     | 
    
         
            +
                      kind: kind_for_entry(entry),
         
     | 
| 
      
 83 
     | 
    
         
            +
                      uri: URI::Generic.from_path(path: entry.file_path).to_s,
         
     | 
| 
      
 84 
     | 
    
         
            +
                      range: range,
         
     | 
| 
      
 85 
     | 
    
         
            +
                      selection_range: range,
         
     | 
| 
      
 86 
     | 
    
         
            +
                      detail: entry.file_name,
         
     | 
| 
      
 87 
     | 
    
         
            +
                    )
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -52,7 +52,7 @@ module RubyLsp 
     | 
|
| 
       52 
52 
     | 
    
         | 
| 
       53 
53 
     | 
    
         
             
                      Interface::WorkspaceSymbol.new(
         
     | 
| 
       54 
54 
     | 
    
         
             
                        name: entry.name,
         
     | 
| 
       55 
     | 
    
         
            -
                        container_name:  
     | 
| 
      
 55 
     | 
    
         
            +
                        container_name: container.join("::"),
         
     | 
| 
       56 
56 
     | 
    
         
             
                        kind: kind,
         
     | 
| 
       57 
57 
     | 
    
         
             
                        location: Interface::Location.new(
         
     | 
| 
       58 
58 
     | 
    
         
             
                          uri: URI::Generic.from_path(path: file_path).to_s,
         
     | 
| 
         @@ -64,26 +64,6 @@ module RubyLsp 
     | 
|
| 
       64 
64 
     | 
    
         
             
                      )
         
     | 
| 
       65 
65 
     | 
    
         
             
                    end
         
     | 
| 
       66 
66 
     | 
    
         
             
                  end
         
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                  private
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
                  sig { params(entry: RubyIndexer::Entry).returns(T.nilable(Integer)) }
         
     | 
| 
       71 
     | 
    
         
            -
                  def kind_for_entry(entry)
         
     | 
| 
       72 
     | 
    
         
            -
                    case entry
         
     | 
| 
       73 
     | 
    
         
            -
                    when RubyIndexer::Entry::Class
         
     | 
| 
       74 
     | 
    
         
            -
                      Constant::SymbolKind::CLASS
         
     | 
| 
       75 
     | 
    
         
            -
                    when RubyIndexer::Entry::Module
         
     | 
| 
       76 
     | 
    
         
            -
                      Constant::SymbolKind::NAMESPACE
         
     | 
| 
       77 
     | 
    
         
            -
                    when RubyIndexer::Entry::Constant
         
     | 
| 
       78 
     | 
    
         
            -
                      Constant::SymbolKind::CONSTANT
         
     | 
| 
       79 
     | 
    
         
            -
                    when RubyIndexer::Entry::Method
         
     | 
| 
       80 
     | 
    
         
            -
                      entry.name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
         
     | 
| 
       81 
     | 
    
         
            -
                    when RubyIndexer::Entry::Accessor
         
     | 
| 
       82 
     | 
    
         
            -
                      Constant::SymbolKind::PROPERTY
         
     | 
| 
       83 
     | 
    
         
            -
                    when RubyIndexer::Entry::InstanceVariable
         
     | 
| 
       84 
     | 
    
         
            -
                      Constant::SymbolKind::FIELD
         
     | 
| 
       85 
     | 
    
         
            -
                    end
         
     | 
| 
       86 
     | 
    
         
            -
                  end
         
     | 
| 
       87 
67 
     | 
    
         
             
                end
         
     | 
| 
       88 
68 
     | 
    
         
             
              end
         
     | 
| 
       89 
69 
     | 
    
         
             
            end
         
     | 
    
        data/lib/ruby_lsp/requests.rb
    CHANGED
    
    | 
         @@ -47,6 +47,8 @@ module RubyLsp 
     | 
|
| 
       47 
47 
     | 
    
         
             
                autoload :ShowSyntaxTree, "ruby_lsp/requests/show_syntax_tree"
         
     | 
| 
       48 
48 
     | 
    
         
             
                autoload :WorkspaceSymbol, "ruby_lsp/requests/workspace_symbol"
         
     | 
| 
       49 
49 
     | 
    
         
             
                autoload :SignatureHelp, "ruby_lsp/requests/signature_help"
         
     | 
| 
      
 50 
     | 
    
         
            +
                autoload :PrepareTypeHierarchy, "ruby_lsp/requests/prepare_type_hierarchy"
         
     | 
| 
      
 51 
     | 
    
         
            +
                autoload :TypeHierarchySupertypes, "ruby_lsp/requests/type_hierarchy_supertypes"
         
     | 
| 
       50 
52 
     | 
    
         | 
| 
       51 
53 
     | 
    
         
             
                # :nodoc:
         
     | 
| 
       52 
54 
     | 
    
         
             
                module Support
         
     |