Skip to content

Repair inner class nesting when stripped by an obfuscator - #362

Open
RDIL wants to merge 1 commit into
QuiltMC:masterfrom
RDIL:reece/inner-classes
Open

Repair inner class nesting when stripped by an obfuscator#362
RDIL wants to merge 1 commit into
QuiltMC:masterfrom
RDIL:reece/inner-classes

Conversation

@RDIL

@RDIL RDIL commented Aug 24, 2026

Copy link
Copy Markdown

There's a lot going on here, so I'm going to try and break it down as simply as I can:

  • Enigma has two concepts of how nesting works which disagree with each other. (1) It grabbed it from the $ in a class name, but (2) decompilers get it from the InnerClasses attribute.
  • Some obfuscators (like the one used on Charles Proxy, not sure which it actually is) strip out this nesting attribute, which lead to phantom classes that Enigma could tell were nested, but the decompiler couldn't.
  • This meant you couldn't edit them! (Or even see them in the GUI's source tree)

So, how have I gone about fixing this? Glad you asked!

Class trees, class search, Gui.showReference, moveClassTree, javadoc/stat invalidation (and many more) are now all aware of this and can handle appropriately. Most importantly, we stop silently dropping $ classes.

A lovely new test has been added to prevent it from regressing (I hope)

There's a lot going on here, so I'm going to try and break it down as simply as I can:

- Enigma has two concepts of how nesting works which disagree with each other. (1) It grabbed it from the `$` in a class name, but (2) decompilers get it from the InnerClasses attribute.
- Some obfuscators (like the one used on Charles Proxy, not sure which it actually is) strip out this nesting attribute, which lead to phantom classes that Enigma could tell were nested, but the decompiler couldn't.
- This meant you couldn't edit them! (Or even see them in the GUI's source tree)

So, how have I gone about fixing this? Glad you asked!

Class trees, class search, `Gui.showReference`, `moveClassTree`, javadoc/stat invalidation (and many more) are now all aware of this and can handle appropriately. Most importantly, we stop silently dropping `$` classes.

A lovely new test has been added to prevent it from regressing (I hope)
}

for (ClassEntry classEntry : this.classRanges.keySet()) {
String[] parts = classEntry.getContextualName().split("\\$");

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

without this refactor, it tries to find an outer class with a named inner class that doesn't exist, and would throw.

this.currentIsKeyed = false;
this.classRanges.clear();
this.classDeclarations.clear();
this.classStack.clear();

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

existing bug!: this wasn't cleared between runs, which could lead to a different file's tokens occasionally being leaked onto an unrelated file, in very particular circumstances

Comment on lines -84 to -85
tokenCollector.set(new EnigmaTextTokenCollector(next));
return tokenCollector.get();

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

this didn't work because tokenCollector.get() would only ever resolve the current file, even if we're asking for a different file!

@supersaiyansubtlety
supersaiyansubtlety self-requested a review August 25, 2026 03:10
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