Index X = Class.new(Super) constant assignments as classes - #1306
Open
apiology wants to merge 1 commit into
Open
Index X = Class.new(Super) constant assignments as classes#1306apiology wants to merge 1 commit into
X = Class.new(Super) constant assignments as classes#1306apiology wants to merge 1 commit into
Conversation
Gems commonly build classes with an anonymous-class assignment instead of
a `class` keyword, e.g. Asana's error hierarchy:
module Vendor
Specific = Class.new(StandardError) do
# @return [Integer]
def retry_after
5
end
end
end
`ParserGem::NodeProcessors::CasgnNode` mapped that `casgn` to an untyped
`Pin::Constant`, and the methods in the block landed on the enclosing
namespace, so `Vendor::Specific#retry_after` did not resolve:
`Unresolved call to retry_after on Vendor::Specific` at level strong.
Adds `Convention::ClassDefinition`, following the existing
`Convention::StructDefinition` / `Convention::DataDefinition` pattern: a
`casgn` node processor that recognizes `Class.new(...)` (with or without
a block), pushes a `Pin::Namespace` named after the constant, pushes a
`Pin::Reference::Superclass` when the argument is a constant, and
processes the block body with that namespace as the closure.
The processor is registered for `:casgn` after the Struct and Data
processors -- which keep winning for `Struct.new` / `Data.define` -- and
before `CasgnNode`, which still handles every other constant assignment
because the new processor returns true on non-match.
Fixes castwide#1303
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MEDQFCJ2M7gaYkUQVpiQzn
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Aug 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1303.
Gems commonly build classes as
X = Class.new(Parent) do ... end— Asana's entire error hierarchy is one example. Solargraph indexed the result as an untyped constant, so no method on such a class resolved, and the methods in the block were attached to the enclosing namespace instead of the new class. There was no annotation that worked around it: a@!parsestub declaring the same name contributed nothing, and@!overrideon the constant crashed the typechecker (#1302).This adds a
Convention::ClassDefinitionfollowing the existingStructDefinition/DataDefinitionpattern: a:casgnnode processor that pushes aPin::Namespacefor the assigned constant plus aPin::Reference::Superclass, so block methods attach to the new class and the superclass is recorded. It registers after the Struct/Data processors and beforeParserGem::NodeProcessors::CasgnNode, since registration order is precedence and Struct/Data must keep winning.Negative controls verified in one file covering all four forms:
S = Struct.new(:bar)andD = Data.define(:baz)still resolve through their own conventions, a plainAlias = Otheris still an ordinaryPin::Constant, andC = Class.new(StandardError) do … endnow resolves its block methods. Full suite green locally: 1632 examples, 0 failures, 60 pending. RuboCop clean; strong typecheck on both new lib files reports 0 problems.Authored by Claude (Anthropic's Claude Code) on behalf of @apiology.