Skip to content

Conversation

@lekemula
Copy link
Contributor

@lekemula lekemula commented Aug 21, 2025

Warning

DISCLAIMER: @claude was used to generate the code of the new methods, but mostly because I knew what I was looking for, and I was too lazy to figure out the methods needed to be called to make it work.

Problem

In my current work project (with 7,140 Ruby files with 109,664 total lines), I've noticed that initial or cold LSP completions were taking an extremely long time. By initial or cold completions, I mean:

  1. First requests after LSP boot (> ~40s)
  2. First requests after opening a new file (~10-20s)
  3. First requests after editing an open file (~10-20s)

The subsequent completions were fine up until the next edit, I'm assuming due to the caching ( less than typically ~0.5-1s)

# .solargraph.yml
---
include:
  - "**/*.rb"
exclude:
  - "**/spec/**/*"
  - test/**/*
  - vendor/**/*
  - ".bundle/**/*"
domains: []
plugins:
  - solargraph-rspec
  - solargraph-rails
rspec:
  let_methods:
    - let_it_be
reporters:
  - rubocop
  - require_not_found
formatter:
  rubocop:
    cops: all
max_files: 20000

Coming from the #1028, I initially thought the issue might be related to the indexing store update. However after using the excellent profiler, vernier, I came to find that the bottleneck seemed to be the Solargraph::ApiMap#resolve_method_aliases particularly its recursive usage of #get_method_stack inside Solargraph::ApiMap#resolve_method_alias

origin = get_method_stack(pin.full_context.tag, pin.original, scope: pin.scope, preserve_generics: true).first

Vernier screenshot image

Solution

Replace recursive get_method_stack and linear search with direct indexed method lookup via Store and Index.

  • Add indexed lookups for methods and aliases by name
    • Assume that the method names are relatively distinct enough to reduce the search space -> turned out redundant.
  • Reuse Cached ancestor traversal to avoid repeated computations via get_method_stack
  • Add fast path for creating resolved alias pins without individual lookups

Results 🚀

Before

Vernier Profile

Screenshots

First request after LSP boot

  • Total Go-to-definition completion time (~47s)
image
  • Solargraph::Library#definitions_at time (~4.3s)
image

[!NOTE]
As we can see, most of the time is spent on cataloging initially, which makes sense.


First request after opening a new file

  • Total Go-to-definition completion time (~9.6s)
image
  • Solargraph::Library#definitions_at time (~7.9s)
image

After

Vernier Profile

Screenshots

First request after LSP boot

  • Total Go-to-definition completion time (~13.8s)
image
  • Solargraph::Library#definitions_at time (0.92s)
image

[!NOTE]
As we can see, most of the time is spent on cataloging initially, which makes sense.


First request after opening a new file

  • Total Go-to-definition completion time (4.6s)
image
  • Solargraph::Library#definitions_at time (0.6s)
image

Summary

Performance improvements (measured on a large Ruby project with ~7,100 files):

  • First request after LSP boot: ⏱️ 47s → 13.8s (~3.6x faster)

  • First request after opening a new file: ⏱️ 9.6s → 4.6s (~2x faster)

  • Solargraph::Library#definitions_at hot path: ⏱️ 4.3s → 0.9s (~4.6x faster)

Cached responses seem not to be impacted by this change, and they remain fast as before.

Further potential Improvements

Example completion after file open:

image

From the samples above (with the new implementation), cataloging accounts for roughly 75-85% of the total time in cold completion responses. There may be room for improvement here - for example, by making cataloging run asynchronously. I recall some recent changes in this area, so the implications aren’t entirely clear. That said, my hunch is that for code completion specifically, developer experience often benefits more from speed than from perfect accuracy (just my personal opinion).

Vernier quick how-tos

Assuming that you've already installed the gem locally, to run the solargraph with vernier use:

vernier run -- solargraph stdio

Use https://vernier.prof/ to upload the profiles above.

If Vernier is a new tool for you, this video stream from Aaron is highly recommended!

@lekemula lekemula force-pushed the improve-goto-defintion-performance branch 2 times, most recently from 413442f to 9782ac4 Compare August 21, 2025 20:22
@cursor = cursor
block_pin = block
block_pin.rebind(api_map) if block_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(block_pin.receiver).contain?(cursor.range.start)
block_pin.rebind(api_map) if block_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(block_pin.receiver)&.contain?(cursor.range.start)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was accidentally included from my other branch 🙈, I'll remove it.

@lekemula lekemula force-pushed the improve-goto-defintion-performance branch from 9782ac4 to 18eb225 Compare August 21, 2025 20:47
@lekemula lekemula marked this pull request as ready for review August 21, 2025 20:57
@lekemula
Copy link
Contributor Author

lekemula commented Aug 21, 2025

I'm not sure I know what I need to do for type-checking lint:
https://github.com/castwide/solargraph/actions/runs/17138672729/job/48620888903?pr=1035

Could you please instruct?

- Add indexed lookups for methods and aliases by name
- Cache ancestor traversal to avoid repeated computations
- Separate regular pins from aliases for more efficient processing
- Replace linear search with direct indexed method lookup
- Add fast path for creating resolved alias pins without individual lookups

Generated with Claude Code
@lekemula lekemula force-pushed the improve-goto-defintion-performance branch from 16722e8 to 4f44722 Compare August 21, 2025 21:01
@apiology
Copy link
Contributor

I'd suggest creating a spec demonstrating creating an alias in a subclass to a method defined in the superclass - that'd show that if you can't find the method the easy way, you fall back to the old way

@apiology
Copy link
Contributor

/home/runner/work/solargraph/solargraph/lib/solargraph/api_map/store.rb:55 - Not enough arguments to Kernel#select

Probably another good spec to add - these select methods are on arrays, which implement Enumerable. Enumerable#select is an alias for Enumerable#find_all, and I'm guessing the logic to find that alias and use it isn't working right with this change.

@lekemula
Copy link
Contributor Author

lekemula commented Aug 22, 2025

Hi, thanks for the great hints @apiology! It was not immediately evident to me where that might be coming from. I think I know where the culprit might be.

I'd suggest creating a spec demonstrating creating an alias in a subclass to a method defined in the superclass - that'd show that if you can't find the method the easy way, you fall back to the old way

Probably I should have mentioned, but the reason why there were no specs added is that it seemed like we have sufficient coverage in api_map_spec.rb.

This should cover your above case, right?

it 'detects method aliases with origins in other sources' do
source1 = Solargraph::SourceMap.load_string(%(
class Sup
# @return [String]
def foo; end
end
), 'source1.rb')
source2 = Solargraph::SourceMap.load_string(%(
class Sub < Sup
alias bar foo
end
), 'source2.rb')
@api_map.catalog Solargraph::Bench.new(source_maps: [source1, source2])
pin = @api_map.get_path_pins('Sub#bar').first
expect(pin).not_to be_nil
expect(pin.return_type.tag).to eq('String')
end

That said, we need some more module inclusion/extension cases, which I think also relate to the typechecking failures.

The new method is meant to look up the aliases in the ancestor's tree in the same way as the old one, but I think the ordering in which we do the lookup is not quite right atm. Hence it uses the Kernel.select instead of Enumerable.select

@lekemula lekemula force-pushed the improve-goto-defintion-performance branch from 363cb8a to ab51b0b Compare August 23, 2025 19:57
@lekemula
Copy link
Contributor Author

lekemula commented Aug 23, 2025

Alright, this turned out to be a very interesting case.

The reason why the typechecking was failing for Enumerable#select is because the new implementation was changing the ordering of get_method_stack:

From: /Users/lekemula/Projects/solargraph/lib/solargraph/source/chain/call.rb:62 Solargraph::Source::Chain::Call#resolve:

    50: def resolve api_map, name_pin, locals
    51:   return super_pins(api_map, name_pin) if word == 'super'
    52:   return yield_pins(api_map, name_pin) if word == 'yield'
    53:   found = if head?
    54:     api_map.visible_pins(locals, word, name_pin, location)
    55:   else
    56:     []
    57:   end
    58:   return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
    59:   pins = name_pin.binder.each_unique_type.flat_map do |context|
    60:     ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
    61:     stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
 => 62:     [stack.first].compact
    63:   end
    64:   return [] if pins.empty?
    65:   inferred_pins(pins, api_map, name_pin, locals)
    66: end

[10] pry(#<Solargraph::Source::Chain::Call>)> stack.first
=> #<Solargraph::Pin::Method `name="select" return_type=Kernel#select def select: (read ::Array[::IO], ?write ::Array[::IO], ?error ::Array[::IO], ?timeout ::Time::_Timeout) -> ::Array[::String], context=::Kernel, closure=[name="Kernel" return_type=Kernel module ::Kernel, context=::Class<>, closure=[(top-level)], binder=::Module<Kernel>], binder=::Kernel` at #<Solargraph::Location /Users/lekemula/.rvm/gems/ruby-3.2.2/gems/rbs-3.9.4/core/kernel.rbs, #<Solargraph::Range #<Solargraph::Position 1712, 2> to #<Solargraph::Position 1712, 122>>>) via :rbs>
[11] pry(#<Solargraph::Source::Chain::Call>)> stack
=> [#<Solargraph::Pin::Method `name="select" return_type=Kernel#select def select: (read ::Array[::IO], ?write ::Array[::IO], ?error ::Array[::IO], ?timeout ::Time::_Timeout) -> ::Array[::String], context=::Kernel, closure=[name="Kernel" return_type=Kernel module ::Kernel, context=::Class<>, closure=[(top-level)], binder=::Module<Kernel>], binder=::Kernel` at #<Solargraph::Location /Users/lekemula/.rvm/gems/ruby-3.2.2/gems/rbs-3.9.4/core/kernel.rbs, #<Solargraph::Range #<Solargraph::Position 1712, 2> to #<Solargraph::Position 1712, 122>>>) via :rbs>,
 #<Solargraph::Pin::Method `Enumerable#select
def select: () { (arg_0 Solargraph::Pin::Base) -> ::BasicObject } -> ::Array[Solargraph::Pin::Base]
          | select: () -> ::Enumerator[Solargraph::Pin::Base, ::Array[Solargraph::Pin::Base]]
` at #<Solargraph::Location /Users/lekemula/.rvm/gems/ruby-3.2.2/gems/rbs-3.9.4/core/enumerable.rbs, #<Solargraph::Range #<Solargraph::Position 543, 2> to #<Solargraph::Position 544, 55>>>) via :resolve_method_alias>]
[12] pry(#<Solargraph::Source::Chain::Call>)> stack.count
=> 2
[13] pry(#<Solargraph::Source::Chain::Call>)> stack.map(&:path)
=> ["Kernel#select", "Enumerable#select"]

On the master branch, this was working as expected:

=> ["Enumerable#select", "Kernel#select"]

Keeping the old implementation of def resolve_method_aliases and only changing the def resolve_method_alias seems to fix it. Apparently, I had let the @claude too much out of the leash!

41d99d4 (#1035)

PS. Glad that we're dogfooding typechecking to catch such edge cases! 🙌

@lekemula lekemula force-pushed the improve-goto-defintion-performance branch from ab51b0b to 63c22eb Compare August 23, 2025 20:06
`get_method_stack` returns the following order for `Enumerable#select`:

- master branch:

=> ["Enumerable#select", "Kernel#select"]

- current branch:

=> ["Kernel#select", "Enumerable#select"]
@lekemula lekemula force-pushed the improve-goto-defintion-performance branch 3 times, most recently from 5e4bee5 to 4b4a46c Compare August 23, 2025 21:21
loop through ancestors and rely on store.get_path_pins
@lekemula lekemula force-pushed the improve-goto-defintion-performance branch from 4b4a46c to 49fa704 Compare August 23, 2025 21:30
@castwide
Copy link
Owner

Nice work, thanks! Out of curiosity, I tested this branch against a project that had slow completions due to heavy use of dynamic yield receivers. Performance was noticeably improved there, too.

The linting error should go away with the merge. If it doesn't, I'll deal with the fallout.

@castwide castwide merged commit 5e5938a into castwide:master Aug 24, 2025
22 of 23 checks passed
@lekemula
Copy link
Contributor Author

lekemula commented Aug 24, 2025

@castwide, thanks for merging this already, and I'm happy to hear that you've also noticed the improvements.

I'm curious about your thoughts on further potential Improvements - ie, moving the Library#sync_catalog async? I think that would significantly improve the cold go-to definition, and bring completions in <1s, which I think would be the sweet spot.

We used to have it async before #876.

@castwide
Copy link
Owner

From what I've determined, there's nothing to be gained from making Library#sync_catalog asynchronous. Ruby threads are always executed in a single process, so it will never run concurrently at the OS level (e.g., POSIX). Any other function within the solargraph process that needs the newest maps will need to wait for the library to synchronize anyway. Ruby threads don't make it any faster. The main reason #sync_catalog exists is to ensure that clients have access to the most current versions of code maps at the moment they're requested.

apiology pushed a commit to apiology/solargraph that referenced this pull request Aug 27, 2025
* Improve performance of resolve_method_aliases method

- Add indexed lookups for methods and aliases by name
- Cache ancestor traversal to avoid repeated computations
- Separate regular pins from aliases for more efficient processing
- Replace linear search with direct indexed method lookup
- Add fast path for creating resolved alias pins without individual lookups

Generated with Claude Code

* Update .rubocop_todo.yml

* Fix typechecking - get_method_stack order

`get_method_stack` returns the following order for `Enumerable#select`:

- master branch:

=> ["Enumerable#select", "Kernel#select"]

- current branch:

=> ["Kernel#select", "Enumerable#select"]

* Avoid redundant indexing methods_by_name

loop through ancestors and rely on store.get_path_pins
castwide added a commit that referenced this pull request Dec 30, 2025
* Enable strict type checking in CI

* Add 'solargraph method_pin' command for debugging

```sh
$ SOLARGRAPH_ASSERTS=on bundle exec solargraph method_pin --rbs 'RuboCop::AST::ArrayNode#values'
def values: () -> Array
$ bundle exec solargraph help method_pin
Usage:
  solargraph method_pin [PATH]

Options:
  [--rbs], [--no-rbs], [--skip-rbs]           # Output the pin as RBS
                                              # Default: false
  [--typify], [--no-typify], [--skip-typify]  # Output the calculated return type of the pin from annotations
                                              # Default: false
  [--probe], [--no-probe], [--skip-probe]     # Output the calculated return type of the pin from annotations and inference
                                              # Default: false
  [--stack], [--no-stack], [--skip-stack]     # Show entire stack by including definitions in superclasses
                                              # Default: false

Describe a method pin
$
```

* RuboCop and Solargraph fixes

* Linting fix

* Add spec

* Fix spec

* Allow newer RBS gem versions, exclude incompatible ones (#995)

* Allow newer RBS gem versions

This allow users to upgrade to recent Tapioca versions.

Tapioca now requires newish versions of the spoom gem, which depends on 4.x
pre-releases of the rbs gem.

* Add RBS version to test matrix

* Add exclude rule

* Move to 3.6.1

* Look for external requires before cataloging bench (#1021)

* Look for external requires before cataloging bench

It seems like sync_catalog will go through the motions but not
actually load pins from gems here due to passing an empty requires
array to ApiMap.

I'm sure those requires get pulled in eventually, but we go through at
least one catalog cycle without it happening.

Found while trying to test a different issue but not being able to get
completions from a gem in a spec.

* Ensure backport is pre-cached

* Remove Library#folding_ranges (#904)

* Complain in strong type-checking if an @sg-ignore line is not needed (#1011)

* Complain in strong type-checking if an @sg-ignore line is not needed

* Fix return type

* Fix spec

* Linting/coverage fixes

* Coverage fix

* Document a log level env variable (#894)

* Document a log level env variable

* Fix logger reference

* Fix env var name

* Populate location information from RBS files (#768)

* Populate location information from RBS files

The 'rbs' gem maps the location of different definitions to the
relevant point in the RGS files themselves - this change provides the
ability to jump into the right place in those files to see the type
definition via the LSP.

* Prefer source location in language server

* Resolve merge issue

* Fix Path vs String type error

* Consolidate parameter handling into Pin::Callable (#844)

* Consolidate parameter handling into Pin::Closure

* Clarify clobbered variable names

* Fix bug in to_rbs, add spec, then fix new bug found after running spec

* Catch one more Signature.new to translate from strict typechecking

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Use Pin::Callable type in args_node.rb

* Select String#each_line overload with mandatory vs optional arg info

* Adjust local variable presence to start after assignment, not before (#864)

* Adjust local variable presence to start after assignment, not before

* Add regression test around assignment in return position

* Fix assignment visibility code, which relied on bad asgn semantics

* Resolve params from ref tags (#872)

* Resolve params from ref tags

* Resolve ref tags with namespaces

* Fix merge issue

* RuboCop fixes

* Add @sg-ignore

* Linting

* Linting fix

* Linting fix

---------

Co-authored-by: Fred Snyder <fsnyder@castwide.com>

* Fix hole in type checking evaluation (#1009)

* Fix hole in type checking evaluation

The call to `bar()` in `[ bar('string') ].compact` is not currently
type-checked due to a missed spot in `NodeMethods#call_nodes_from(node)`

* Avoid over-reporting call issues

* Fix annotation

* Add nocov markers around unreachable area

* Fix a coverage issue

* Cover more paths in type checking

* Fix a code coverage issue

* Drop blank line

* Ratchet Rubocop todo

* Fix missing coverage

* Improve typechecking error message (#1014)

If we know the target of an unresolved method call, include it in the
error message.

* Internal strict type-checking fixes (#1013)

* Internal strict type-checking fixes

* Add annotation

* Add annotation

* Add @sg-ignores for now

* Reproduce and fix a ||= (or-asgn) evaluation issue (#1017)

* Reproduce and fix a ||= (or-asgn) evaluation issue

* Fix linting issue

* Define closure for Pin::Symbol, for completeness (#1027)

This isn't used anywhere to my knowledge, but it makes sense to think
of symbols as being in the global namespace, helps guarantee that
closure is always available on a pin, and of course keeps the assert
happy ;)

* Fix 'all!' config to reporters (#1018)

* Fix 'all!' config to reporters

Solargraph found the type error here!

* Linting fixes

* Fix DocMap.all_rbs_collection_gems_in_memory return type (#1037)

* Fix RuboCop linting errors in regular expressions (#1038)

* Fix RuboCop linting errors in regular expressions

* Continue on rubocop_todo errors

* Move configuration

* Continue on undercover errors

* Resolve class aliases via Constant pins (#1029)

* Resolve class aliases via Constant pins

This also eliminates the need for Parser::NodeMethods as a searately
defined class.

* Resolve merge issues

* Resolve Solargraph strong complaint

* Add @sg-ignore

* Fix RuboCop issues

* Drop unused method

* Ratchet .rubocop_todo.yml

* Speed-up LSP completion response times (#1035)

* Improve performance of resolve_method_aliases method

- Add indexed lookups for methods and aliases by name
- Cache ancestor traversal to avoid repeated computations
- Separate regular pins from aliases for more efficient processing
- Replace linear search with direct indexed method lookup
- Add fast path for creating resolved alias pins without individual lookups

Generated with Claude Code

* Update .rubocop_todo.yml

* Fix typechecking - get_method_stack order

`get_method_stack` returns the following order for `Enumerable#select`:

- master branch:

=> ["Enumerable#select", "Kernel#select"]

- current branch:

=> ["Kernel#select", "Enumerable#select"]

* Avoid redundant indexing methods_by_name

loop through ancestors and rely on store.get_path_pins

* RuboCop todo update

* Try rbs collection update before specs

* RuboCop fixes

* Add @sg-ignores

* Fix typo

* Exclude problematic combinations on Ruby head

* Fix indentation

* method_pin -> pin, hide command

* Fix type

* Make 'self' types concrete while checking arguments

* strict -> strong

* Also change default in Rakefile

* RuboCop todo file stability

To avoid merge conflicts and contributors having to deal with
non-intuitive RuboCop todo changes:

* Lock down development versions of RuboCop and plugins so that
  unrelated PRs aren't affected by newly implemented RuboCop rules.
* Exclude rule entirely if more than 5 files violate it today, so that
  PRs are less likely to cause todo file changes unless they are
  specifically targeted at cleanup.
* Clarify guidance on RuboCop todo file in CI error message.
* Fix to hopefully ensure guidance always appears in CI error message.

* Fix merge issue

* Add spec

* Work around strong typechecking issue

* Pull in overcommit fix

* Add spec

* Add --references flag (superclass for now)

* Add another @sg-ignore

* Catch up with .rubocop_todo.yml

* Add another @sg-ignore

* Tolerate case statement in specs

* Drop broken 'namespaces' method

These unused methods call into ApiMap::Index#namespaces, which does
not exist.

* Rerun rubocop todo

* Rebuild rubocop todo file

* Force build

* Restore

* install -> update with rbs collection

* Try Ruby 3.2

* Update solargraph

* Re-add bundle install

* Drop MATRIX_SOLARGRAPH_VERSION

* Drop debugging changes

* Update expectations from master branch

* Update rubocop todo

* Fix merge failure

* [regression] Fix issue resolving mixins under same namespace

* Prevent recursion via caching mechanism

* Linting fix, ignore rubocop-yard issue pending yard PR merge

* [regression] Fix resolution in deep YARD namespace hierarchies

YARD-parsed namespaces weren't correctly setting their gates, leading
to unresolved types from methods.

* Linting

* Fix merge

* Resolve constants in references

Also replaces 'include' logic with call to ApiMap::Constants

Fixes #1099

* Linting

* Ratchet RuboCop

* Fix lack of parameters in include types

* Bug fixes

* Add actual type for Mutexes

* Allow more valid method pin paths

* RuboCop fix

* Linting

* Enable solargraph-rspec tests

* Fix rspec gems specs

* Closure merging fixes

1) Prefer closures with more gates, to maximize compatibility
2) Look at basename of location, to make choice consistent

* Drop incidental requirement

* [regression] Fix resolution of a nested type case

Found in the Solargraph::Pin::DelegatedMethod class in strong
typechecking in apiology#12

* Fix example name

* Add another unmerged-Yard-PR issue

* Fix merge issue

* Ratchet RuboCop

* Drop unneeded @sg-ignores

* Drop unneeded @sg-ignore

* Drop another @sg-ignore

* Annotation fixes for strong typechecking

* Add @sg-ignores for issues covered by future PRs

* Add @sg-ignores for issues covered by future PRs

* Reproduce solargraph-rspec rspec failure

* Trigger build

* Fix new bundler issue

* Debug

* Turn off warning diagnostics in CLI

* Debug

* Fix pin merging bug

* Add @sg-ignore

* Add @sg-ignore

* Pull in solargraph-rspec fixes from another branch

* Drop @sg-ignores

* Add @sg-ignore

* Drop @sg-ignore

* Use consistent ruby versions for typechecking

* Avoid ignoring valid pins in typechecking

An overly-conservative check in type_checker.rb was suppressing
later warnings on method parameters with no default values

* Fix newly found type issue

* Annotations needed after #1130

* Annotations needed after #1130

---------

Co-authored-by: Fred Snyder <fsnyder@castwide.com>
Co-authored-by: Lekë Mula <l.mula@finlink.de>
castwide added a commit that referenced this pull request Jan 1, 2026
…1126)

* Add 'solargraph method_pin' command for debugging

```sh
$ SOLARGRAPH_ASSERTS=on bundle exec solargraph method_pin --rbs 'RuboCop::AST::ArrayNode#values'
def values: () -> Array
$ bundle exec solargraph help method_pin
Usage:
  solargraph method_pin [PATH]

Options:
  [--rbs], [--no-rbs], [--skip-rbs]           # Output the pin as RBS
                                              # Default: false
  [--typify], [--no-typify], [--skip-typify]  # Output the calculated return type of the pin from annotations
                                              # Default: false
  [--probe], [--no-probe], [--skip-probe]     # Output the calculated return type of the pin from annotations and inference
                                              # Default: false
  [--stack], [--no-stack], [--skip-stack]     # Show entire stack by including definitions in superclasses
                                              # Default: false

Describe a method pin
$
```

* RuboCop and Solargraph fixes

* Linting fix

* Add spec

* Fix spec

* Allow newer RBS gem versions, exclude incompatible ones (#995)

* Allow newer RBS gem versions

This allow users to upgrade to recent Tapioca versions.

Tapioca now requires newish versions of the spoom gem, which depends on 4.x
pre-releases of the rbs gem.

* Add RBS version to test matrix

* Add exclude rule

* Move to 3.6.1

* Look for external requires before cataloging bench (#1021)

* Look for external requires before cataloging bench

It seems like sync_catalog will go through the motions but not
actually load pins from gems here due to passing an empty requires
array to ApiMap.

I'm sure those requires get pulled in eventually, but we go through at
least one catalog cycle without it happening.

Found while trying to test a different issue but not being able to get
completions from a gem in a spec.

* Ensure backport is pre-cached

* Remove Library#folding_ranges (#904)

* Complain in strong type-checking if an @sg-ignore line is not needed (#1011)

* Complain in strong type-checking if an @sg-ignore line is not needed

* Fix return type

* Fix spec

* Linting/coverage fixes

* Coverage fix

* Document a log level env variable (#894)

* Document a log level env variable

* Fix logger reference

* Fix env var name

* Populate location information from RBS files (#768)

* Populate location information from RBS files

The 'rbs' gem maps the location of different definitions to the
relevant point in the RGS files themselves - this change provides the
ability to jump into the right place in those files to see the type
definition via the LSP.

* Prefer source location in language server

* Resolve merge issue

* Fix Path vs String type error

* Consolidate parameter handling into Pin::Callable (#844)

* Consolidate parameter handling into Pin::Closure

* Clarify clobbered variable names

* Fix bug in to_rbs, add spec, then fix new bug found after running spec

* Catch one more Signature.new to translate from strict typechecking

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Introduce Pin::Callable

* Use Pin::Callable type in args_node.rb

* Select String#each_line overload with mandatory vs optional arg info

* Adjust local variable presence to start after assignment, not before (#864)

* Adjust local variable presence to start after assignment, not before

* Add regression test around assignment in return position

* Fix assignment visibility code, which relied on bad asgn semantics

* Resolve params from ref tags (#872)

* Resolve params from ref tags

* Resolve ref tags with namespaces

* Fix merge issue

* RuboCop fixes

* Add @sg-ignore

* Linting

* Linting fix

* Linting fix

---------

Co-authored-by: Fred Snyder <fsnyder@castwide.com>

* Fix hole in type checking evaluation (#1009)

* Fix hole in type checking evaluation

The call to `bar()` in `[ bar('string') ].compact` is not currently
type-checked due to a missed spot in `NodeMethods#call_nodes_from(node)`

* Avoid over-reporting call issues

* Fix annotation

* Add nocov markers around unreachable area

* Fix a coverage issue

* Cover more paths in type checking

* Fix a code coverage issue

* Drop blank line

* Ratchet Rubocop todo

* Fix missing coverage

* Improve typechecking error message (#1014)

If we know the target of an unresolved method call, include it in the
error message.

* Internal strict type-checking fixes (#1013)

* Internal strict type-checking fixes

* Add annotation

* Add annotation

* Add @sg-ignores for now

* Reproduce and fix a ||= (or-asgn) evaluation issue (#1017)

* Reproduce and fix a ||= (or-asgn) evaluation issue

* Fix linting issue

* Define closure for Pin::Symbol, for completeness (#1027)

This isn't used anywhere to my knowledge, but it makes sense to think
of symbols as being in the global namespace, helps guarantee that
closure is always available on a pin, and of course keeps the assert
happy ;)

* Fix 'all!' config to reporters (#1018)

* Fix 'all!' config to reporters

Solargraph found the type error here!

* Linting fixes

* Fix DocMap.all_rbs_collection_gems_in_memory return type (#1037)

* Fix RuboCop linting errors in regular expressions (#1038)

* Fix RuboCop linting errors in regular expressions

* Continue on rubocop_todo errors

* Move configuration

* Continue on undercover errors

* Resolve class aliases via Constant pins (#1029)

* Resolve class aliases via Constant pins

This also eliminates the need for Parser::NodeMethods as a searately
defined class.

* Resolve merge issues

* Resolve Solargraph strong complaint

* Add @sg-ignore

* Fix RuboCop issues

* Drop unused method

* Ratchet .rubocop_todo.yml

* Speed-up LSP completion response times (#1035)

* Improve performance of resolve_method_aliases method

- Add indexed lookups for methods and aliases by name
- Cache ancestor traversal to avoid repeated computations
- Separate regular pins from aliases for more efficient processing
- Replace linear search with direct indexed method lookup
- Add fast path for creating resolved alias pins without individual lookups

Generated with Claude Code

* Update .rubocop_todo.yml

* Fix typechecking - get_method_stack order

`get_method_stack` returns the following order for `Enumerable#select`:

- master branch:

=> ["Enumerable#select", "Kernel#select"]

- current branch:

=> ["Kernel#select", "Enumerable#select"]

* Avoid redundant indexing methods_by_name

loop through ancestors and rely on store.get_path_pins

* RuboCop todo update

* Try rbs collection update before specs

* RuboCop fixes

* Add @sg-ignores

* Fix typo

* Exclude problematic combinations on Ruby head

* Fix indentation

* method_pin -> pin, hide command

* Fix type

* RuboCop todo file stability

To avoid merge conflicts and contributors having to deal with
non-intuitive RuboCop todo changes:

* Lock down development versions of RuboCop and plugins so that
  unrelated PRs aren't affected by newly implemented RuboCop rules.
* Exclude rule entirely if more than 5 files violate it today, so that
  PRs are less likely to cause todo file changes unless they are
  specifically targeted at cleanup.
* Clarify guidance on RuboCop todo file in CI error message.
* Fix to hopefully ensure guidance always appears in CI error message.

* Fix merge issue

* Add --references flag (superclass for now)

* Add another @sg-ignore

* Catch up with .rubocop_todo.yml

* Add another @sg-ignore

* Tolerate case statement in specs

* Rerun rubocop todo

* Force build

* Restore

* install -> update with rbs collection

* Try Ruby 3.2

* Update solargraph

* Re-add bundle install

* Drop MATRIX_SOLARGRAPH_VERSION

* Drop debugging changes

* Update expectations from master branch

* Update rubocop todo

* Fix merge failure

* Allow more valid method pin paths

* RuboCop fix

* Linting

* Reproduce solargraph-rspec rspec failure

* Trigger build

* Fix new bundler issue

* Debug

* Turn off warning diagnostics in CLI

* Debug

* Fix pin merging bug

* Add @sg-ignore

* Allow levels to be changed for typechecking rules in .solargraph.yml

Suggested updates for https://solargraph.org/guides/configuration:

1) Change block in Defaults section to:

```
include:
- "**/*.rb"
exclude:
- spec/**/*
- test/**/*
- vendor/**/*
- ".bundle/**/*"
require: []
domains: []
reporters:
- rubocop
- require_not_found
formatter:
  rubocop:
    cops: safe
    except: []
    only: []
    extra_args: []
type_checker:
  rules: {}
max_files: 5000
```

2) Add section 'formatter' (hadn't been added)

Specify configuration for code formatters used in the LSP.  Currently
supports 'rubocop' as the subsection, with the following keys:

* `cops`: Valid values: 'all', 'safe'
* `except`: List of cops to pass to the --except argument in the RuboCop
  CLI
* `only`: List of cops to pass to the --only argument in the RuboCop
  CLI
* `extra_args`: Additional arguments to pass to the RuboCop CLI

3) Add section 'type_checker.rules'

Override which rules are applied at a given typechecking level.
Example:

```
type_checker:
  rules:
    validate_calls: typed # make 'typed' level more strict without
                          # bringing in other rules
```

For the current list of typechecking rules, see
[rules.rb](https://github.com/castwide/solargraph/blob/master/lib/solargraph/type_checker/rules.rb)
in the Solargraph source.

* Fix merge

* Fix merge

---------

Co-authored-by: Fred Snyder <fsnyder@castwide.com>
Co-authored-by: Lekë Mula <l.mula@finlink.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants