Skip to content

Fix NameError raised by RubyIndexer's abstract method guard - #4197

Open
aryrabelo wants to merge 1 commit into
Shopify:mainfrom
aryrabelo:fix-ruby-indexer-abstract-method-error
Open

Fix NameError raised by RubyIndexer's abstract method guard#4197
aryrabelo wants to merge 1 commit into
Shopify:mainfrom
aryrabelo:fix-ruby-indexer-abstract-method-error

Conversation

@aryrabelo

Copy link
Copy Markdown

Motivation

RubyIndexer::Entry::Member#signatures is an abstract method that raises AbstractMethodInvokedError. That constant is not defined anywhere under RubyIndexer. It exists only as RubyLsp::AbstractMethodInvokedError in lib/ruby_lsp/utils.rb, and RubyIndexer is a sibling module of RubyLsp, not nested inside it. So when the guard fires, it raises NameError instead of the intended error:

NameError: uninitialized constant RubyIndexer::Entry::Member::AbstractMethodInvokedError

This is the only one of the 17 raise AbstractMethodInvokedError sites in the repository that lives outside lib/ruby_lsp/. The other 16 are inside module RubyLsp and resolve correctly.

On severity, so the diff is not read as more urgent than it is: this is not reachable from the code as it stands. Member is abstract, and both of its concrete subclasses implement signatures, Accessor with a method and Method with an attr_reader. The guard is latent. The value of fixing it is that it still works for the case it exists to catch, a future subclass that forgets to implement the method, and that rescue AbstractMethodInvokedError would not catch a NameError.

Implementation

AbstractMethodInvokedError is now defined inside RubyIndexer::Entry, so the bare constant resolves lexically from Entry::Member.

I deliberately did not point the raise at RubyLsp::AbstractMethodInvokedError. Today lib/ruby_indexer/lib/ has no code dependency on RubyLsp at all, the only two mentions being a rubocop:disable directive in enhancement.rb and a prose comment in index.rb, and referencing it would create the first one. RubyIndexer already declares its own error classes in exactly this shape: UnresolvableAliasError, NonExistingNamespaceError and IndexNotEmptyError all sit at the top of class Index in index.rb, scoped to the class that raises them.

Automated Tests

No test added. The repository has no test covering any of the 17 abstract method guards, so adding one here would introduce a pattern that does not exist yet, and it would need a throwaway Member subclass whose only purpose is to trigger the raise.

I did verify the change both ways rather than by inspection. A standalone minitest asserting that the guard raises the intended error fails against the current nesting, with NameError: uninitialized constant ..., and passes against the patched nesting. If you would rather have that in lib/ruby_indexer/test/, say so and I will add it.

Manual Tests

The guard is not reachable through the editor, so there is nothing to exercise in a VS Code instance. The failure mode reproduces directly:

module RubyLsp
  class AbstractMethodInvokedError < StandardError; end
end
module RubyIndexer
  class Entry
    class Member < Entry
      def signatures = raise AbstractMethodInvokedError
    end
  end
end

Class.new(RubyIndexer::Entry::Member).new.signatures
# NameError: uninitialized constant RubyIndexer::Entry::Member::AbstractMethodInvokedError

With this change the same snippet raises RubyIndexer::Entry::AbstractMethodInvokedError.

Spotted by itaruby(to be released), a Ruby type checker I'm working on.

@aryrabelo
aryrabelo requested a review from a team as a code owner August 26, 2026 09:08
@aryrabelo

Copy link
Copy Markdown
Author

CLA signed.

@aryrabelo

Copy link
Copy Markdown
Author

I have signed the CLA.

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.

1 participant