From 383d40e42067252ac2c9ec84f3cea1840d31c398 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 19 Aug 2023 14:58:07 -0400 Subject: [PATCH] Detect mixins with calls to other merged methods Related: #222 --- .../modernfix/core/ModernFixMixinPlugin.java | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java b/common/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java index c61492a3..9e0354d5 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java @@ -166,11 +166,13 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin { "getFluidState", "method_26227", "m_60819_", "func_204520_s" ); Map injectorMethodNames = new HashMap<>(); + Map allMethods = new HashMap<>(); Map injectorMixinSource = new HashMap<>(); String descriptor = Type.getDescriptor(MixinMerged.class); for(MethodNode m : targetClass.methods) { if((m.access & Opcodes.ACC_STATIC) != 0) continue; + allMethods.put(m.name, m); Set seenNodes = new HashSet<>(); if(m.invisibleAnnotations != null) { for(AnnotationNode ann : m.invisibleAnnotations) { @@ -217,8 +219,35 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin { } } Set accessedFieldNames = new HashSet<>(); - // We now know all methods that have been injected into initCache. See what fields they write to - injectorMethodNames.forEach((name, method) -> { + + // Make a map of all injected methods called by initCache + Map writingMethods = new HashMap<>(injectorMethodNames); + writingMethods.keySet().retainAll(cacheCalledInjectors); + + // Recursively check the injected methods for any methods they may call + int previousSize = 0; + Set checkedCalls = new HashSet<>(); + while(writingMethods.size() > previousSize) { + previousSize = writingMethods.size(); + List keysToCheck = new ArrayList<>(writingMethods.keySet()); + for(String name : keysToCheck) { + if(!checkedCalls.add(name)) + continue; + for(AbstractInsnNode n : writingMethods.get(name).instructions) { + if(n instanceof MethodInsnNode) { + MethodInsnNode invokeNode = (MethodInsnNode)n; + if(invokeNode.owner.equals(targetClass.name)) { + MethodNode theMethod = allMethods.get(invokeNode.name); + if(theMethod != null) + writingMethods.put(invokeNode.name, theMethod); + } + } + } + } + } + + // We now know all methods that have been injected into initCache, and their callers. See what fields they write to + writingMethods.forEach((name, method) -> { if(cacheCalledInjectors.contains(name)) { for(AbstractInsnNode n : method.instructions) { if(n instanceof FieldInsnNode) {