ruby-lsp 0.17.17 → 0.18.3
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 +4 -110
 - data/VERSION +1 -1
 - data/exe/ruby-lsp +5 -11
 - data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +14 -6
 - data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +162 -27
 - data/lib/ruby_indexer/lib/ruby_indexer/index.rb +110 -8
 - data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +2 -2
 - data/lib/ruby_indexer/test/classes_and_modules_test.rb +24 -10
 - data/lib/ruby_indexer/test/constant_test.rb +4 -4
 - data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
 - data/lib/ruby_indexer/test/index_test.rb +68 -0
 - data/lib/ruby_indexer/test/method_test.rb +257 -2
 - data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
 - data/lib/ruby_lsp/base_server.rb +21 -1
 - data/lib/ruby_lsp/document.rb +5 -3
 - data/lib/ruby_lsp/erb_document.rb +29 -10
 - data/lib/ruby_lsp/global_state.rb +4 -3
 - data/lib/ruby_lsp/internal.rb +40 -2
 - data/lib/ruby_lsp/listeners/code_lens.rb +34 -5
 - data/lib/ruby_lsp/listeners/completion.rb +20 -6
 - data/lib/ruby_lsp/listeners/inlay_hints.rb +1 -16
 - data/lib/ruby_lsp/listeners/signature_help.rb +55 -24
 - data/lib/ruby_lsp/rbs_document.rb +5 -4
 - data/lib/ruby_lsp/requests/code_action_resolve.rb +0 -15
 - data/lib/ruby_lsp/requests/code_actions.rb +0 -10
 - data/lib/ruby_lsp/requests/code_lens.rb +1 -11
 - data/lib/ruby_lsp/requests/completion.rb +3 -20
 - data/lib/ruby_lsp/requests/completion_resolve.rb +2 -10
 - data/lib/ruby_lsp/requests/definition.rb +6 -20
 - data/lib/ruby_lsp/requests/diagnostics.rb +0 -10
 - data/lib/ruby_lsp/requests/document_highlight.rb +7 -14
 - data/lib/ruby_lsp/requests/document_link.rb +0 -10
 - data/lib/ruby_lsp/requests/document_symbol.rb +0 -17
 - data/lib/ruby_lsp/requests/folding_ranges.rb +0 -10
 - data/lib/ruby_lsp/requests/formatting.rb +0 -16
 - data/lib/ruby_lsp/requests/hover.rb +9 -9
 - data/lib/ruby_lsp/requests/inlay_hints.rb +2 -35
 - data/lib/ruby_lsp/requests/on_type_formatting.rb +0 -10
 - data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +0 -11
 - data/lib/ruby_lsp/requests/request.rb +17 -1
 - data/lib/ruby_lsp/requests/selection_ranges.rb +0 -10
 - data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -23
 - data/lib/ruby_lsp/requests/show_syntax_tree.rb +0 -11
 - data/lib/ruby_lsp/requests/signature_help.rb +5 -20
 - data/lib/ruby_lsp/requests/support/common.rb +1 -1
 - data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +2 -0
 - data/lib/ruby_lsp/requests/support/rubocop_runner.rb +2 -0
 - data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +0 -11
 - data/lib/ruby_lsp/requests/workspace_symbol.rb +0 -12
 - data/lib/ruby_lsp/ruby_document.rb +4 -3
 - data/lib/ruby_lsp/server.rb +45 -11
 - data/lib/ruby_lsp/setup_bundler.rb +33 -15
 - data/lib/ruby_lsp/type_inferrer.rb +8 -10
 - data/lib/ruby_lsp/utils.rb +11 -1
 - metadata +3 -6
 - data/lib/ruby_lsp/check_docs.rb +0 -130
 - data/lib/ruby_lsp/requests.rb +0 -64
 - data/lib/ruby_lsp/response_builders.rb +0 -13
 
| 
         @@ -242,6 +242,64 @@ module RubyIndexer 
     | 
|
| 
       242 
242 
     | 
    
         
             
                  completion_items.values.map!(&:first)
         
     | 
| 
       243 
243 
     | 
    
         
             
                end
         
     | 
| 
       244 
244 
     | 
    
         | 
| 
      
 245 
     | 
    
         
            +
                sig do
         
     | 
| 
      
 246 
     | 
    
         
            +
                  params(
         
     | 
| 
      
 247 
     | 
    
         
            +
                    name: String,
         
     | 
| 
      
 248 
     | 
    
         
            +
                    nesting: T::Array[String],
         
     | 
| 
      
 249 
     | 
    
         
            +
                  ).returns(T::Array[T::Array[T.any(
         
     | 
| 
      
 250 
     | 
    
         
            +
                    Entry::Constant,
         
     | 
| 
      
 251 
     | 
    
         
            +
                    Entry::ConstantAlias,
         
     | 
| 
      
 252 
     | 
    
         
            +
                    Entry::Namespace,
         
     | 
| 
      
 253 
     | 
    
         
            +
                    Entry::UnresolvedConstantAlias,
         
     | 
| 
      
 254 
     | 
    
         
            +
                  )]])
         
     | 
| 
      
 255 
     | 
    
         
            +
                end
         
     | 
| 
      
 256 
     | 
    
         
            +
                def constant_completion_candidates(name, nesting)
         
     | 
| 
      
 257 
     | 
    
         
            +
                  # If we have a top level reference, then we don't need to include completions inside the current nesting
         
     | 
| 
      
 258 
     | 
    
         
            +
                  if name.start_with?("::")
         
     | 
| 
      
 259 
     | 
    
         
            +
                    return T.cast(
         
     | 
| 
      
 260 
     | 
    
         
            +
                      @entries_tree.search(name.delete_prefix("::")),
         
     | 
| 
      
 261 
     | 
    
         
            +
                      T::Array[T::Array[T.any(
         
     | 
| 
      
 262 
     | 
    
         
            +
                        Entry::Constant,
         
     | 
| 
      
 263 
     | 
    
         
            +
                        Entry::ConstantAlias,
         
     | 
| 
      
 264 
     | 
    
         
            +
                        Entry::Namespace,
         
     | 
| 
      
 265 
     | 
    
         
            +
                        Entry::UnresolvedConstantAlias,
         
     | 
| 
      
 266 
     | 
    
         
            +
                      )]],
         
     | 
| 
      
 267 
     | 
    
         
            +
                    )
         
     | 
| 
      
 268 
     | 
    
         
            +
                  end
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
                  # Otherwise, we have to include every possible constant the user might be referring to. This is essentially the
         
     | 
| 
      
 271 
     | 
    
         
            +
                  # same algorithm as resolve, but instead of returning early we concatenate all unique results
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
                  # Direct constants inside this namespace
         
     | 
| 
      
 274 
     | 
    
         
            +
                  entries = @entries_tree.search(nesting.any? ? "#{nesting.join("::")}::#{name}" : name)
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
                  # Constants defined in enclosing scopes
         
     | 
| 
      
 277 
     | 
    
         
            +
                  nesting.length.downto(1) do |i|
         
     | 
| 
      
 278 
     | 
    
         
            +
                    namespace = T.must(nesting[0...i]).join("::")
         
     | 
| 
      
 279 
     | 
    
         
            +
                    entries.concat(@entries_tree.search("#{namespace}::#{name}"))
         
     | 
| 
      
 280 
     | 
    
         
            +
                  end
         
     | 
| 
      
 281 
     | 
    
         
            +
             
     | 
| 
      
 282 
     | 
    
         
            +
                  # Inherited constants
         
     | 
| 
      
 283 
     | 
    
         
            +
                  if name.end_with?("::")
         
     | 
| 
      
 284 
     | 
    
         
            +
                    entries.concat(inherited_constant_completion_candidates(nil, nesting + [name]))
         
     | 
| 
      
 285 
     | 
    
         
            +
                  else
         
     | 
| 
      
 286 
     | 
    
         
            +
                    entries.concat(inherited_constant_completion_candidates(name, nesting))
         
     | 
| 
      
 287 
     | 
    
         
            +
                  end
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
      
 289 
     | 
    
         
            +
                  # Top level constants
         
     | 
| 
      
 290 
     | 
    
         
            +
                  entries.concat(@entries_tree.search(name))
         
     | 
| 
      
 291 
     | 
    
         
            +
                  entries.uniq!
         
     | 
| 
      
 292 
     | 
    
         
            +
                  T.cast(
         
     | 
| 
      
 293 
     | 
    
         
            +
                    entries,
         
     | 
| 
      
 294 
     | 
    
         
            +
                    T::Array[T::Array[T.any(
         
     | 
| 
      
 295 
     | 
    
         
            +
                      Entry::Constant,
         
     | 
| 
      
 296 
     | 
    
         
            +
                      Entry::ConstantAlias,
         
     | 
| 
      
 297 
     | 
    
         
            +
                      Entry::Namespace,
         
     | 
| 
      
 298 
     | 
    
         
            +
                      Entry::UnresolvedConstantAlias,
         
     | 
| 
      
 299 
     | 
    
         
            +
                    )]],
         
     | 
| 
      
 300 
     | 
    
         
            +
                  )
         
     | 
| 
      
 301 
     | 
    
         
            +
                end
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
       245 
303 
     | 
    
         
             
                # Resolve a constant to its declaration based on its name and the nesting where the reference was found. Parameter
         
     | 
| 
       246 
304 
     | 
    
         
             
                # documentation:
         
     | 
| 
       247 
305 
     | 
    
         
             
                #
         
     | 
| 
         @@ -312,12 +370,12 @@ module RubyIndexer 
     | 
|
| 
       312 
370 
     | 
    
         
             
                      break unless block.call(progress)
         
     | 
| 
       313 
371 
     | 
    
         
             
                    end
         
     | 
| 
       314 
372 
     | 
    
         | 
| 
       315 
     | 
    
         
            -
                    index_single(path)
         
     | 
| 
      
 373 
     | 
    
         
            +
                    index_single(path, collect_comments: false)
         
     | 
| 
       316 
374 
     | 
    
         
             
                  end
         
     | 
| 
       317 
375 
     | 
    
         
             
                end
         
     | 
| 
       318 
376 
     | 
    
         | 
| 
       319 
     | 
    
         
            -
                sig { params(indexable_path: IndexablePath, source: T.nilable(String)).void }
         
     | 
| 
       320 
     | 
    
         
            -
                def index_single(indexable_path, source = nil)
         
     | 
| 
      
 377 
     | 
    
         
            +
                sig { params(indexable_path: IndexablePath, source: T.nilable(String), collect_comments: T::Boolean).void }
         
     | 
| 
      
 378 
     | 
    
         
            +
                def index_single(indexable_path, source = nil, collect_comments: true)
         
     | 
| 
       321 
379 
     | 
    
         
             
                  content = source || File.read(indexable_path.full_path)
         
     | 
| 
       322 
380 
     | 
    
         
             
                  dispatcher = Prism::Dispatcher.new
         
     | 
| 
       323 
381 
     | 
    
         | 
| 
         @@ -327,6 +385,7 @@ module RubyIndexer 
     | 
|
| 
       327 
385 
     | 
    
         
             
                    dispatcher,
         
     | 
| 
       328 
386 
     | 
    
         
             
                    result,
         
     | 
| 
       329 
387 
     | 
    
         
             
                    indexable_path.full_path,
         
     | 
| 
      
 388 
     | 
    
         
            +
                    collect_comments: collect_comments,
         
     | 
| 
       330 
389 
     | 
    
         
             
                    enhancements: @enhancements,
         
     | 
| 
       331 
390 
     | 
    
         
             
                  )
         
     | 
| 
       332 
391 
     | 
    
         
             
                  dispatcher.dispatch(result.value)
         
     | 
| 
         @@ -364,12 +423,10 @@ module RubyIndexer 
     | 
|
| 
       364 
423 
     | 
    
         
             
                # aliases, so we have to invoke `follow_aliased_namespace` again to check until we only return a real name
         
     | 
| 
       365 
424 
     | 
    
         
             
                sig { params(name: String, seen_names: T::Array[String]).returns(String) }
         
     | 
| 
       366 
425 
     | 
    
         
             
                def follow_aliased_namespace(name, seen_names = [])
         
     | 
| 
       367 
     | 
    
         
            -
                  return name if @entries[name]
         
     | 
| 
       368 
     | 
    
         
            -
             
     | 
| 
       369 
426 
     | 
    
         
             
                  parts = name.split("::")
         
     | 
| 
       370 
427 
     | 
    
         
             
                  real_parts = []
         
     | 
| 
       371 
428 
     | 
    
         | 
| 
       372 
     | 
    
         
            -
                  (parts.length - 1).downto(0) 
     | 
| 
      
 429 
     | 
    
         
            +
                  (parts.length - 1).downto(0) do |i|
         
     | 
| 
       373 
430 
     | 
    
         
             
                    current_name = T.must(parts[0..i]).join("::")
         
     | 
| 
       374 
431 
     | 
    
         
             
                    entry = @entries[current_name]&.first
         
     | 
| 
       375 
432 
     | 
    
         | 
| 
         @@ -607,7 +664,7 @@ module RubyIndexer 
     | 
|
| 
       607 
664 
     | 
    
         
             
                      attached_ancestor.file_path,
         
     | 
| 
       608 
665 
     | 
    
         
             
                      attached_ancestor.location,
         
     | 
| 
       609 
666 
     | 
    
         
             
                      attached_ancestor.name_location,
         
     | 
| 
       610 
     | 
    
         
            -
                       
     | 
| 
      
 667 
     | 
    
         
            +
                      nil,
         
     | 
| 
       611 
668 
     | 
    
         
             
                      nil,
         
     | 
| 
       612 
669 
     | 
    
         
             
                    )
         
     | 
| 
       613 
670 
     | 
    
         
             
                    add(singleton, skip_prefix_tree: true)
         
     | 
| 
         @@ -823,7 +880,7 @@ module RubyIndexer 
     | 
|
| 
       823 
880 
     | 
    
         
             
                  )]))
         
     | 
| 
       824 
881 
     | 
    
         
             
                end
         
     | 
| 
       825 
882 
     | 
    
         
             
                def lookup_enclosing_scopes(name, nesting, seen_names)
         
     | 
| 
       826 
     | 
    
         
            -
                  nesting.length.downto(1) 
     | 
| 
      
 883 
     | 
    
         
            +
                  nesting.length.downto(1) do |i|
         
     | 
| 
       827 
884 
     | 
    
         
             
                    namespace = T.must(nesting[0...i]).join("::")
         
     | 
| 
       828 
885 
     | 
    
         | 
| 
       829 
886 
     | 
    
         
             
                    # If we find an entry with `full_name` directly, then we can already return it, even if it contains aliases -
         
     | 
| 
         @@ -870,6 +927,51 @@ module RubyIndexer 
     | 
|
| 
       870 
927 
     | 
    
         
             
                  nil
         
     | 
| 
       871 
928 
     | 
    
         
             
                end
         
     | 
| 
       872 
929 
     | 
    
         | 
| 
      
 930 
     | 
    
         
            +
                sig do
         
     | 
| 
      
 931 
     | 
    
         
            +
                  params(
         
     | 
| 
      
 932 
     | 
    
         
            +
                    name: T.nilable(String),
         
     | 
| 
      
 933 
     | 
    
         
            +
                    nesting: T::Array[String],
         
     | 
| 
      
 934 
     | 
    
         
            +
                  ).returns(T::Array[T::Array[T.any(
         
     | 
| 
      
 935 
     | 
    
         
            +
                    Entry::Namespace,
         
     | 
| 
      
 936 
     | 
    
         
            +
                    Entry::ConstantAlias,
         
     | 
| 
      
 937 
     | 
    
         
            +
                    Entry::UnresolvedConstantAlias,
         
     | 
| 
      
 938 
     | 
    
         
            +
                    Entry::Constant,
         
     | 
| 
      
 939 
     | 
    
         
            +
                  )]])
         
     | 
| 
      
 940 
     | 
    
         
            +
                end
         
     | 
| 
      
 941 
     | 
    
         
            +
                def inherited_constant_completion_candidates(name, nesting)
         
     | 
| 
      
 942 
     | 
    
         
            +
                  namespace_entries = if name
         
     | 
| 
      
 943 
     | 
    
         
            +
                    *nesting_parts, constant_name = build_non_redundant_full_name(name, nesting).split("::")
         
     | 
| 
      
 944 
     | 
    
         
            +
                    return [] if nesting_parts.empty?
         
     | 
| 
      
 945 
     | 
    
         
            +
             
     | 
| 
      
 946 
     | 
    
         
            +
                    resolve(nesting_parts.join("::"), [])
         
     | 
| 
      
 947 
     | 
    
         
            +
                  else
         
     | 
| 
      
 948 
     | 
    
         
            +
                    resolve(nesting.join("::"), [])
         
     | 
| 
      
 949 
     | 
    
         
            +
                  end
         
     | 
| 
      
 950 
     | 
    
         
            +
                  return [] unless namespace_entries
         
     | 
| 
      
 951 
     | 
    
         
            +
             
     | 
| 
      
 952 
     | 
    
         
            +
                  ancestors = linearized_ancestors_of(T.must(namespace_entries.first).name)
         
     | 
| 
      
 953 
     | 
    
         
            +
                  candidates = ancestors.flat_map do |ancestor_name|
         
     | 
| 
      
 954 
     | 
    
         
            +
                    @entries_tree.search("#{ancestor_name}::#{constant_name}")
         
     | 
| 
      
 955 
     | 
    
         
            +
                  end
         
     | 
| 
      
 956 
     | 
    
         
            +
             
     | 
| 
      
 957 
     | 
    
         
            +
                  # For candidates with the same name, we must only show the first entry in the inheritance chain, since that's the
         
     | 
| 
      
 958 
     | 
    
         
            +
                  # one the user will be referring to in completion
         
     | 
| 
      
 959 
     | 
    
         
            +
                  completion_items = candidates.each_with_object({}) do |entries, hash|
         
     | 
| 
      
 960 
     | 
    
         
            +
                    *parts, short_name = T.must(entries.first).name.split("::")
         
     | 
| 
      
 961 
     | 
    
         
            +
                    namespace_name = parts.join("::")
         
     | 
| 
      
 962 
     | 
    
         
            +
                    ancestor_index = ancestors.index(namespace_name)
         
     | 
| 
      
 963 
     | 
    
         
            +
                    existing_entry, existing_entry_index = hash[short_name]
         
     | 
| 
      
 964 
     | 
    
         
            +
             
     | 
| 
      
 965 
     | 
    
         
            +
                    next unless ancestor_index && (!existing_entry || ancestor_index < existing_entry_index)
         
     | 
| 
      
 966 
     | 
    
         
            +
             
     | 
| 
      
 967 
     | 
    
         
            +
                    hash[short_name] = [entries, ancestor_index]
         
     | 
| 
      
 968 
     | 
    
         
            +
                  end
         
     | 
| 
      
 969 
     | 
    
         
            +
             
     | 
| 
      
 970 
     | 
    
         
            +
                  completion_items.values.map!(&:first)
         
     | 
| 
      
 971 
     | 
    
         
            +
                rescue NonExistingNamespaceError
         
     | 
| 
      
 972 
     | 
    
         
            +
                  []
         
     | 
| 
      
 973 
     | 
    
         
            +
                end
         
     | 
| 
      
 974 
     | 
    
         
            +
             
     | 
| 
       873 
975 
     | 
    
         
             
                # Removes redudancy from a constant reference's full name. For example, if we find a reference to `A::B::Foo` inside
         
     | 
| 
       874 
976 
     | 
    
         
             
                # of the ["A", "B"] nesting, then we should not concatenate the nesting with the name or else we'll end up with
         
     | 
| 
       875 
977 
     | 
    
         
             
                # `A::B::A::B::Foo`. This method will remove any redundant parts from the final name based on the reference and the
         
     | 
| 
         @@ -272,10 +272,10 @@ module RubyIndexer 
     | 
|
| 
       272 
272 
     | 
    
         
             
                    RBS::AST::Declarations::Constant,
         
     | 
| 
       273 
273 
     | 
    
         
             
                    RBS::AST::Members::MethodDefinition,
         
     | 
| 
       274 
274 
     | 
    
         
             
                    RBS::AST::Members::Alias,
         
     | 
| 
       275 
     | 
    
         
            -
                  )).returns(T 
     | 
| 
      
 275 
     | 
    
         
            +
                  )).returns(T.nilable(String))
         
     | 
| 
       276 
276 
     | 
    
         
             
                end
         
     | 
| 
       277 
277 
     | 
    
         
             
                def comments_to_string(declaration)
         
     | 
| 
       278 
     | 
    
         
            -
                   
     | 
| 
      
 278 
     | 
    
         
            +
                  declaration.comment&.string
         
     | 
| 
       279 
279 
     | 
    
         
             
                end
         
     | 
| 
       280 
280 
     | 
    
         
             
              end
         
     | 
| 
       281 
281 
     | 
    
         
             
            end
         
     | 
| 
         @@ -213,10 +213,10 @@ module RubyIndexer 
     | 
|
| 
       213 
213 
     | 
    
         
             
                  RUBY
         
     | 
| 
       214 
214 
     | 
    
         | 
| 
       215 
215 
     | 
    
         
             
                  foo_entry = @index["Foo"].first
         
     | 
| 
       216 
     | 
    
         
            -
                  assert_equal("This is a Foo comment\nThis is another Foo comment", foo_entry.comments 
     | 
| 
      
 216 
     | 
    
         
            +
                  assert_equal("This is a Foo comment\nThis is another Foo comment", foo_entry.comments)
         
     | 
| 
       217 
217 
     | 
    
         | 
| 
       218 
218 
     | 
    
         
             
                  bar_entry = @index["Bar"].first
         
     | 
| 
       219 
     | 
    
         
            -
                  assert_equal("This Bar comment has 1 line padding", bar_entry.comments 
     | 
| 
      
 219 
     | 
    
         
            +
                  assert_equal("This Bar comment has 1 line padding", bar_entry.comments)
         
     | 
| 
       220 
220 
     | 
    
         
             
                end
         
     | 
| 
       221 
221 
     | 
    
         | 
| 
       222 
222 
     | 
    
         
             
                def test_skips_comments_containing_invalid_encodings
         
     | 
| 
         @@ -239,10 +239,10 @@ module RubyIndexer 
     | 
|
| 
       239 
239 
     | 
    
         
             
                  RUBY
         
     | 
| 
       240 
240 
     | 
    
         | 
| 
       241 
241 
     | 
    
         
             
                  foo_entry = @index["Foo"].first
         
     | 
| 
       242 
     | 
    
         
            -
                  assert_equal("This is a Foo comment\nThis is another Foo comment", foo_entry.comments 
     | 
| 
      
 242 
     | 
    
         
            +
                  assert_equal("This is a Foo comment\nThis is another Foo comment", foo_entry.comments)
         
     | 
| 
       243 
243 
     | 
    
         | 
| 
       244 
244 
     | 
    
         
             
                  bar_entry = @index["Foo::Bar"].first
         
     | 
| 
       245 
     | 
    
         
            -
                  assert_equal("This is a Bar comment", bar_entry.comments 
     | 
| 
      
 245 
     | 
    
         
            +
                  assert_equal("This is a Bar comment", bar_entry.comments)
         
     | 
| 
       246 
246 
     | 
    
         
             
                end
         
     | 
| 
       247 
247 
     | 
    
         | 
| 
       248 
248 
     | 
    
         
             
                def test_comments_can_be_attached_to_a_reopened_class
         
     | 
| 
         @@ -255,10 +255,10 @@ module RubyIndexer 
     | 
|
| 
       255 
255 
     | 
    
         
             
                  RUBY
         
     | 
| 
       256 
256 
     | 
    
         | 
| 
       257 
257 
     | 
    
         
             
                  first_foo_entry = @index["Foo"][0]
         
     | 
| 
       258 
     | 
    
         
            -
                  assert_equal("This is a Foo comment", first_foo_entry.comments 
     | 
| 
      
 258 
     | 
    
         
            +
                  assert_equal("This is a Foo comment", first_foo_entry.comments)
         
     | 
| 
       259 
259 
     | 
    
         | 
| 
       260 
260 
     | 
    
         
             
                  second_foo_entry = @index["Foo"][1]
         
     | 
| 
       261 
     | 
    
         
            -
                  assert_equal("This is another Foo comment", second_foo_entry.comments 
     | 
| 
      
 261 
     | 
    
         
            +
                  assert_equal("This is another Foo comment", second_foo_entry.comments)
         
     | 
| 
       262 
262 
     | 
    
         
             
                end
         
     | 
| 
       263 
263 
     | 
    
         | 
| 
       264 
264 
     | 
    
         
             
                def test_comments_removes_the_leading_pound_and_space
         
     | 
| 
         @@ -271,10 +271,10 @@ module RubyIndexer 
     | 
|
| 
       271 
271 
     | 
    
         
             
                  RUBY
         
     | 
| 
       272 
272 
     | 
    
         | 
| 
       273 
273 
     | 
    
         
             
                  first_foo_entry = @index["Foo"][0]
         
     | 
| 
       274 
     | 
    
         
            -
                  assert_equal("This is a Foo comment", first_foo_entry.comments 
     | 
| 
      
 274 
     | 
    
         
            +
                  assert_equal("This is a Foo comment", first_foo_entry.comments)
         
     | 
| 
       275 
275 
     | 
    
         | 
| 
       276 
276 
     | 
    
         
             
                  second_foo_entry = @index["Bar"][0]
         
     | 
| 
       277 
     | 
    
         
            -
                  assert_equal("This is a Bar comment", second_foo_entry.comments 
     | 
| 
      
 277 
     | 
    
         
            +
                  assert_equal("This is a Bar comment", second_foo_entry.comments)
         
     | 
| 
       278 
278 
     | 
    
         
             
                end
         
     | 
| 
       279 
279 
     | 
    
         | 
| 
       280 
280 
     | 
    
         
             
                def test_private_class_and_module_indexing
         
     | 
| 
         @@ -483,7 +483,7 @@ module RubyIndexer 
     | 
|
| 
       483 
483 
     | 
    
         | 
| 
       484 
484 
     | 
    
         
             
                  foo = T.must(@index["Foo::<Class:Foo>"].first)
         
     | 
| 
       485 
485 
     | 
    
         
             
                  assert_equal(4, foo.location.start_line)
         
     | 
| 
       486 
     | 
    
         
            -
                  assert_equal("Some extra comments", foo.comments 
     | 
| 
      
 486 
     | 
    
         
            +
                  assert_equal("Some extra comments", foo.comments)
         
     | 
| 
       487 
487 
     | 
    
         
             
                end
         
     | 
| 
       488 
488 
     | 
    
         | 
| 
       489 
489 
     | 
    
         
             
                def test_dynamic_singleton_class_blocks
         
     | 
| 
         @@ -501,7 +501,7 @@ module RubyIndexer 
     | 
|
| 
       501 
501 
     | 
    
         
             
                  # That pattern cannot be properly analyzed statically and assuming that it's always a regular singleton simplifies
         
     | 
| 
       502 
502 
     | 
    
         
             
                  # the implementation considerably.
         
     | 
| 
       503 
503 
     | 
    
         
             
                  assert_equal(3, singleton.location.start_line)
         
     | 
| 
       504 
     | 
    
         
            -
                  assert_equal("Some extra comments", singleton.comments 
     | 
| 
      
 504 
     | 
    
         
            +
                  assert_equal("Some extra comments", singleton.comments)
         
     | 
| 
       505 
505 
     | 
    
         
             
                end
         
     | 
| 
       506 
506 
     | 
    
         | 
| 
       507 
507 
     | 
    
         
             
                def test_namespaces_inside_singleton_blocks
         
     | 
| 
         @@ -605,5 +605,19 @@ module RubyIndexer 
     | 
|
| 
       605 
605 
     | 
    
         
             
                  assert_entry("Foo::Bar", Entry::Class, "/fake/path/foo.rb:2-4:3-7")
         
     | 
| 
       606 
606 
     | 
    
         
             
                  assert_entry("Qux", Entry::Class, "/fake/path/foo.rb:5-4:6-7")
         
     | 
| 
       607 
607 
     | 
    
         
             
                end
         
     | 
| 
      
 608 
     | 
    
         
            +
             
     | 
| 
      
 609 
     | 
    
         
            +
                def test_lazy_comment_fetching_uses_correct_line_breaks_for_rendering
         
     | 
| 
      
 610 
     | 
    
         
            +
                  path = "lib/ruby_lsp/node_context.rb"
         
     | 
| 
      
 611 
     | 
    
         
            +
                  indexable = IndexablePath.new("#{Dir.pwd}/lib", path)
         
     | 
| 
      
 612 
     | 
    
         
            +
             
     | 
| 
      
 613 
     | 
    
         
            +
                  @index.index_single(indexable, collect_comments: false)
         
     | 
| 
      
 614 
     | 
    
         
            +
             
     | 
| 
      
 615 
     | 
    
         
            +
                  entry = @index["RubyLsp::NodeContext"].first
         
     | 
| 
      
 616 
     | 
    
         
            +
             
     | 
| 
      
 617 
     | 
    
         
            +
                  assert_equal(<<~COMMENTS.chomp, entry.comments)
         
     | 
| 
      
 618 
     | 
    
         
            +
                    This class allows listeners to access contextual information about a node in the AST, such as its parent,
         
     | 
| 
      
 619 
     | 
    
         
            +
                    its namespace nesting, and the surrounding CallNode (e.g. a method call).
         
     | 
| 
      
 620 
     | 
    
         
            +
                  COMMENTS
         
     | 
| 
      
 621 
     | 
    
         
            +
                end
         
     | 
| 
       608 
622 
     | 
    
         
             
              end
         
     | 
| 
       609 
623 
     | 
    
         
             
            end
         
     | 
| 
         @@ -86,16 +86,16 @@ module RubyIndexer 
     | 
|
| 
       86 
86 
     | 
    
         
             
                    A::BAZ = 1
         
     | 
| 
       87 
87 
     | 
    
         
             
                  RUBY
         
     | 
| 
       88 
88 
     | 
    
         | 
| 
       89 
     | 
    
         
            -
                  foo_comment = @index["FOO"].first.comments 
     | 
| 
      
 89 
     | 
    
         
            +
                  foo_comment = @index["FOO"].first.comments
         
     | 
| 
       90 
90 
     | 
    
         
             
                  assert_equal("FOO comment", foo_comment)
         
     | 
| 
       91 
91 
     | 
    
         | 
| 
       92 
     | 
    
         
            -
                  a_foo_comment = @index["A::FOO"].first.comments 
     | 
| 
      
 92 
     | 
    
         
            +
                  a_foo_comment = @index["A::FOO"].first.comments
         
     | 
| 
       93 
93 
     | 
    
         
             
                  assert_equal("A::FOO comment", a_foo_comment)
         
     | 
| 
       94 
94 
     | 
    
         | 
| 
       95 
     | 
    
         
            -
                  bar_comment = @index["BAR"].first.comments 
     | 
| 
      
 95 
     | 
    
         
            +
                  bar_comment = @index["BAR"].first.comments
         
     | 
| 
       96 
96 
     | 
    
         
             
                  assert_equal("::BAR comment", bar_comment)
         
     | 
| 
       97 
97 
     | 
    
         | 
| 
       98 
     | 
    
         
            -
                  a_baz_comment = @index["A::BAZ"].first.comments 
     | 
| 
      
 98 
     | 
    
         
            +
                  a_baz_comment = @index["A::BAZ"].first.comments
         
     | 
| 
       99 
99 
     | 
    
         
             
                  assert_equal("A::BAZ comment", a_baz_comment)
         
     | 
| 
       100 
100 
     | 
    
         
             
                end
         
     | 
| 
       101 
101 
     | 
    
         | 
| 
         @@ -38,7 +38,7 @@ module RubyIndexer 
     | 
|
| 
       38 
38 
     | 
    
         
             
                          file_path,
         
     | 
| 
       39 
39 
     | 
    
         
             
                          location,
         
     | 
| 
       40 
40 
     | 
    
         
             
                          location,
         
     | 
| 
       41 
     | 
    
         
            -
                           
     | 
| 
      
 41 
     | 
    
         
            +
                          nil,
         
     | 
| 
       42 
42 
     | 
    
         
             
                          [Entry::Signature.new([Entry::RequiredParameter.new(name: :a)])],
         
     | 
| 
       43 
43 
     | 
    
         
             
                          Entry::Visibility::PUBLIC,
         
     | 
| 
       44 
44 
     | 
    
         
             
                          owner,
         
     | 
| 
         @@ -120,7 +120,7 @@ module RubyIndexer 
     | 
|
| 
       120 
120 
     | 
    
         
             
                        file_path,
         
     | 
| 
       121 
121 
     | 
    
         
             
                        location,
         
     | 
| 
       122 
122 
     | 
    
         
             
                        location,
         
     | 
| 
       123 
     | 
    
         
            -
                         
     | 
| 
      
 123 
     | 
    
         
            +
                        nil,
         
     | 
| 
       124 
124 
     | 
    
         
             
                        [],
         
     | 
| 
       125 
125 
     | 
    
         
             
                        Entry::Visibility::PUBLIC,
         
     | 
| 
       126 
126 
     | 
    
         
             
                        owner,
         
     | 
| 
         @@ -1863,5 +1863,73 @@ module RubyIndexer 
     | 
|
| 
       1863 
1863 
     | 
    
         
             
                def test_entries_for_returns_nil_if_no_matches
         
     | 
| 
       1864 
1864 
     | 
    
         
             
                  assert_nil(@index.entries_for("non_existing_file.rb", Entry::Namespace))
         
     | 
| 
       1865 
1865 
     | 
    
         
             
                end
         
     | 
| 
      
 1866 
     | 
    
         
            +
             
     | 
| 
      
 1867 
     | 
    
         
            +
                def test_constant_completion_candidates_all_possible_constants
         
     | 
| 
      
 1868 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 1869 
     | 
    
         
            +
                    XQRK = 3
         
     | 
| 
      
 1870 
     | 
    
         
            +
             
     | 
| 
      
 1871 
     | 
    
         
            +
                    module Bar
         
     | 
| 
      
 1872 
     | 
    
         
            +
                      XQRK = 2
         
     | 
| 
      
 1873 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1874 
     | 
    
         
            +
             
     | 
| 
      
 1875 
     | 
    
         
            +
                    module Foo
         
     | 
| 
      
 1876 
     | 
    
         
            +
                      XQRK = 1
         
     | 
| 
      
 1877 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1878 
     | 
    
         
            +
             
     | 
| 
      
 1879 
     | 
    
         
            +
                    module Namespace
         
     | 
| 
      
 1880 
     | 
    
         
            +
                      XQRK = 0
         
     | 
| 
      
 1881 
     | 
    
         
            +
             
     | 
| 
      
 1882 
     | 
    
         
            +
                      class Baz
         
     | 
| 
      
 1883 
     | 
    
         
            +
                        include Foo
         
     | 
| 
      
 1884 
     | 
    
         
            +
                        include Bar
         
     | 
| 
      
 1885 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1886 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1887 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 1888 
     | 
    
         
            +
             
     | 
| 
      
 1889 
     | 
    
         
            +
                  result = @index.constant_completion_candidates("X", ["Namespace", "Baz"])
         
     | 
| 
      
 1890 
     | 
    
         
            +
             
     | 
| 
      
 1891 
     | 
    
         
            +
                  result.each do |entries|
         
     | 
| 
      
 1892 
     | 
    
         
            +
                    name = entries.first.name
         
     | 
| 
      
 1893 
     | 
    
         
            +
                    assert(entries.all? { |e| e.name == name })
         
     | 
| 
      
 1894 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1895 
     | 
    
         
            +
             
     | 
| 
      
 1896 
     | 
    
         
            +
                  assert_equal(["Namespace::XQRK", "Bar::XQRK", "XQRK"], result.map { |entries| entries.first.name })
         
     | 
| 
      
 1897 
     | 
    
         
            +
             
     | 
| 
      
 1898 
     | 
    
         
            +
                  result = @index.constant_completion_candidates("::X", ["Namespace", "Baz"])
         
     | 
| 
      
 1899 
     | 
    
         
            +
                  assert_equal(["XQRK"], result.map { |entries| entries.first.name })
         
     | 
| 
      
 1900 
     | 
    
         
            +
                end
         
     | 
| 
      
 1901 
     | 
    
         
            +
             
     | 
| 
      
 1902 
     | 
    
         
            +
                def test_constant_completion_candidates_for_empty_name
         
     | 
| 
      
 1903 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 1904 
     | 
    
         
            +
                    module Foo
         
     | 
| 
      
 1905 
     | 
    
         
            +
                      Bar = 1
         
     | 
| 
      
 1906 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1907 
     | 
    
         
            +
             
     | 
| 
      
 1908 
     | 
    
         
            +
                    class Baz
         
     | 
| 
      
 1909 
     | 
    
         
            +
                      include Foo
         
     | 
| 
      
 1910 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1911 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 1912 
     | 
    
         
            +
             
     | 
| 
      
 1913 
     | 
    
         
            +
                  result = @index.constant_completion_candidates("Baz::", [])
         
     | 
| 
      
 1914 
     | 
    
         
            +
                  assert_includes(result.map { |entries| entries.first.name }, "Foo::Bar")
         
     | 
| 
      
 1915 
     | 
    
         
            +
                end
         
     | 
| 
      
 1916 
     | 
    
         
            +
             
     | 
| 
      
 1917 
     | 
    
         
            +
                def test_follow_alias_namespace
         
     | 
| 
      
 1918 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 1919 
     | 
    
         
            +
                    module First
         
     | 
| 
      
 1920 
     | 
    
         
            +
                      module Second
         
     | 
| 
      
 1921 
     | 
    
         
            +
                        class Foo
         
     | 
| 
      
 1922 
     | 
    
         
            +
                        end
         
     | 
| 
      
 1923 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1924 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1925 
     | 
    
         
            +
             
     | 
| 
      
 1926 
     | 
    
         
            +
                    module Namespace
         
     | 
| 
      
 1927 
     | 
    
         
            +
                      Second = First::Second
         
     | 
| 
      
 1928 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1929 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 1930 
     | 
    
         
            +
             
     | 
| 
      
 1931 
     | 
    
         
            +
                  real_namespace = @index.follow_aliased_namespace("Namespace::Second")
         
     | 
| 
      
 1932 
     | 
    
         
            +
                  assert_equal("First::Second", real_namespace)
         
     | 
| 
      
 1933 
     | 
    
         
            +
                end
         
     | 
| 
       1866 
1934 
     | 
    
         
             
              end
         
     | 
| 
       1867 
1935 
     | 
    
         
             
            end
         
     | 
| 
         @@ -330,6 +330,33 @@ module RubyIndexer 
     | 
|
| 
       330 
330 
     | 
    
         
             
                  assert_empty(parameters)
         
     | 
| 
       331 
331 
     | 
    
         
             
                end
         
     | 
| 
       332 
332 
     | 
    
         | 
| 
      
 333 
     | 
    
         
            +
                def test_methods_with_argument_forwarding
         
     | 
| 
      
 334 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 335 
     | 
    
         
            +
                    class Foo
         
     | 
| 
      
 336 
     | 
    
         
            +
                      def bar(...)
         
     | 
| 
      
 337 
     | 
    
         
            +
                      end
         
     | 
| 
      
 338 
     | 
    
         
            +
             
     | 
| 
      
 339 
     | 
    
         
            +
                      def baz(a, ...)
         
     | 
| 
      
 340 
     | 
    
         
            +
                      end
         
     | 
| 
      
 341 
     | 
    
         
            +
                    end
         
     | 
| 
      
 342 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 343 
     | 
    
         
            +
             
     | 
| 
      
 344 
     | 
    
         
            +
                  entry = T.must(@index["bar"].first)
         
     | 
| 
      
 345 
     | 
    
         
            +
                  assert_instance_of(Entry::Method, entry, "Expected `bar` to be indexed")
         
     | 
| 
      
 346 
     | 
    
         
            +
             
     | 
| 
      
 347 
     | 
    
         
            +
                  parameters = entry.signatures.first.parameters
         
     | 
| 
      
 348 
     | 
    
         
            +
                  assert_equal(1, parameters.length)
         
     | 
| 
      
 349 
     | 
    
         
            +
                  assert_instance_of(Entry::ForwardingParameter, parameters.first)
         
     | 
| 
      
 350 
     | 
    
         
            +
             
     | 
| 
      
 351 
     | 
    
         
            +
                  entry = T.must(@index["baz"].first)
         
     | 
| 
      
 352 
     | 
    
         
            +
                  assert_instance_of(Entry::Method, entry, "Expected `baz` to be indexed")
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
                  parameters = entry.signatures.first.parameters
         
     | 
| 
      
 355 
     | 
    
         
            +
                  assert_equal(2, parameters.length)
         
     | 
| 
      
 356 
     | 
    
         
            +
                  assert_instance_of(Entry::RequiredParameter, parameters[0])
         
     | 
| 
      
 357 
     | 
    
         
            +
                  assert_instance_of(Entry::ForwardingParameter, parameters[1])
         
     | 
| 
      
 358 
     | 
    
         
            +
                end
         
     | 
| 
      
 359 
     | 
    
         
            +
             
     | 
| 
       333 
360 
     | 
    
         
             
                def test_keeps_track_of_method_owner
         
     | 
| 
       334 
361 
     | 
    
         
             
                  index(<<~RUBY)
         
     | 
| 
       335 
362 
     | 
    
         
             
                    class Foo
         
     | 
| 
         @@ -355,9 +382,9 @@ module RubyIndexer 
     | 
|
| 
       355 
382 
     | 
    
         
             
                  RUBY
         
     | 
| 
       356 
383 
     | 
    
         | 
| 
       357 
384 
     | 
    
         
             
                  assert_entry("bar", Entry::Accessor, "/fake/path/foo.rb:2-15:2-18")
         
     | 
| 
       358 
     | 
    
         
            -
                  assert_equal("Hello there", @index["bar"].first.comments 
     | 
| 
      
 385 
     | 
    
         
            +
                  assert_equal("Hello there", @index["bar"].first.comments)
         
     | 
| 
       359 
386 
     | 
    
         
             
                  assert_entry("other", Entry::Accessor, "/fake/path/foo.rb:2-21:2-26")
         
     | 
| 
       360 
     | 
    
         
            -
                  assert_equal("Hello there", @index["other"].first.comments 
     | 
| 
      
 387 
     | 
    
         
            +
                  assert_equal("Hello there", @index["other"].first.comments)
         
     | 
| 
       361 
388 
     | 
    
         
             
                  assert_entry("baz=", Entry::Accessor, "/fake/path/foo.rb:3-15:3-18")
         
     | 
| 
       362 
389 
     | 
    
         
             
                  assert_entry("qux", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
         
     | 
| 
       363 
390 
     | 
    
         
             
                  assert_entry("qux=", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
         
     | 
| 
         @@ -461,5 +488,233 @@ module RubyIndexer 
     | 
|
| 
       461 
488 
     | 
    
         
             
                  assert_equal(6, name_location.start_column)
         
     | 
| 
       462 
489 
     | 
    
         
             
                  assert_equal(9, name_location.end_column)
         
     | 
| 
       463 
490 
     | 
    
         
             
                end
         
     | 
| 
      
 491 
     | 
    
         
            +
             
     | 
| 
      
 492 
     | 
    
         
            +
                def test_signature_matches_for_a_method_with_positional_params
         
     | 
| 
      
 493 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 494 
     | 
    
         
            +
                    class Foo
         
     | 
| 
      
 495 
     | 
    
         
            +
                      def bar(a, b = 123)
         
     | 
| 
      
 496 
     | 
    
         
            +
                      end
         
     | 
| 
      
 497 
     | 
    
         
            +
                    end
         
     | 
| 
      
 498 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 499 
     | 
    
         
            +
             
     | 
| 
      
 500 
     | 
    
         
            +
                  entry = T.must(@index["bar"].first)
         
     | 
| 
      
 501 
     | 
    
         
            +
             
     | 
| 
      
 502 
     | 
    
         
            +
                  # Matching calls
         
     | 
| 
      
 503 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar()")
         
     | 
| 
      
 504 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1)")
         
     | 
| 
      
 505 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2)")
         
     | 
| 
      
 506 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(...)")
         
     | 
| 
      
 507 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, ...)")
         
     | 
| 
      
 508 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a)")
         
     | 
| 
      
 509 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a)")
         
     | 
| 
      
 510 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a, 2)")
         
     | 
| 
      
 511 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a, 2)")
         
     | 
| 
      
 512 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, **a)")
         
     | 
| 
      
 513 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1) {}")
         
     | 
| 
      
 514 
     | 
    
         
            +
                  # This call is impossible to analyze statically because it depends on whether there are elements inside `a` or
         
     | 
| 
      
 515 
     | 
    
         
            +
                  # not. If there's nothing, the call will fail. But if there's anything inside, the hash will become the first
         
     | 
| 
      
 516 
     | 
    
         
            +
                  # positional argument
         
     | 
| 
      
 517 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(**a)")
         
     | 
| 
      
 518 
     | 
    
         
            +
             
     | 
| 
      
 519 
     | 
    
         
            +
                  # Non matching calls
         
     | 
| 
      
 520 
     | 
    
         
            +
             
     | 
| 
      
 521 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, 2, 3)")
         
     | 
| 
      
 522 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, b: 2)")
         
     | 
| 
      
 523 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, 2, c: 3)")
         
     | 
| 
      
 524 
     | 
    
         
            +
                end
         
     | 
| 
      
 525 
     | 
    
         
            +
             
     | 
| 
      
 526 
     | 
    
         
            +
                def test_signature_matches_for_a_method_with_argument_forwarding
         
     | 
| 
      
 527 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 528 
     | 
    
         
            +
                    class Foo
         
     | 
| 
      
 529 
     | 
    
         
            +
                      def bar(...)
         
     | 
| 
      
 530 
     | 
    
         
            +
                      end
         
     | 
| 
      
 531 
     | 
    
         
            +
                    end
         
     | 
| 
      
 532 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 533 
     | 
    
         
            +
             
     | 
| 
      
 534 
     | 
    
         
            +
                  entry = T.must(@index["bar"].first)
         
     | 
| 
      
 535 
     | 
    
         
            +
             
     | 
| 
      
 536 
     | 
    
         
            +
                  # All calls match a forwarding parameter
         
     | 
| 
      
 537 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1)")
         
     | 
| 
      
 538 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2)")
         
     | 
| 
      
 539 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(...)")
         
     | 
| 
      
 540 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, ...)")
         
     | 
| 
      
 541 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a)")
         
     | 
| 
      
 542 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a)")
         
     | 
| 
      
 543 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a, 2)")
         
     | 
| 
      
 544 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a, 2)")
         
     | 
| 
      
 545 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, **a)")
         
     | 
| 
      
 546 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1) {}")
         
     | 
| 
      
 547 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar()")
         
     | 
| 
      
 548 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2, 3)")
         
     | 
| 
      
 549 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2, a: 1, b: 5) {}")
         
     | 
| 
      
 550 
     | 
    
         
            +
                end
         
     | 
| 
      
 551 
     | 
    
         
            +
             
     | 
| 
      
 552 
     | 
    
         
            +
                def test_signature_matches_for_post_forwarding_parameter
         
     | 
| 
      
 553 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 554 
     | 
    
         
            +
                    class Foo
         
     | 
| 
      
 555 
     | 
    
         
            +
                      def bar(a, ...)
         
     | 
| 
      
 556 
     | 
    
         
            +
                      end
         
     | 
| 
      
 557 
     | 
    
         
            +
                    end
         
     | 
| 
      
 558 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 559 
     | 
    
         
            +
             
     | 
| 
      
 560 
     | 
    
         
            +
                  entry = T.must(@index["bar"].first)
         
     | 
| 
      
 561 
     | 
    
         
            +
             
     | 
| 
      
 562 
     | 
    
         
            +
                  # All calls with at least one positional argument match
         
     | 
| 
      
 563 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1)")
         
     | 
| 
      
 564 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2)")
         
     | 
| 
      
 565 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(...)")
         
     | 
| 
      
 566 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, ...)")
         
     | 
| 
      
 567 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a)")
         
     | 
| 
      
 568 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a)")
         
     | 
| 
      
 569 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a, 2)")
         
     | 
| 
      
 570 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a, 2)")
         
     | 
| 
      
 571 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, **a)")
         
     | 
| 
      
 572 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1) {}")
         
     | 
| 
      
 573 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2, 3)")
         
     | 
| 
      
 574 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2, a: 1, b: 5) {}")
         
     | 
| 
      
 575 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar()")
         
     | 
| 
      
 576 
     | 
    
         
            +
                end
         
     | 
| 
      
 577 
     | 
    
         
            +
             
     | 
| 
      
 578 
     | 
    
         
            +
                def test_signature_matches_for_destructured_parameters
         
     | 
| 
      
 579 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 580 
     | 
    
         
            +
                    class Foo
         
     | 
| 
      
 581 
     | 
    
         
            +
                      def bar(a, (b, c))
         
     | 
| 
      
 582 
     | 
    
         
            +
                      end
         
     | 
| 
      
 583 
     | 
    
         
            +
                    end
         
     | 
| 
      
 584 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 585 
     | 
    
         
            +
             
     | 
| 
      
 586 
     | 
    
         
            +
                  entry = T.must(@index["bar"].first)
         
     | 
| 
      
 587 
     | 
    
         
            +
             
     | 
| 
      
 588 
     | 
    
         
            +
                  # All calls with at least one positional argument match
         
     | 
| 
      
 589 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar()")
         
     | 
| 
      
 590 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1)")
         
     | 
| 
      
 591 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2)")
         
     | 
| 
      
 592 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(...)")
         
     | 
| 
      
 593 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, ...)")
         
     | 
| 
      
 594 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a)")
         
     | 
| 
      
 595 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a)")
         
     | 
| 
      
 596 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a, 2)")
         
     | 
| 
      
 597 
     | 
    
         
            +
                  # This matches because `bar(1, *[], 2)` would result in `bar(1, 2)`, which is a valid call
         
     | 
| 
      
 598 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a, 2)")
         
     | 
| 
      
 599 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, **a)")
         
     | 
| 
      
 600 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1) {}")
         
     | 
| 
      
 601 
     | 
    
         
            +
             
     | 
| 
      
 602 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, 2, 3)")
         
     | 
| 
      
 603 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, 2, a: 1, b: 5) {}")
         
     | 
| 
      
 604 
     | 
    
         
            +
                end
         
     | 
| 
      
 605 
     | 
    
         
            +
             
     | 
| 
      
 606 
     | 
    
         
            +
                def test_signature_matches_for_post_parameters
         
     | 
| 
      
 607 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 608 
     | 
    
         
            +
                    class Foo
         
     | 
| 
      
 609 
     | 
    
         
            +
                      def bar(*splat, a)
         
     | 
| 
      
 610 
     | 
    
         
            +
                      end
         
     | 
| 
      
 611 
     | 
    
         
            +
                    end
         
     | 
| 
      
 612 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 613 
     | 
    
         
            +
             
     | 
| 
      
 614 
     | 
    
         
            +
                  entry = T.must(@index["bar"].first)
         
     | 
| 
      
 615 
     | 
    
         
            +
             
     | 
| 
      
 616 
     | 
    
         
            +
                  # All calls with at least one positional argument match
         
     | 
| 
      
 617 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1)")
         
     | 
| 
      
 618 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2)")
         
     | 
| 
      
 619 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(...)")
         
     | 
| 
      
 620 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, ...)")
         
     | 
| 
      
 621 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a)")
         
     | 
| 
      
 622 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a)")
         
     | 
| 
      
 623 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(*a, 2)")
         
     | 
| 
      
 624 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, *a, 2)")
         
     | 
| 
      
 625 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, **a)")
         
     | 
| 
      
 626 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, 2, 3)")
         
     | 
| 
      
 627 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1) {}")
         
     | 
| 
      
 628 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar()")
         
     | 
| 
      
 629 
     | 
    
         
            +
             
     | 
| 
      
 630 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, 2, a: 1, b: 5) {}")
         
     | 
| 
      
 631 
     | 
    
         
            +
                end
         
     | 
| 
      
 632 
     | 
    
         
            +
             
     | 
| 
      
 633 
     | 
    
         
            +
                def test_signature_matches_for_keyword_parameters
         
     | 
| 
      
 634 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 635 
     | 
    
         
            +
                    class Foo
         
     | 
| 
      
 636 
     | 
    
         
            +
                      def bar(a:, b: 123)
         
     | 
| 
      
 637 
     | 
    
         
            +
                      end
         
     | 
| 
      
 638 
     | 
    
         
            +
                    end
         
     | 
| 
      
 639 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 640 
     | 
    
         
            +
             
     | 
| 
      
 641 
     | 
    
         
            +
                  entry = T.must(@index["bar"].first)
         
     | 
| 
      
 642 
     | 
    
         
            +
             
     | 
| 
      
 643 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(...)")
         
     | 
| 
      
 644 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar()")
         
     | 
| 
      
 645 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(a: 1)")
         
     | 
| 
      
 646 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(a: 1, b: 32)")
         
     | 
| 
      
 647 
     | 
    
         
            +
             
     | 
| 
      
 648 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(a: 1, c: 2)")
         
     | 
| 
      
 649 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, ...)")
         
     | 
| 
      
 650 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1) {}")
         
     | 
| 
      
 651 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, *a)")
         
     | 
| 
      
 652 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(*a, 2)")
         
     | 
| 
      
 653 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, *a, 2)")
         
     | 
| 
      
 654 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, **a)")
         
     | 
| 
      
 655 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(*a)")
         
     | 
| 
      
 656 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1)")
         
     | 
| 
      
 657 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, 2)")
         
     | 
| 
      
 658 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, 2, a: 1, b: 5) {}")
         
     | 
| 
      
 659 
     | 
    
         
            +
                end
         
     | 
| 
      
 660 
     | 
    
         
            +
             
     | 
| 
      
 661 
     | 
    
         
            +
                def test_signature_matches_for_keyword_splats
         
     | 
| 
      
 662 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 663 
     | 
    
         
            +
                    class Foo
         
     | 
| 
      
 664 
     | 
    
         
            +
                      def bar(a, b:, **kwargs)
         
     | 
| 
      
 665 
     | 
    
         
            +
                      end
         
     | 
| 
      
 666 
     | 
    
         
            +
                    end
         
     | 
| 
      
 667 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 668 
     | 
    
         
            +
             
     | 
| 
      
 669 
     | 
    
         
            +
                  entry = T.must(@index["bar"].first)
         
     | 
| 
      
 670 
     | 
    
         
            +
             
     | 
| 
      
 671 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(...)")
         
     | 
| 
      
 672 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar()")
         
     | 
| 
      
 673 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1)")
         
     | 
| 
      
 674 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, b: 2)")
         
     | 
| 
      
 675 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(1, b: 2, c: 3, d: 4)")
         
     | 
| 
      
 676 
     | 
    
         
            +
             
     | 
| 
      
 677 
     | 
    
         
            +
                  refute_signature_matches(entry, "bar(1, 2, b: 2)")
         
     | 
| 
      
 678 
     | 
    
         
            +
                end
         
     | 
| 
      
 679 
     | 
    
         
            +
             
     | 
| 
      
 680 
     | 
    
         
            +
                def test_partial_signature_matches
         
     | 
| 
      
 681 
     | 
    
         
            +
                  # It's important to match signatures partially, because we want to figure out which signature we should show while
         
     | 
| 
      
 682 
     | 
    
         
            +
                  # the user is in the middle of typing
         
     | 
| 
      
 683 
     | 
    
         
            +
                  index(<<~RUBY)
         
     | 
| 
      
 684 
     | 
    
         
            +
                    class Foo
         
     | 
| 
      
 685 
     | 
    
         
            +
                      def bar(a:, b:)
         
     | 
| 
      
 686 
     | 
    
         
            +
                      end
         
     | 
| 
      
 687 
     | 
    
         
            +
             
     | 
| 
      
 688 
     | 
    
         
            +
                      def baz(a, b)
         
     | 
| 
      
 689 
     | 
    
         
            +
                      end
         
     | 
| 
      
 690 
     | 
    
         
            +
                    end
         
     | 
| 
      
 691 
     | 
    
         
            +
                  RUBY
         
     | 
| 
      
 692 
     | 
    
         
            +
             
     | 
| 
      
 693 
     | 
    
         
            +
                  entry = T.must(@index["bar"].first)
         
     | 
| 
      
 694 
     | 
    
         
            +
                  assert_signature_matches(entry, "bar(a: 1)")
         
     | 
| 
      
 695 
     | 
    
         
            +
             
     | 
| 
      
 696 
     | 
    
         
            +
                  entry = T.must(@index["baz"].first)
         
     | 
| 
      
 697 
     | 
    
         
            +
                  assert_signature_matches(entry, "baz(1)")
         
     | 
| 
      
 698 
     | 
    
         
            +
                end
         
     | 
| 
      
 699 
     | 
    
         
            +
             
     | 
| 
      
 700 
     | 
    
         
            +
                private
         
     | 
| 
      
 701 
     | 
    
         
            +
             
     | 
| 
      
 702 
     | 
    
         
            +
                sig { params(entry: Entry::Method, call_string: String).void }
         
     | 
| 
      
 703 
     | 
    
         
            +
                def assert_signature_matches(entry, call_string)
         
     | 
| 
      
 704 
     | 
    
         
            +
                  sig = T.must(entry.signatures.first)
         
     | 
| 
      
 705 
     | 
    
         
            +
                  arguments = parse_prism_args(call_string)
         
     | 
| 
      
 706 
     | 
    
         
            +
                  assert(sig.matches?(arguments), "Expected #{call_string} to match #{entry.name}#{entry.decorated_parameters}")
         
     | 
| 
      
 707 
     | 
    
         
            +
                end
         
     | 
| 
      
 708 
     | 
    
         
            +
             
     | 
| 
      
 709 
     | 
    
         
            +
                sig { params(entry: Entry::Method, call_string: String).void }
         
     | 
| 
      
 710 
     | 
    
         
            +
                def refute_signature_matches(entry, call_string)
         
     | 
| 
      
 711 
     | 
    
         
            +
                  sig = T.must(entry.signatures.first)
         
     | 
| 
      
 712 
     | 
    
         
            +
                  arguments = parse_prism_args(call_string)
         
     | 
| 
      
 713 
     | 
    
         
            +
                  refute(sig.matches?(arguments), "Expected #{call_string} to not match #{entry.name}#{entry.decorated_parameters}")
         
     | 
| 
      
 714 
     | 
    
         
            +
                end
         
     | 
| 
      
 715 
     | 
    
         
            +
             
     | 
| 
      
 716 
     | 
    
         
            +
                def parse_prism_args(s)
         
     | 
| 
      
 717 
     | 
    
         
            +
                  Array(Prism.parse(s).value.statements.body.first.arguments&.arguments)
         
     | 
| 
      
 718 
     | 
    
         
            +
                end
         
     | 
| 
       464 
719 
     | 
    
         
             
              end
         
     | 
| 
       465 
720 
     | 
    
         
             
            end
         
     | 
| 
         @@ -345,7 +345,7 @@ module RubyIndexer 
     | 
|
| 
       345 
345 
     | 
    
         
             
                  assert_equal("all?", entry.old_name)
         
     | 
| 
       346 
346 
     | 
    
         
             
                  assert_equal("Array", entry.owner.name)
         
     | 
| 
       347 
347 
     | 
    
         
             
                  assert(entry.file_path.end_with?("core/array.rbs"))
         
     | 
| 
       348 
     | 
    
         
            -
                  assert_includes(entry.comments 
     | 
| 
      
 348 
     | 
    
         
            +
                  assert_includes(entry.comments, "Returns `true` if any element of `self` meets a given criterion.")
         
     | 
| 
       349 
349 
     | 
    
         
             
                end
         
     | 
| 
       350 
350 
     | 
    
         | 
| 
       351 
351 
     | 
    
         
             
                private
         
     |