Skip to content

Rename interface methods alongside their implementations and async state machines#273

Open
AlpinePastoralist wants to merge 1 commit into
sunnamed434:mainfrom
AlpinePastoralist:FullRenamer
Open

Rename interface methods alongside their implementations and async state machines#273
AlpinePastoralist wants to merge 1 commit into
sunnamed434:mainfrom
AlpinePastoralist:FullRenamer

Conversation

@AlpinePastoralist
Copy link
Copy Markdown

Rename interface methods together with their implementations and rename async state machines

The previous implementation skipped every method with IsVirtual=true, which meant the entire public surface of services and repositories (every implicit interface implementation in C# is virtual at IL level) kept its original name. The original method name also leaked through compiler-generated async state-machine types named "d__N".

This change:

  1. Adds a pre-pass that collects each interface method in the current obfuscation scope, reserves one random name per method, and applies the same name to every matching implementation that is also in scope. The contract between interface and implementation stays consistent.

  2. After renaming a method, looks for nested compiler-generated types whose name embeds the original method name ("d__N" or "b__N_M") and renames them too. This closes the most common stack-trace leak for async methods and closures.

  3. Refines the virtual-method skip in the standard rename loop:

    • IsVirtual && !IsNewSlot is kept as skip (true override; the name is bound to the base class method).
    • IsVirtual && IsNewSlot && IsFinal is added as skip (implicit implementation of an interface that lives outside the current module; renaming would break the contract and trigger TypeLoadException at load time).
  4. Replaces the in-line loops for method/type/field rename with iteration over pre-collected lists so the helpers can be called safely while the underlying collections are still in use.

The original behaviour is preserved for type and field renames.

…ions and rename async state machines

The previous implementation skipped every method with IsVirtual=true, which
meant the entire public surface of services and repositories (every implicit
interface implementation in C# is virtual at IL level) kept its original
name. The original method name also leaked through compiler-generated async
state-machine types named "<MethodName>d__N".

This change:

1. Adds a pre-pass that collects each interface method in the current
   obfuscation scope, reserves one random name per method, and applies the
   same name to every matching implementation that is also in scope. The
   contract between interface and implementation stays consistent.

2. After renaming a method, looks for nested compiler-generated types whose
   name embeds the original method name ("<originalName>d__N" or
   "<originalName>b__N_M") and renames them too. This closes the most
   common stack-trace leak for async methods and closures.

3. Refines the virtual-method skip in the standard rename loop:
   - IsVirtual && !IsNewSlot is kept as skip (true override; the name is
     bound to the base class method).
   - IsVirtual && IsNewSlot && IsFinal is added as skip (implicit
     implementation of an interface that lives outside the current module;
     renaming would break the contract and trigger TypeLoadException at
     load time).

4. Replaces the in-line loops for method/type/field rename with iteration
   over pre-collected lists so the helpers can be called safely while the
   underlying collections are still in use.

The original behaviour is preserved for type and field renames.
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