Skip to content

Renaming a class or enum leaves dangling references inside Optional/Handle/Result wrappers and interface function signatures #222

Closed

Description

@matt-edmondson

What's wrong

TryRenameClass and TryRenameEnum (Schema/Models/Schema.Rename.cs) find references through EnumerateMemberTypes() (L168-171) and ExpandType (L173-184). That walk has two gaps:

  • ExpandType recurses only into Array.ElementType. It never descends into WrapperType.ElementType (Schema/Models/Types/WrapperType.cs:19), which covers Optional<>, Handle<> and Result<>.
  • EnumerateMemberTypes walks only class members. It never visits interface function return types (SchemaFunction.ReturnType) or parameter types (SchemaParameter.Type).

Failure scenario

A schema has class Foo and:

  • a member typed Handle<Object(Foo)> or Optional<Object(Foo)>, and
  • an interface function returning Object(Foo) or taking a Foo parameter.

TryRenameClass(Foo, "Bar") returns true, but those references still say Foo. Validate() then reports dangling references in a schema the rename promised to keep consistent. Generated code refers to a type that no longer exists, and the editor's rename-with-cascade silently breaks the schema. Enum renames fail the same way for wrapped or function-signature enum references.

Schema.Test/SchemaRenameTests.cs covers only direct and Array references, which is why this was not caught.

Suggested fix

  • Make ExpandType recurse into WrapperType.ElementType, and into any other composite that holds an ElementType.
  • Include every interface's function ReturnType and each parameter's Type in the enumeration, expanded the same way.
  • If RepointArrayKeys uses the same walk, check it too.

Acceptance criteria

  • After renaming a class or enum, Validate() reports no dangling reference for a reference nested in Optional, Handle, Result, or Array<Optional<…>>.
  • The same holds for a reference in an interface function's return type or parameter type.
  • SchemaRenameTests has cases for each.

Activity

  1. matt-edmondson commented on Sep 29, 2026

    @matt-edmondson
    ContributorAuthor

    Triage

    • Category: Bug
    • Priority: Medium. A rename reports success but leaves the schema invalid, so generated code refers to a type that no longer exists. It only affects wrapped references and interface signatures, but the editor's rename-with-cascade hits it in normal use.
    • Area / suggested assignment: Schema.Rename.cs type walk (EnumerateMemberTypes, ExpandType), and RepointArrayKeys if it shares the walk
    • Duplicates: none found.
    • In progress: no. PR Bump ktsu.AppDataStorage and 27 others #221 is a dependency bump.

    Notes: Consider one shared "every type reference in the schema" enumerator, used by both rename and Validate(). Validate already finds these references, which is how the dangling ones show up. Two separate walks are how this gap appeared.


    Generated by Claude Code

  2. added 2 commits that reference this issue on Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions