From 3e8f50c02706760c4d56eccd2169124a42f023d8 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Fri, 15 Mar 2024 19:29:49 +0100 Subject: [PATCH 1/9] Add initial JADX support --- build.gradle | 19 +- gradle/runtime.libs.versions.toml | 4 + .../loom/decompilers/jadx/JarEntryWriter.java | 46 ++++ .../decompilers/jadx/LoomJadxDecompiler.java | 198 ++++++++++++++++++ .../decompilers/DecompilerConfiguration.java | 19 +- .../test/integration/DecompileTest.groovy | 1 + 6 files changed, 283 insertions(+), 4 deletions(-) create mode 100644 src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java create mode 100644 src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java diff --git a/build.gradle b/build.gradle index 8c426029a..34ca305ab 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,8 @@ def brokenConfigurations = [ "commonDecompilerRuntimeClasspath", "fernflowerRuntimeClasspath", "cfrRuntimeClasspath", - "vineflowerRuntimeClasspath" + "vineflowerRuntimeClasspath", + "jadxRuntimeClasspath", ] configurations.configureEach { @@ -109,6 +110,11 @@ sourceSets { srcDir("src/decompilers/vineflower") } } + jadx { + java { + srcDir("src/decompilers/jadx") + } + } } dependencies { @@ -147,14 +153,24 @@ dependencies { vineflowerCompileOnly runtimeLibs.vineflower vineflowerCompileOnly libs.fabric.mapping.io + jadxCompileOnly dependencies.create(runtimeLibs.jadx.core.get()) { + exclude group: 'com.android.tools.build', module: 'aapt2-proto' + } + jadxCompileOnly dependencies.create(runtimeLibs.jadx.java.get()) { + exclude group: 'io.github.skylot', module: 'raung-disasm' + } + jadxCompileOnly libs.fabric.mapping.io + fernflowerApi sourceSets.commonDecompiler.output cfrApi sourceSets.commonDecompiler.output vineflowerApi sourceSets.commonDecompiler.output + jadxApi sourceSets.commonDecompiler.output implementation sourceSets.commonDecompiler.output implementation sourceSets.fernflower.output implementation sourceSets.cfr.output implementation sourceSets.vineflower.output + implementation sourceSets.jadx.output // source code remapping implementation libs.fabric.mercury @@ -198,6 +214,7 @@ jar { from sourceSets.cfr.output.classesDirs from sourceSets.fernflower.output.classesDirs from sourceSets.vineflower.output.classesDirs + from sourceSets.jadx.output.classesDirs } base { diff --git a/gradle/runtime.libs.versions.toml b/gradle/runtime.libs.versions.toml index cf2a01c7c..52d9c2103 100644 --- a/gradle/runtime.libs.versions.toml +++ b/gradle/runtime.libs.versions.toml @@ -3,6 +3,7 @@ fernflower = "2.0.0" cfr = "0.2.2" vineflower = "1.9.3" +jadx = "1.4.7" # Runtime depedencies mixin-compile-extensions = "0.6.0" @@ -16,6 +17,9 @@ native-support = "1.0.1" fernflower = { module = "net.fabricmc:fabric-fernflower", version.ref = "fernflower" } cfr = { module = "net.fabricmc:cfr", version.ref = "cfr" } vineflower = { module = "org.vineflower:vineflower", version.ref = "vineflower" } +jadx-core = { module = "io.github.skylot:jadx-core", version.ref = "jadx" } +jadx-java = { module = "io.github.skylot:jadx-java-input", version.ref = "jadx" } + # Runtime depedencies mixin-compile-extensions = { module = "net.fabricmc:fabric-mixin-compile-extensions", version.ref = "mixin-compile-extensions" } diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java new file mode 100644 index 000000000..f4bea6c8e --- /dev/null +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java @@ -0,0 +1,46 @@ +package net.fabricmc.loom.decompilers.jadx; + +import java.io.IOException; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; + +public class JarEntryWriter { + private final Set addedDirectories = new HashSet<>(); + private final JarOutputStream outputStream; + + JarEntryWriter(JarOutputStream outputStream) { + this.outputStream = outputStream; + } + + synchronized void write(String filename, byte[] data) throws IOException { + String[] path = filename.split("/"); + String pathPart = ""; + + for (int i = 0; i < path.length - 1; i++) { + pathPart += path[i] + "/"; + + if (addedDirectories.add(pathPart)) { + JarEntry entry = new JarEntry(pathPart); + entry.setTime(new Date().getTime()); + + try { + outputStream.putNextEntry(entry); + outputStream.closeEntry(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + JarEntry entry = new JarEntry(filename); + entry.setTime(new Date().getTime()); + entry.setSize(data.length); + + outputStream.putNextEntry(entry); + outputStream.write(data); + outputStream.closeEntry(); + } +} diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java new file mode 100644 index 000000000..dda15ee6f --- /dev/null +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java @@ -0,0 +1,198 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.decompilers.jadx; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +import jadx.api.CommentsLevel; +import jadx.api.ICodeInfo; +import jadx.api.JadxArgs; +import jadx.api.JadxDecompiler; +import jadx.api.JavaClass; +import jadx.api.JavaField; +import jadx.api.JavaMethod; +import jadx.api.impl.NoOpCodeCache; +import jadx.core.codegen.TypeGen; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.info.MethodInfo; +import jadx.core.dex.nodes.ClassNode; +import jadx.plugins.input.java.JavaInputPlugin; + +import net.fabricmc.loom.decompilers.LoomInternalDecompiler; +import net.fabricmc.mappingio.MappingReader; +import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MappingTree.ClassMapping; +import net.fabricmc.mappingio.tree.MappingTree.FieldMapping; +import net.fabricmc.mappingio.tree.MappingTree.MethodMapping; +import net.fabricmc.mappingio.tree.MemoryMappingTree; + +public final class LoomJadxDecompiler implements LoomInternalDecompiler { + private static JadxArgs getJadxArgs() { + JadxArgs jadxArgs = new JadxArgs(); + jadxArgs.setCodeCache(NoOpCodeCache.INSTANCE); + jadxArgs.setShowInconsistentCode(true); + // jadxArgs.setInlineAnonymousClasses(false); + // jadxArgs.setInlineMethods(false); + jadxArgs.setSkipResources(true); + jadxArgs.setRenameValid(false); + jadxArgs.setRespectBytecodeAccModifiers(true); + jadxArgs.setCommentsLevel(CommentsLevel.WARN); + + return jadxArgs; + } + + @Override + public void decompile(LoomInternalDecompiler.Context context) { + JadxArgs jadxArgs = getJadxArgs(); + jadxArgs.setThreadsCount(context.numberOfThreads()); + + List inputs = new ArrayList<>(context.libraries()); + inputs.add(context.compiledJar()); + + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + + try (JadxDecompiler jadx = new JadxDecompiler(jadxArgs); + JarOutputStream jarOutputStream = new JarOutputStream(Files.newOutputStream(context.sourcesDestination()), manifest); + Writer lineMapWriter = Files.newBufferedWriter(context.linemapDestination(), StandardCharsets.UTF_8)) { + jadx.addCustomLoad(JavaInputPlugin.loadClassFiles(inputs)); + jadx.load(); + + String comment; + MappingTree tree = readMappings(context.javaDocs().toFile()); + JarEntryWriter jarEntryWriter = new JarEntryWriter(jarOutputStream); + + for (JavaClass cls : jadx.getClasses()) { + if (cls.getClassNode().contains(AFlag.DONT_GENERATE)) { + continue; + } + + // Add Javadocs + ClassMapping clsMapping = tree.getClass(internalNameOf(cls.getClassNode())); + + if ((comment = emptyToNull(clsMapping.getComment())) != null) { + cls.getClassNode().addAttr(AType.CODE_COMMENTS, comment); + } + + for (JavaField fld : cls.getFields()) { + FieldMapping fldMapping = clsMapping.getField(fld.getFieldNode().getName(), TypeGen.signature(fld.getType())); + + if ((comment = emptyToNull(fldMapping.getComment())) != null) { + fld.getFieldNode().addAttr(AType.CODE_COMMENTS, comment); + } + } + + for (JavaMethod mth : cls.getMethods()) { + MethodInfo mthInfo = mth.getMethodNode().getMethodInfo(); + String mthName = mthInfo.getName(); + MethodMapping mthMapping = clsMapping.getMethod(mthName, mthInfo.getShortId().substring(mthName.length())); + + if ((comment = emptyToNull(mthMapping.getComment())) != null) { + mth.getMethodNode().addAttr(AType.CODE_COMMENTS, comment); + } + } + + // Decompile + ICodeInfo codeInfo = cls.getCodeInfo(); + + if (codeInfo == null) { + context.logger().error("Code not generated for class " + cls.getFullName()); + continue; + } + + if (codeInfo == ICodeInfo.EMPTY) { + continue; + } + + // Write to JAR + String filename = clsMapping.getSrcName() + ".java"; + + try { + byte[] code = codeInfo.getCodeStr().getBytes(StandardCharsets.UTF_8); + jarEntryWriter.write(filename, code); + } catch (IOException e) { + throw new RuntimeException("Unable to create archive: " + filename, e); + } + + // Write line map + int maxLine = 0; + int maxLineDest = 0; + StringBuilder builder = new StringBuilder(); + + for (Map.Entry mappingEntry : cls.getCodeInfo().getCodeMetadata().getLineMapping().entrySet()) { + final int src = mappingEntry.getKey(); + final int dst = mappingEntry.getValue(); + + maxLine = Math.max(maxLine, src); + maxLineDest = Math.max(maxLineDest, dst); + + builder.append("\t").append(src).append("\t").append(dst).append("\n"); + } + + lineMapWriter.write(String.format(Locale.ENGLISH, "%s\t%d\t%d\n", clsMapping.getSrcName(), maxLine, maxLineDest)); + lineMapWriter.write(builder.toString()); + lineMapWriter.write("\n"); + } + } catch (IOException e) { + throw new UncheckedIOException("Failed to decompile", e); + } + } + + private MappingTree readMappings(File input) { + try (BufferedReader reader = Files.newBufferedReader(input.toPath())) { + MemoryMappingTree mappingTree = new MemoryMappingTree(); + MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingTree, "named"); + MappingReader.read(reader, nsSwitch); + + return mappingTree; + } catch (IOException e) { + throw new RuntimeException("Failed to read mappings", e); + } + } + + private String internalNameOf(ClassNode cls) { + return cls.getClassInfo().makeRawFullName().replace('.', '/'); + } + + public static String emptyToNull(String string) { + return string.isEmpty() ? null : string; + } +} diff --git a/src/main/java/net/fabricmc/loom/decompilers/DecompilerConfiguration.java b/src/main/java/net/fabricmc/loom/decompilers/DecompilerConfiguration.java index 618629555..4a5ece0ce 100644 --- a/src/main/java/net/fabricmc/loom/decompilers/DecompilerConfiguration.java +++ b/src/main/java/net/fabricmc/loom/decompilers/DecompilerConfiguration.java @@ -42,6 +42,7 @@ import net.fabricmc.loom.api.decompilers.LoomDecompiler; import net.fabricmc.loom.decompilers.cfr.LoomCFRDecompiler; import net.fabricmc.loom.decompilers.fernflower.FabricFernFlowerDecompiler; +import net.fabricmc.loom.decompilers.jadx.LoomJadxDecompiler; import net.fabricmc.loom.decompilers.vineflower.VineflowerDecompiler; import net.fabricmc.loom.util.LoomVersions; import net.fabricmc.loom.util.ZipUtils; @@ -55,16 +56,22 @@ public void run() { var fernflowerConfiguration = createConfiguration("fernflower", LoomVersions.FERNFLOWER); var cfrConfiguration = createConfiguration("cfr", LoomVersions.CFR); var vineflowerConfiguration = createConfiguration("vineflower", LoomVersions.VINEFLOWER); + var jadxConfiguration = createConfiguration("jadx", LoomVersions.JADX_CORE, LoomVersions.JADX_JAVA); // FIXME: exclude transitive aapt2-proto and raung-disasm dependencies registerDecompiler(getProject(), "fernFlower", BuiltinFernflower.class, fernflowerConfiguration); registerDecompiler(getProject(), "cfr", BuiltinCfr.class, cfrConfiguration); registerDecompiler(getProject(), "vineflower", BuiltinVineflower.class, vineflowerConfiguration); + registerDecompiler(getProject(), "jadx", BuiltinVineflower.class, jadxConfiguration); } - private NamedDomainObjectProvider createConfiguration(String name, LoomVersions version) { + private NamedDomainObjectProvider createConfiguration(String name, LoomVersions... versions) { final String configurationName = name + "DecompilerClasspath"; NamedDomainObjectProvider configuration = getProject().getConfigurations().register(configurationName); - getProject().getDependencies().add(configurationName, version.mavenNotation()); + + for (LoomVersions version : versions) { + getProject().getDependencies().add(configurationName, version.mavenNotation()); + } + return configuration; } @@ -77,7 +84,7 @@ private void registerDecompiler(Project project, String name, Class Date: Fri, 15 Mar 2024 19:45:48 +0100 Subject: [PATCH 2/9] Run `spotlessApply` --- .../loom/decompilers/jadx/JarEntryWriter.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java index f4bea6c8e..e20d5eda7 100644 --- a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java @@ -1,3 +1,27 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2024 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package net.fabricmc.loom.decompilers.jadx; import java.io.IOException; From f3269a91c627954c0831ec6d32cf4341709388d7 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Fri, 15 Mar 2024 19:49:04 +0100 Subject: [PATCH 3/9] Fix copyright year --- .../net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java index dda15ee6f..b2f8bb211 100644 --- a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021 FabricMC + * Copyright (c) 2024 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal From 0bb95e1e505b1b3e719f9f3338961c254853c3e9 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 16 Mar 2024 13:58:03 +0000 Subject: [PATCH 4/9] Create JADX configuration --- .../loom/decompilers/jadx/JarEntryWriter.java | 2 +- .../decompilers/jadx/LoomJadxDecompiler.java | 2 +- .../decompilers/DecompilerConfiguration.java | 29 +++++++++++++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java index e20d5eda7..6e5f5f46e 100644 --- a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/JarEntryWriter.java @@ -38,7 +38,7 @@ public class JarEntryWriter { JarEntryWriter(JarOutputStream outputStream) { this.outputStream = outputStream; } - + synchronized void write(String filename, byte[] data) throws IOException { String[] path = filename.split("/"); String pathPart = ""; diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java index b2f8bb211..6bd2bfe1d 100644 --- a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java @@ -144,7 +144,7 @@ public void decompile(LoomInternalDecompiler.Context context) { // Write to JAR String filename = clsMapping.getSrcName() + ".java"; - + try { byte[] code = codeInfo.getCodeStr().getBytes(StandardCharsets.UTF_8); jarEntryWriter.write(filename, code); diff --git a/src/main/java/net/fabricmc/loom/decompilers/DecompilerConfiguration.java b/src/main/java/net/fabricmc/loom/decompilers/DecompilerConfiguration.java index 4a5ece0ce..6c2b69c97 100644 --- a/src/main/java/net/fabricmc/loom/decompilers/DecompilerConfiguration.java +++ b/src/main/java/net/fabricmc/loom/decompilers/DecompilerConfiguration.java @@ -34,6 +34,8 @@ import org.gradle.api.NamedDomainObjectProvider; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.ExternalModuleDependency; +import org.gradle.api.artifacts.dsl.DependencyFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,12 +58,12 @@ public void run() { var fernflowerConfiguration = createConfiguration("fernflower", LoomVersions.FERNFLOWER); var cfrConfiguration = createConfiguration("cfr", LoomVersions.CFR); var vineflowerConfiguration = createConfiguration("vineflower", LoomVersions.VINEFLOWER); - var jadxConfiguration = createConfiguration("jadx", LoomVersions.JADX_CORE, LoomVersions.JADX_JAVA); // FIXME: exclude transitive aapt2-proto and raung-disasm dependencies + var jadxConfiguration = createJadxConfiguration(); registerDecompiler(getProject(), "fernFlower", BuiltinFernflower.class, fernflowerConfiguration); registerDecompiler(getProject(), "cfr", BuiltinCfr.class, cfrConfiguration); registerDecompiler(getProject(), "vineflower", BuiltinVineflower.class, vineflowerConfiguration); - registerDecompiler(getProject(), "jadx", BuiltinVineflower.class, jadxConfiguration); + registerDecompiler(getProject(), "jadx", BuiltinJadx.class, jadxConfiguration); } private NamedDomainObjectProvider createConfiguration(String name, LoomVersions... versions) { @@ -75,6 +77,29 @@ private NamedDomainObjectProvider createConfiguration(String name return configuration; } + private NamedDomainObjectProvider createJadxConfiguration() { + final String configurationName = "jadxDecompilerClasspath"; + final NamedDomainObjectProvider configuration = getProject().getConfigurations().register(configurationName); + final DependencyFactory dependencyFactory = getProject().getDependencyFactory(); + + final ExternalModuleDependency jadxCore = dependencyFactory.create(LoomVersions.JADX_CORE.mavenNotation()); + jadxCore.exclude(Map.of( + "group", "com.android.tools.build", + "module", "aapt2-proto" + )); + + final ExternalModuleDependency jadxJava = dependencyFactory.create(LoomVersions.JADX_JAVA.mavenNotation()); + jadxJava.exclude(Map.of( + "group", "io.github.skylot", + "module", "raung-disasm" + )); + + getProject().getDependencies().add(configurationName, jadxCore); + getProject().getDependencies().add(configurationName, jadxJava); + + return configuration; + } + private void registerDecompiler(Project project, String name, Class decompilerClass, NamedDomainObjectProvider configuration) { LoomGradleExtension.get(project).getDecompilerOptions().register(name, options -> { options.getDecompilerClassName().set(decompilerClass.getName()); From a8f4b88efb6a2aca8423ce05a4e9a7077e16b8bb Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sat, 16 Mar 2024 17:09:01 +0100 Subject: [PATCH 5/9] Fix NPE --- .../decompilers/jadx/LoomJadxDecompiler.java | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java index 6bd2bfe1d..77a3f60a9 100644 --- a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java @@ -81,6 +81,7 @@ private static JadxArgs getJadxArgs() { @Override public void decompile(LoomInternalDecompiler.Context context) { + System.out.println(System.getProperty("java.io.tmpdir")); JadxArgs jadxArgs = getJadxArgs(); jadxArgs.setThreadsCount(context.numberOfThreads()); @@ -96,7 +97,6 @@ public void decompile(LoomInternalDecompiler.Context context) { jadx.addCustomLoad(JavaInputPlugin.loadClassFiles(inputs)); jadx.load(); - String comment; MappingTree tree = readMappings(context.javaDocs().toFile()); JarEntryWriter jarEntryWriter = new JarEntryWriter(jarOutputStream); @@ -107,28 +107,7 @@ public void decompile(LoomInternalDecompiler.Context context) { // Add Javadocs ClassMapping clsMapping = tree.getClass(internalNameOf(cls.getClassNode())); - - if ((comment = emptyToNull(clsMapping.getComment())) != null) { - cls.getClassNode().addAttr(AType.CODE_COMMENTS, comment); - } - - for (JavaField fld : cls.getFields()) { - FieldMapping fldMapping = clsMapping.getField(fld.getFieldNode().getName(), TypeGen.signature(fld.getType())); - - if ((comment = emptyToNull(fldMapping.getComment())) != null) { - fld.getFieldNode().addAttr(AType.CODE_COMMENTS, comment); - } - } - - for (JavaMethod mth : cls.getMethods()) { - MethodInfo mthInfo = mth.getMethodNode().getMethodInfo(); - String mthName = mthInfo.getName(); - MethodMapping mthMapping = clsMapping.getMethod(mthName, mthInfo.getShortId().substring(mthName.length())); - - if ((comment = emptyToNull(mthMapping.getComment())) != null) { - mth.getMethodNode().addAttr(AType.CODE_COMMENTS, comment); - } - } + addJavadocs(cls, clsMapping); // Decompile ICodeInfo codeInfo = cls.getCodeInfo(); @@ -188,6 +167,36 @@ private MappingTree readMappings(File input) { } } + private void addJavadocs(JavaClass cls, ClassMapping clsMapping) { + String comment; + + if (clsMapping == null) { + return; + } + + if ((comment = emptyToNull(clsMapping.getComment())) != null) { + cls.getClassNode().addAttr(AType.CODE_COMMENTS, comment); + } + + for (JavaField fld : cls.getFields()) { + FieldMapping fldMapping = clsMapping.getField(fld.getFieldNode().getName(), TypeGen.signature(fld.getType())); + + if ((comment = emptyToNull(fldMapping.getComment())) != null) { + fld.getFieldNode().addAttr(AType.CODE_COMMENTS, comment); + } + } + + for (JavaMethod mth : cls.getMethods()) { + MethodInfo mthInfo = mth.getMethodNode().getMethodInfo(); + String mthName = mthInfo.getName(); + MethodMapping mthMapping = clsMapping.getMethod(mthName, mthInfo.getShortId().substring(mthName.length())); + + if ((comment = emptyToNull(mthMapping.getComment())) != null) { + mth.getMethodNode().addAttr(AType.CODE_COMMENTS, comment); + } + } + } + private String internalNameOf(ClassNode cls) { return cls.getClassInfo().makeRawFullName().replace('.', '/'); } From 0880d8b3ab6e38b3a47ca28849062ec109d7f121 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sun, 17 Mar 2024 09:24:49 +0100 Subject: [PATCH 6/9] Fix NPE (2) --- .../loom/decompilers/jadx/LoomJadxDecompiler.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java index 77a3f60a9..2cb593779 100644 --- a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java @@ -105,9 +105,10 @@ public void decompile(LoomInternalDecompiler.Context context) { continue; } + String clsName = internalNameOf(cls.getClassNode()); + // Add Javadocs - ClassMapping clsMapping = tree.getClass(internalNameOf(cls.getClassNode())); - addJavadocs(cls, clsMapping); + addJavadocs(cls, tree.getClass(clsName)); // Decompile ICodeInfo codeInfo = cls.getCodeInfo(); @@ -122,7 +123,7 @@ public void decompile(LoomInternalDecompiler.Context context) { } // Write to JAR - String filename = clsMapping.getSrcName() + ".java"; + String filename = clsName + ".java"; try { byte[] code = codeInfo.getCodeStr().getBytes(StandardCharsets.UTF_8); @@ -146,7 +147,7 @@ public void decompile(LoomInternalDecompiler.Context context) { builder.append("\t").append(src).append("\t").append(dst).append("\n"); } - lineMapWriter.write(String.format(Locale.ENGLISH, "%s\t%d\t%d\n", clsMapping.getSrcName(), maxLine, maxLineDest)); + lineMapWriter.write(String.format(Locale.ENGLISH, "%s\t%d\t%d\n", clsName, maxLine, maxLineDest)); lineMapWriter.write(builder.toString()); lineMapWriter.write("\n"); } From 09f7390191e2125aabe22ef74dcaa85b632db2b9 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Mon, 18 Mar 2024 08:28:48 +0100 Subject: [PATCH 7/9] Fix NPE (3) --- .../fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java index 2cb593779..bf228d825 100644 --- a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java @@ -182,7 +182,7 @@ private void addJavadocs(JavaClass cls, ClassMapping clsMapping) { for (JavaField fld : cls.getFields()) { FieldMapping fldMapping = clsMapping.getField(fld.getFieldNode().getName(), TypeGen.signature(fld.getType())); - if ((comment = emptyToNull(fldMapping.getComment())) != null) { + if (fldMapping != null && (comment = emptyToNull(fldMapping.getComment())) != null) { fld.getFieldNode().addAttr(AType.CODE_COMMENTS, comment); } } @@ -192,7 +192,7 @@ private void addJavadocs(JavaClass cls, ClassMapping clsMapping) { String mthName = mthInfo.getName(); MethodMapping mthMapping = clsMapping.getMethod(mthName, mthInfo.getShortId().substring(mthName.length())); - if ((comment = emptyToNull(mthMapping.getComment())) != null) { + if (mthMapping != null && (comment = emptyToNull(mthMapping.getComment())) != null) { mth.getMethodNode().addAttr(AType.CODE_COMMENTS, comment); } } @@ -203,6 +203,6 @@ private String internalNameOf(ClassNode cls) { } public static String emptyToNull(String string) { - return string.isEmpty() ? null : string; + return string == null || string.isEmpty() ? null : string; } } From 6782367a7d1b1f92bc2a47c9e305576ff78b68b9 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Mon, 18 Mar 2024 15:46:13 +0100 Subject: [PATCH 8/9] Don't decompile the classpath --- .../fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java index bf228d825..be2913fbc 100644 --- a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java @@ -85,16 +85,13 @@ public void decompile(LoomInternalDecompiler.Context context) { JadxArgs jadxArgs = getJadxArgs(); jadxArgs.setThreadsCount(context.numberOfThreads()); - List inputs = new ArrayList<>(context.libraries()); - inputs.add(context.compiledJar()); - Manifest manifest = new Manifest(); manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); try (JadxDecompiler jadx = new JadxDecompiler(jadxArgs); JarOutputStream jarOutputStream = new JarOutputStream(Files.newOutputStream(context.sourcesDestination()), manifest); Writer lineMapWriter = Files.newBufferedWriter(context.linemapDestination(), StandardCharsets.UTF_8)) { - jadx.addCustomLoad(JavaInputPlugin.loadClassFiles(inputs)); + jadx.addCustomLoad(JavaInputPlugin.loadClassFiles(List.of(context.compiledJar()))); jadx.load(); MappingTree tree = readMappings(context.javaDocs().toFile()); From 2b92b7ca12de21a5acb154f1d643a83a3ae4b484 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Mon, 18 Mar 2024 20:54:01 +0100 Subject: [PATCH 9/9] Remove unused imports --- .../net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java index be2913fbc..40bedb13c 100644 --- a/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java +++ b/src/decompilers/jadx/net/fabricmc/loom/decompilers/jadx/LoomJadxDecompiler.java @@ -31,8 +31,6 @@ import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map;