From df097abdbba82cf2127b29d75b186941529c0eeb Mon Sep 17 00:00:00 2001 From: lap2ka <83134094+lap2ka@users.noreply.github.com> Date: Sat, 9 May 2026 12:14:53 +0200 Subject: [PATCH] Fix remapping of mixin annotation targets --- .../transformer/jar/IntermediateMapping.java | 28 +++++++++++++++++-- .../OptimizedRenamingTransformer.java | 23 +++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/jar/IntermediateMapping.java b/transformer/src/main/java/org/sinytra/connector/transformer/jar/IntermediateMapping.java index 4f69c9ae..2adb781f 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/jar/IntermediateMapping.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/jar/IntermediateMapping.java @@ -23,6 +23,8 @@ public class IntermediateMapping { private final Map mappings; // Original + Descriptor -> Mapped private final Map extendedMappings; + // Original -> Mapped name + original descriptor, when the original method name is unambiguous + private final Map methodMappings; public static IntermediateMapping get(String sourceNamespace) { IntermediateMapping existing = INTERMEDIATE_MAPPINGS_CACHE.get(sourceNamespace); @@ -40,12 +42,25 @@ public static IntermediateMapping get(String sourceNamespace) { Map resolved = new HashMap<>(); Map buffer = new HashMap<>(); Map extendedMappings = new HashMap<>(); + Map methodMappings = new HashMap<>(); + Set ambiguousMethods = new HashSet<>(); resolver.getCurrentMap(sourceNamespace).getClasses().stream() .flatMap(cls -> Stream.concat(Stream.of(cls), Stream.concat(cls.getFields().stream(), cls.getMethods().stream())) .filter(node -> prefixes.stream().anyMatch(node.getOriginal()::startsWith))) .forEach(node -> { String original = node.getOriginal(); String mapped = node.getMapped(); + if (node instanceof IMappingFile.IMethod method && method.getDescriptor() != null) { + MethodMapping methodMapping = new MethodMapping(mapped, method.getDescriptor()); + MethodMapping existingMethod = methodMappings.get(original); + if (existingMethod == null && !ambiguousMethods.contains(original)) { + methodMappings.put(original, methodMapping); + } + else if (!methodMapping.equals(existingMethod)) { + methodMappings.remove(original); + ambiguousMethods.add(original); + } + } String mapping = resolved.get(original); if (mapping != null && !mapping.equals(mapped)) { resolved.remove(original); @@ -57,7 +72,7 @@ else if (!extendedMappings.containsKey(getMappingKey(node))) { buffer.put(original, node); } }); - IntermediateMapping mapping = new IntermediateMapping(resolved, extendedMappings); + IntermediateMapping mapping = new IntermediateMapping(resolved, extendedMappings, methodMappings); INTERMEDIATE_MAPPINGS_CACHE.put(sourceNamespace, mapping); return mapping; } @@ -76,9 +91,10 @@ else if (node instanceof IMappingFile.IMethod method) { return node.getOriginal(); } - public IntermediateMapping(Map mappings, Map extendedMappings) { + public IntermediateMapping(Map mappings, Map extendedMappings, Map methodMappings) { this.mappings = mappings; this.extendedMappings = extendedMappings; + this.methodMappings = methodMappings; } @Nullable @@ -101,6 +117,11 @@ public String mapMethodOrDefault(String name, String desc) { return mapped != null ? mapped : name; } + @Nullable + public MethodMapping getMethodMapping(String name) { + return this.methodMappings.get(name); + } + @Nullable public String mapMethod(String name, String desc) { String mapped = this.mappings.get(name); @@ -110,4 +131,7 @@ public String mapMethod(String name, String desc) { } return mapped; } + + public record MethodMapping(String mappedName, String descriptor) { + } } diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/transform/OptimizedRenamingTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/transform/OptimizedRenamingTransformer.java index 5e76d0b5..c44f4170 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/transform/OptimizedRenamingTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/transform/OptimizedRenamingTransformer.java @@ -69,6 +69,11 @@ protected void postProcess(ClassNode node) { processMixinAnnotation(annotation, postProcessRemapper); } } + if (method.invisibleAnnotations != null) { + for (AnnotationNode annotation : method.invisibleAnnotations) { + processMixinAnnotation(annotation, postProcessRemapper); + } + } for (AbstractInsnNode insn : method.instructions) { if (insn instanceof LdcInsnNode ldc) { ldc.cst = postProcessRemapper.mapValue(ldc.cst); @@ -141,10 +146,17 @@ private void processMixinAnnotation(AnnotationNode annotation, PostProcessRemapp }); // If remap has been set to false during compilation, we must manually map the annotation values ourselves instead of relying on the provided refmap if (this.remapRefs || handle.getValue("remap").map(h -> !h.get()).orElse(false)) { + qualifyMixinMethodSelectors(handle, postProcessRemapper); postProcessRemapper.mapAnnotationValues(annotation.values); } } + private static void qualifyMixinMethodSelectors(AnnotationHandle handle, PostProcessRemapper postProcessRemapper) { + handle.>getValue("method") + .map(AnnotationValueHandle::get) + .ifPresent(methods -> methods.replaceAll(postProcessRemapper::qualifyMethodSelector)); + } + private record PostProcessRemapper(IntermediateMapping flatMappings, Remapper remapper) { public void mapAnnotationValues(List values) { if (values != null) { @@ -218,6 +230,17 @@ else if (str.matches(INTERNAL_CLASS_NAME_PATTERN)) { } return this.remapper.mapValue(value); } + + public String qualifyMethodSelector(String selector) { + MethodQualifier qualifier = MethodQualifier.parse(selector).orElse(null); + if (qualifier != null && qualifier.desc() == null && qualifier.name() != null) { + IntermediateMapping.MethodMapping methodMapping = this.flatMappings.getMethodMapping(qualifier.name()); + if (methodMapping != null) { + return methodMapping.mappedName() + this.remapper.mapMethodDesc(methodMapping.descriptor()); + } + } + return selector; + } } public static final class IntermediaryClassProvider implements ClassProvider {