From 9d6d5d8dc5ff20d769fb53d9ae869043a17e4b27 Mon Sep 17 00:00:00 2001 From: CraftBukkit/Spigot Date: Mon, 8 Jul 2024 07:01:03 +1000 Subject: [PATCH] SPIGOT-7820: Enum changes - duplicate method name By: DerFrZocker --- .../bukkit/craftbukkit/util/Commodore.java | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java index af4a3bdc21..a86de3326f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java @@ -1,11 +1,14 @@ package org.bukkit.craftbukkit.util; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import com.google.common.io.ByteStreams; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; @@ -160,11 +163,18 @@ public class Commodore { public static byte[] convert(byte[] b, final String pluginName, final ApiVersion pluginVersion, final Set activeCompatibilities) { final boolean modern = pluginVersion.isNewerThanOrSameAs(ApiVersion.FLATTENING); + final boolean enumCompatibility = pluginVersion.isOlderThanOrSameAs(ApiVersion.getOrCreateVersion("1.20.6")) && activeCompatibilities.contains("enum-compatibility-mode"); ClassReader cr = new ClassReader(b); ClassWriter cw = new ClassWriter(0); // TODO 2024-06-22: Open PR to ASM to included interface in handle hash + List methodEnumSignatures = getMethodSignatures(b); + Multimap enumLessToEnum = HashMultimap.create(); + for (String method : methodEnumSignatures) { + enumLessToEnum.put(method.replace("Ljava/lang/Enum;", "Ljava/lang/Object;"), method); + } + ClassVisitor visitor = cw; - if (pluginVersion.isOlderThanOrSameAs(ApiVersion.getOrCreateVersion("1.20.6")) && activeCompatibilities.contains("enum-compatibility-mode")) { + if (enumCompatibility) { visitor = new LimitedClassRemapper(cw, new SimpleRemapper(ENUM_RENAMES)); } @@ -232,6 +242,15 @@ public class Commodore { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (enumCompatibility && (access & Opcodes.ACC_SYNTHETIC) != 0 && (access & Opcodes.ACC_BRIDGE) != 0 && desc.contains("Ljava/lang/Object;")) { + // SPIGOT-7820: Do not use object method if enum method is present + // The object method does only redirect to the enum method + Collection result = enumLessToEnum.get(desc.replace("Ljava/lang/Enum;", "Ljava/lang/Object;") + " " + name); + if (result.size() == 2) { + name = name + "_BUKKIT_UNUSED"; + } + } + return new MethodVisitor(api, super.visitMethod(access, name, desc, signature, exceptions)) { @Override @@ -644,6 +663,20 @@ public class Commodore { return false; } + private static List getMethodSignatures(byte[] clazz) { + List methods = new ArrayList<>(); + ClassReader cr = new ClassReader(clazz); + cr.accept(new ClassVisitor(Opcodes.ASM9) { + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + methods.add(descriptor + " " + name); + return null; + } + }, 0); + + return methods; + } + private static String buildMethodName(RerouteMethodData rerouteMethodData) { return BUKKIT_GENERATED_METHOD_PREFIX + rerouteMethodData.targetOwner().replace('/', '_') + "_" + rerouteMethodData.targetName(); }