Skip to content

Commit 83a79fe

Browse files
Close #34:
- Record components now are correctly remapped Fix RuntimeParameterAnnotationFixer error on J16+ Fix logic issues: should download mc jar when version and side are both provided
1 parent 0995672 commit 83a79fe

File tree

5 files changed

+72
-20
lines changed

5 files changed

+72
-20
lines changed

src/main/java/cn/maxpixel/mcdecompiler/MinecraftDecompiler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,13 @@ private ClassifiedDeobfuscator buildDeobfuscator() {
306306
return new ClassifiedDeobfuscator(new ClassifiedMappingReader<NamespacedMapping>(mtc.getProcessor(), inputMappings()),
307307
targetNamespace());
308308
} else return new ClassifiedDeobfuscator(new ClassifiedMappingReader<PairedMapping>(mtc.getProcessor(), inputMappings()));
309-
} else throw new UnsupportedOperationException("Unsupported yet");//TODO
309+
} else throw new UnsupportedOperationException("Unsupported yet");
310310
}
311311
return new ClassifiedDeobfuscator(version(), type());
312312
}
313313

314314
private boolean shouldDownloadJar() {
315-
return version() != null || type() != null;
315+
return version() != null && type() != null;
316316
}
317317

318318
@Override

src/main/java/cn/maxpixel/mcdecompiler/MinecraftDecompilerCommandLine.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public static void main(String[] args) throws Throwable {
5252
"deobfuscate/decompile. Only works on Proguard mappings or when downloading libraries for the decompiler. ")
5353
.requiredIf(sideTypeO).withRequiredArg();
5454
OptionSpecBuilder regenVarNameO = parser.acceptsAll(asList("r", "rvn", "regenVarName"), "Regenerate local variable " +
55-
"names using JAD style if the input mapping doesn't provide one");
55+
"names if the input mapping doesn't provide one");
5656
OptionSpecBuilder reverseO = parser.accepts("reverse", "Reverse the input mapping, then use the reversed mapping " +
5757
"to deobfuscate.").availableUnless(sideTypeO);
5858
OptionSpecBuilder dontIncludeOthersO = parser.accepts("dontIncludeOthers", "Drop the resource files of the output jar.");

src/main/java/cn/maxpixel/mcdecompiler/asm/ClassifiedMappingRemapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ private static boolean nameAndDescEquals(PairedMapping left, PairedMapping right
213213
return b;
214214
}
215215

216+
@Override
217+
public String mapRecordComponentName(String owner, String name, String descriptor) {
218+
return mapFieldName(owner, name, descriptor);
219+
}
220+
216221
@Override
217222
public String mapFieldName(String owner, String name, String descriptor) {
218223
return Optional.ofNullable(fieldByUnm.get(owner))

src/main/java/cn/maxpixel/mcdecompiler/asm/LocalVariableTableRenamer.java

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ public class LocalVariableTableRenamer extends ClassVisitor {
5454
private final String toNamespace;
5555
private final ClassMapping<NamespacedMapping> mapping;
5656

57+
private boolean isRecord;
58+
private ObjectArrayList<String> recordNames;
59+
private StringBuilder recordDesc;
60+
5761
public LocalVariableTableRenamer(ClassVisitor classVisitor, boolean rvn) {
5862
super(Info.ASM_VERSION, classVisitor);
5963
this.rvn = rvn;
@@ -75,13 +79,33 @@ public void visit(int version, int access, String name, String signature, String
7579
if(mapping != null && !mapping.mapping.getName(fromNamespace).equals(name))
7680
throw new IllegalArgumentException("Mapping mismatch");
7781
this.className = name;
82+
this.isRecord = (access & Opcodes.ACC_RECORD) != 0;
83+
if(isRecord) {
84+
recordDesc = new StringBuilder("<init>(");
85+
recordNames = new ObjectArrayList<>();
86+
}
7887
super.visit(version, access, name, signature, superName, interfaces);
7988
}
8089

90+
@Override
91+
public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) {
92+
recordDesc.append(descriptor);
93+
recordNames.add(name);
94+
return super.visitRecordComponent(name, descriptor, signature);
95+
}
96+
8197
@Override
8298
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
99+
if(isRecord && recordDesc.charAt(recordDesc.length() - 2) != ')') recordDesc.append(")V");
100+
boolean maySkip = false;
101+
if(isRecord) {
102+
String nd = name.concat(descriptor);
103+
if(nd.equals("equals(Ljava/lang/Object;)Z") || nd.equals("hashCode()I") || nd.equals("toString()Ljava/lang/String"))
104+
return super.visitMethod(access, name, descriptor, signature, exceptions);
105+
if(nd.contentEquals(recordDesc)) maySkip = true;
106+
}
83107
// Filter some methods because only lambda methods need to share renamer with the caller
84-
Renamer renamer = (access & (Opcodes.ACC_SYNTHETIC | Opcodes.ACC_PRIVATE)) == (Opcodes.ACC_SYNTHETIC | Opcodes.ACC_PRIVATE) ?
108+
Renamer renamer = (access & (Opcodes.ACC_SYNTHETIC | Opcodes.ACC_PRIVATE)) != 0 ?
85109
sharedRenamers.getOrDefault(String.join(".", className, name, descriptor), new Renamer()) : new Renamer();
86110
if((access & Opcodes.ACC_ABSTRACT) != 0 && recordStarted && !descriptor.startsWith("()")) {
87111
StringJoiner joiner = new StringJoiner(" ").add(className).add(name).add(descriptor);
@@ -106,9 +130,19 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str
106130
}).toArray(NamespacedMapping[]::new);
107131
if(m.length > 1) throw new IllegalArgumentException("Method duplicated");
108132
return m.length == 1 && m[0].hasComponent(LocalVariableTable.Namespaced.class) ? Optional.of(m[0]) : Optional.empty();
109-
})
110-
.map(LocalVariableTable.Namespaced.class::cast);
133+
}).map(m -> m.getComponent(LocalVariableTable.Namespaced.class));
134+
final boolean finalMaySkip = maySkip;
111135
return new MethodVisitor(api, super.visitMethod(access, name, descriptor, signature, exceptions)) {
136+
private boolean skip;
137+
private int i;
138+
@Override
139+
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
140+
if(finalMaySkip && !skip && opcode == Opcodes.INVOKESPECIAL && owner.equals("java/lang/Record") &&
141+
name.equals("<init>") && descriptor.equals("()V"))
142+
skip = true;
143+
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
144+
}
145+
112146
@Override
113147
public void visitInvokeDynamicInsn(String n, String desc, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
114148
if("java/lang/invoke/LambdaMetafactory".equals(bootstrapMethodHandle.getOwner())) {
@@ -124,9 +158,11 @@ public void visitInvokeDynamicInsn(String n, String desc, Handle bootstrapMethod
124158

125159
@Override
126160
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
127-
if(index == 0 && (access & Opcodes.ACC_STATIC) == 0) {
128-
super.visitLocalVariable("this", descriptor, signature, start, end, index);
129-
} else {
161+
if(index != 0 || (access & Opcodes.ACC_STATIC) != 0) {
162+
if(skip && i < recordNames.size()) {
163+
super.visitLocalVariable(recordNames.get(i++), descriptor, signature, start, end, index);
164+
return;
165+
}
130166
if(lvt.isPresent()) {
131167
String s = lvt.get().getLocalVariableName(index, toNamespace);
132168
if(s != null && !s.isBlank() && !placeholderMatcher.reset(s).matches()) {
@@ -138,8 +174,8 @@ public void visitLocalVariable(String name, String descriptor, String signature,
138174
super.visitLocalVariable(renamer.getVarName(Type.getType(descriptor)), descriptor, signature, start, end, index);
139175
return;
140176
}
141-
super.visitLocalVariable(name, descriptor, signature, start, end, index);
142177
}
178+
super.visitLocalVariable(name, descriptor, signature, start, end, index);
143179
}
144180
};
145181
}
@@ -168,12 +204,12 @@ public static void endRecord(Path writeTo) throws IOException {
168204
public static class Renamer {
169205
private static class Holder {
170206
public final int id;
171-
public final boolean skip_zero;
207+
public final boolean skipZero;
172208
public final ObjectArrayList<String> names = new ObjectArrayList<>();
173209

174-
public Holder(int id, boolean skip_zero, String... names) {
210+
public Holder(int id, boolean skipZero, String... names) {
175211
this.id = id;
176-
this.skip_zero = skip_zero;
212+
this.skipZero = skipZero;
177213
this.names.addElements(0, names);
178214
}
179215
}
@@ -219,7 +255,7 @@ public String getVarName(Type type) {
219255
varBaseName = holder.names.get(0);
220256
int count = vars.getOrDefault(varBaseName, holder.id);
221257
vars.put(varBaseName, count + 1);
222-
return varBaseName + (count == 0 && holder.skip_zero ? "" : count);
258+
return varBaseName + (count == 0 && holder.skipZero ? "" : count);
223259
} else {
224260
ids.computeIfAbsent(holder, (ToIntFunction<? super Holder>) h -> h.id);
225261
for(;;) {
@@ -228,7 +264,7 @@ public String getVarName(Type type) {
228264
if(!vars.containsKey(varBaseName)) {
229265
int j = ids.getInt(holder);
230266
vars.put(varBaseName, j);
231-
return varBaseName + (j == 0 && holder.skip_zero ? "" : j);
267+
return varBaseName + (j == 0 && holder.skipZero ? "" : j);
232268
}
233269
}
234270
ids.addTo(holder, 1);

src/main/java/cn/maxpixel/mcdecompiler/asm/RuntimeParameterAnnotationFixer.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import org.apache.logging.log4j.Logger;
2424
import org.objectweb.asm.*;
2525

26-
// Visitor version of https://github.com/ModCoderPack/MCInjector/blob/master/src/main/java/de/oceanlabs/mcp/mcinjector/adaptors/ParameterAnnotationFixer.java
26+
// Visitor version of https://github.com/MinecraftForge/ForgeAutoRenamingTool/blob/master/src/main/java/net/minecraftforge/fart/internal/ParameterAnnotationFixer.java
2727
public class RuntimeParameterAnnotationFixer extends ClassVisitor {
2828
private static final Logger LOGGER = LogManager.getLogger("Runtime(In)visibleParameterAnnotations Attribute Fixer");
2929
private int removeCount;// = isEnum ? 2 : 1
@@ -47,10 +47,21 @@ public void visit(int version, int access, String name, String signature, String
4747

4848
@Override
4949
public void visitInnerClass(String name, String outerName, String innerName, int access) {
50-
if(toProcess == null && name.equals(className) && (access & (Opcodes.ACC_STATIC | Opcodes.ACC_INTERFACE)) == 0 && innerName != null) {
51-
this.removeCount = 1;
52-
this.toProcess = '(' + Type.getObjectType(outerName).getDescriptor();
53-
LOGGER.debug("Fixing class {} because it is an inner class of {}", name, outerName);
50+
if(toProcess == null && name.equals(className) && (access & (Opcodes.ACC_STATIC | Opcodes.ACC_INTERFACE)) == 0 &&
51+
innerName != null) {
52+
if(outerName == null) {
53+
int i = className.lastIndexOf('$');
54+
if(i != -1) {
55+
this.removeCount = 1;
56+
String s = className.substring(0, i);
57+
this.toProcess = '(' + Type.getObjectType(s).getDescriptor();
58+
LOGGER.debug("Fixing class {} as its name appears to be an inner class of {}", name, s);
59+
}
60+
} else {
61+
this.removeCount = 1;
62+
this.toProcess = '(' + Type.getObjectType(outerName).getDescriptor();
63+
LOGGER.debug("Fixing class {} as its an inner class of {}", name, outerName);
64+
}
5465
}
5566
super.visitInnerClass(name, outerName, innerName, access);
5667
}

0 commit comments

Comments
 (0)