Skip to content

Commit

Permalink
Start trying to fix inner remapping
Browse files Browse the repository at this point in the history
  • Loading branch information
modmuss50 committed Feb 26, 2025
1 parent d611960 commit 565510c
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 39 deletions.
30 changes: 2 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ Mercury
=======

Mercury is a source code transformation library for Java codebases, with an
included remapper - built on [Eclipse's JDT] and [Lorenz]. Mercury is licensed
included remapper - built on [Eclipse's JDT] and [tiny-remapper]. Mercury is licensed
under the [Eclipse Public License 2.0](LICENSE).

While Mercury is yet to see a proper release (we're working on it), it has
been successfully used by the following projects:
While Mercury is used by the following projects:

- **[The Fabric Project]** uses Mercury in their
[Gradle build tools](https://fabricmc.net/wiki/tutorial:migratemappings) to
Expand Down Expand Up @@ -36,30 +35,6 @@ mercury.getProcessors().add(MercuryRemapper.create(mappings));
mercury.rewrite(Paths.get("a"), Paths.get("b"));
```

### Rewrite access transformers

Mercury also has an optional dependency on [at], allowing access transformers
to be applied to source, and be updated to reflect changes in the structure of
the codebase. *See the following example to see how this could work*.

```java
final Mercury mercury = new Mercury();
mercury.getClassPath().add(Paths.get("example.jar"));
mercury.getProcessors().add(MercuryRemapper.create(mappings));

// Since we run after MercuryRemapper, the access transformer needs to be
// remapped - fortunately, at provides an optional dependency on Lorenz,
// and a utility to do just that!
final AccessTransformSet remappedTransforms =
AccessTransformSetMapper.remap(transforms, mappings);
// We can then use AccessTransformerRewriter with the remapped access
// transform set.
mercury.getProcessors()
.add(AccessTransformerRewriter.create(remappedTransforms));

mercury.rewrite(Paths.get("a"), Paths.get("b"));
```

## See Also

There is beginning to be tooling designed to work with Mercury, these may be
Expand All @@ -77,7 +52,6 @@ We have an IRC channel on [EsperNet], `#cadix`, which is available for all
and discuss Mercury and other Cadix projects.

[Eclipse's JDT]: https://www.eclipse.org/jdt/
[Lorenz]: https://github.com/CadixDev/Lorenz
[The Fabric Project]: https://fabricmc.net/
[The Sponge Project]: https://www.spongepowered.org/
[at]: https://github.com/CadixDev/at
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
group = net.fabricmc
name = Mercury
version = 0.4.2
version = 0.5.0
description = A source transformation and -remapping framework for Java.
url = https://github.com/FabricMC/Mercury
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public String mapMethodArg(String methodOwner, String methodName, String methodD
return remapper().mapMethodArg(methodOwner.replace(".", "/"), methodName, methodDesc, lvIndex, name);
}

// Returns the package of the class, e.g "com.example"
public String getDeobfuscatedPackage(TrClass trClass) {
String fullName = mapClass(trClass.getName());
if (fullName.indexOf('.') == -1) {
Expand All @@ -61,14 +62,16 @@ public String getDeobfuscatedPackage(TrClass trClass) {
return fullName.substring(0, fullName.lastIndexOf('.'));
}

// Returns the name of the class without the package or without the outer class
public String getSimpleDeobfuscatedName(TrClass trClass) {
String fullName = mapClass(trClass.getName());
return fullName.substring(fullName.lastIndexOf('.') + 1);
String name = mapClass(trClass.getName());
String fullName = name.substring(name.lastIndexOf('.') + 1);
return fullName.contains("$") ? fullName.substring(fullName.lastIndexOf('$') + 1) : fullName;
}

// TODO is this the same as mapClass?
public String getFullDeobfuscatedName(TrClass trClass) {
return mapClass(trClass.getName());
return mapClass(trClass.getName()).replace('/', '.');
}

public String getSimpleObfuscatedName(TrClass trClass) {
Expand Down
14 changes: 9 additions & 5 deletions src/main/java/org/cadixdev/mercury/remapper/RemapperVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ private void remapType(SimpleName node, ITypeBinding binding) {
return;
}

String qualifiedName = (mapping != null ? remapper.getFullDeobfuscatedName(mapping).replace('/', '.') : binding.getBinaryName()).replace('$', '.');
String qualifiedName = (mapping != null ? remapper.getFullDeobfuscatedName(mapping) : binding.getBinaryName()).replace('$', '.');

if(!node.isVar()) {
String newName = this.importRewrite.addImport(qualifiedName, this.importStack.peek());
Expand Down Expand Up @@ -152,10 +152,14 @@ private void remapInnerType(QualifiedName qualifiedName, ITypeBinding outerClass
throw new IllegalStateException("No binary name for " + outerClass.getQualifiedName());
}

// TODO is this right?
// Given the name of the outer class and inner class (Such as "Inner.Other", remap just the innner class name
String fullInnerName = binaryName + '$' + qualifiedName.getName().getIdentifier();
TrClass outer = remapper.getClass(binaryName);
TrClass inner = remapper.getClass(fullInnerName);
String deobfInnerName = remapper.getSimpleDeobfuscatedName(inner);

SimpleName node = qualifiedName.getName();
updateIdentifier(node, remapper.mapClass(fullInnerName));
updateIdentifier(node, deobfInnerName);
}

@Override
Expand Down Expand Up @@ -322,7 +326,7 @@ public boolean visit(ImportDeclaration node) {
}

TrClass mapping = remapper.getClass(name);
if (mapping != null && !name.equals(remapper.getFullDeobfuscatedName(mapping).replace('/', '.'))) {
if (mapping != null && !name.equals(remapper.getFullDeobfuscatedName(mapping))) {
this.importRewrite.removeImport(typeBinding.getQualifiedName());
} else if (this.simpleDeobfuscatedName != null && this.simpleDeobfuscatedName.equals(typeBinding.getName())) {
this.importRewrite.removeImport(typeBinding.getQualifiedName());
Expand Down Expand Up @@ -373,7 +377,7 @@ private void collectImportContext(ImportContext context, ITypeBinding binding) {
String qualifiedName;
if (mapping != null) {
simpleName = remapper.getSimpleDeobfuscatedName(mapping);
qualifiedName = remapper.getFullDeobfuscatedName(mapping).replace('/', '.').replace('$', '.');
qualifiedName = remapper.getFullDeobfuscatedName(mapping).replace('$', '.');
} else {
simpleName = inner.getName();
qualifiedName = inner.getBinaryName().replace('$', '.');
Expand Down
8 changes: 6 additions & 2 deletions src/test/java/org/cadixdev/mercury/test/RemappingTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ class RemappingTests {
"net/example/ImportTestNew.java",
"net/example/newother/AnotherClass.java",
"net/example/newother/OtherClass.java",
"net/example/pkg/Util.java"
"net/example/pkg/Util.java",
// - Test 7
"com/example/InnerTest.java"
})
void remap(String file) throws Exception {
final Path tempDir = Files.createTempDirectory("mercury-test");
Expand Down Expand Up @@ -110,6 +112,8 @@ void remap(String file) throws Exception {
this.copy(in, "com/example/other/AnotherClass.java");
this.copy(in, "com/example/other/OtherClass.java");
this.copy(in, "com/example/pkg/Constants.java");
// - Test 7
this.copy(in, "com/example/InnerTest.java");

// Load our test mappings
MemoryMappingTree mappingTree = new MemoryMappingTree();
Expand Down Expand Up @@ -165,7 +169,7 @@ void verify(final Path dir, final String file) throws IOException {
final Path path = dir.resolve(file);

// First check the path exists
assertTrue(Files.exists(path), file + " doesn't exists!");
assertTrue(Files.exists(path), path + " doesn't exists!");

// Check the file matches the expected output
final String expected;
Expand Down
21 changes: 21 additions & 0 deletions src/test/resources/b/com/example/InnerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2018 Cadix Development (https://www.cadixdev.org)
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which accompanies this distribution,
* and is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/

package com.example;

public class InnerTest {
public static class InnerRenamed {
public static final InnerRenamed instance = new InnerRenamed();
}

public static InnerRenamed inner() {
return InnerRenamed.instance;
}
}
3 changes: 3 additions & 0 deletions src/test/resources/test.jam
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ CL com/example/pkg/Constants net/example/pkg/Util
CL com/example/ImportTest net/example/ImportTestNew
CL com/example/other/OtherClass net/example/newother/OtherClass
CL com/example/other/AnotherClass net/example/newother/AnotherClass

# Test 7. Rename inner class
CL com/example/InnerTest$Inner net/example/InnerTest$InnerRenamed
23 changes: 23 additions & 0 deletions src/testInput/java/com/example/InnerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2018 Cadix Development (https://www.cadixdev.org)
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which accompanies this distribution,
* and is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/

package com.example;

public class InnerTest {
public static class Inner {
public static class InnerInner {
public static final Inner instance = new Inner();
}
}

public static Inner inner() {
return Inner.InnerInner.instance;
}
}

0 comments on commit 565510c

Please # to comment.