From 112a38be2a40f9f29a6d110171bc7192bcb90d94 Mon Sep 17 00:00:00 2001 From: modmuss50 <modmuss50@gmail.com> Date: Sun, 11 Dec 2022 13:50:46 +0000 Subject: [PATCH] Generate access wideners for DataProvider.getName implementations (#2736) * Generate AW for DataProvider.getName impls * Remove final * Typo + improve memory usage --- fabric-data-generation-api-v1/build.gradle | 96 +++++++++++++++---- .../v1/provider/FabricLanguageProvider.java | 2 +- ...abric-data-generation-api-v1.accesswidener | 13 +++ 3 files changed, 94 insertions(+), 17 deletions(-) diff --git a/fabric-data-generation-api-v1/build.gradle b/fabric-data-generation-api-v1/build.gradle index 7506fe753..77d21e241 100644 --- a/fabric-data-generation-api-v1/build.gradle +++ b/fabric-data-generation-api-v1/build.gradle @@ -56,6 +56,8 @@ import org.objectweb.asm.ClassReader import org.objectweb.asm.Opcodes import org.objectweb.asm.tree.ClassNode +import java.lang.reflect.Modifier +import java.util.zip.ZipEntry import java.util.zip.ZipFile task generateAccessWidener() { @@ -63,14 +65,16 @@ task generateAccessWidener() { File inputJar = loom.namedMinecraftProvider.parentMinecraftProvider.commonJar.toFile() String accessWidener = file("template.accesswidener").text + "\n" - visitMethods(inputJar, "net/minecraft/data/server/recipe/RecipeProvider.class") { name, desc, owner -> + def classes = getClasses(inputJar) + + visitMethods(classes["net/minecraft/data/server/recipe/RecipeProvider"]) { name, desc, owner -> if (it.name == "generate") return accessWidener += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n" } - visitMethods(inputJar, "net/minecraft/data/client/BlockStateModelGenerator.class") { name, desc, owner -> + visitMethods(classes["net/minecraft/data/client/BlockStateModelGenerator"]) { name, desc, owner -> if (desc == "()V") // Skip over methods that dont take any arguments, as they are specific to minecraft. return @@ -78,40 +82,100 @@ task generateAccessWidener() { accessWidener += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n" } - visitMethods(inputJar, "net/minecraft/data/server/loottable/BlockLootTableGenerator.class") { name, desc, owner -> + visitMethods(classes["net/minecraft/data/server/loottable/BlockLootTableGenerator"]) { name, desc, owner -> accessWidener += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n" } - visitMethods(inputJar, "net/minecraft/data/client/ItemModelGenerator.class") { name, desc, owner -> + visitMethods(classes["net/minecraft/data/client/ItemModelGenerator"]) { name, desc, owner -> accessWidener += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n" } + classes.values().forEach { classNode -> + visitFinalMethods(classNode) { name, desc, owner -> + if (name != "getName" || desc != "()Ljava/lang/String;") { + // Not the method we are after + return + } + + if (!hasAncestor(classNode, classes, "net/minecraft/data/DataProvider")) { + // Not a descendant of DataProvider + return + } + + accessWidener += "transitive-extendable\tmethod\t${owner}\t${name}\t${desc}\n" + } + } + file("src/main/resources/fabric-data-generation-api-v1.accesswidener").text = accessWidener } } -def visitMethods(File input, String className, closure) { - def clazz = getClassNode(input, className) - - clazz.methods.forEach { +def visitMethods(ClassNode classNode, closure) { + classNode.methods.forEach { if ((it.access & Opcodes.ACC_SYNTHETIC) != 0 || (it.access & Opcodes.ACC_PUBLIC) != 0) return if (it.name.startsWith("<")) return - closure(it.name, it.desc, clazz.name) + closure(it.name, it.desc, classNode.name) } } -ClassNode getClassNode(File input, String className) { - new ZipFile(input).withCloseable { ZipFile zip -> - zip.getInputStream(zip.getEntry(className)).withCloseable { is -> - ClassReader reader = new ClassReader(is) - ClassNode classNode = new ClassNode() - reader.accept(classNode, 0) +def visitFinalMethods(ClassNode classNode, closure) { + classNode.methods.forEach { + if (!Modifier.isFinal(it.access)) + return - return classNode + if (it.name.startsWith("<")) + return + + closure(it.name, it.desc, classNode.name) + } +} + +// Return a map of all class names to classNodes +def getClasses(File input) { + Map<String, ClassNode> classes = [:] + + new ZipFile(input).withCloseable { ZipFile zip -> + zip.entries().toList().forEach { ZipEntry entry -> + if (!entry.name.endsWith(".class")) { + return + } + + zip.getInputStream(entry).withCloseable { is -> + ClassReader reader = new ClassReader(is) + ClassNode classNode = new ClassNode() + reader.accept(classNode, ClassReader.SKIP_CODE) + + classes.put(classNode.name, classNode) + } + } + } + + return classes +} + +def hasAncestor(ClassNode classNode, Map<String, ClassNode> classes, String ancestorName) { + if (classNode.superName == ancestorName) { + return true + } + + // Recuse through the super classes + def superClass = classes.get(classNode.superName) + if (superClass != null && hasAncestor(superClass, classes, ancestorName)) { + return true + } + + for (def interfaceName : classNode.interfaces) { + if (interfaceName == ancestorName) { + return true + } + + def ifaceClass = classes.get(interfaceName) + if (ifaceClass != null && hasAncestor(ifaceClass, classes, ancestorName)) { + return true } } } diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricLanguageProvider.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricLanguageProvider.java index f4ab8c8cb..3250b4743 100644 --- a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricLanguageProvider.java +++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricLanguageProvider.java @@ -102,7 +102,7 @@ public abstract class FabricLanguageProvider implements DataProvider { } @Override - public final String getName() { + public String getName() { return "Language (%s)".formatted(languageCode); } diff --git a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener index b1a727ac5..1bd8475d3 100644 --- a/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener +++ b/fabric-data-generation-api-v1/src/main/resources/fabric-data-generation-api-v1.accesswidener @@ -284,3 +284,16 @@ transitive-accessible method net/minecraft/data/client/ItemModelGenerator regist transitive-accessible method net/minecraft/data/client/ItemModelGenerator register (Lnet/minecraft/item/Item;Lnet/minecraft/item/Item;Lnet/minecraft/data/client/Model;)V transitive-accessible method net/minecraft/data/client/ItemModelGenerator registerCompass (Lnet/minecraft/item/Item;)V transitive-accessible method net/minecraft/data/client/ItemModelGenerator registerClock (Lnet/minecraft/item/Item;)V +transitive-extendable method net/minecraft/data/server/advancement/AdvancementProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/report/CommandSyntaxProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/report/BlockListProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/report/RegistryDumpProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/server/loottable/LootTableProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/MetadataProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/client/ModelProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/server/BiomeParametersProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/dev/NbtProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/SnbtProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/server/recipe/RecipeProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/report/DynamicRegistriesProvider getName ()Ljava/lang/String; +transitive-extendable method net/minecraft/data/server/tag/AbstractTagProvider getName ()Ljava/lang/String;