diff --git a/src/main/java/org/spongepowered/asm/mixin/FabricUtil.java b/src/main/java/org/spongepowered/asm/mixin/FabricUtil.java index 650e45288..ae057f32b 100644 --- a/src/main/java/org/spongepowered/asm/mixin/FabricUtil.java +++ b/src/main/java/org/spongepowered/asm/mixin/FabricUtil.java @@ -66,10 +66,15 @@ public final class FabricUtil { */ public static final int COMPATIBILITY_0_17_1 = 17001; // 0.17.1+mixin.0.8.7 + /** + * Fabric compatibility version 0.17.4 + */ + public static final int COMPATIBILITY_0_17_4 = 17004; // 0.17.4+mixin.0.8.7 + /** * Latest compatibility version */ - public static final int COMPATIBILITY_LATEST = COMPATIBILITY_0_17_1; + public static final int COMPATIBILITY_LATEST = COMPATIBILITY_0_17_4; public static String getModId(IMixinConfig config) { return getModId(config, "(unknown)"); diff --git a/src/main/java/org/spongepowered/asm/mixin/gen/AccessorInfo.java b/src/main/java/org/spongepowered/asm/mixin/gen/AccessorInfo.java index 0a02b504c..ba05e875a 100644 --- a/src/main/java/org/spongepowered/asm/mixin/gen/AccessorInfo.java +++ b/src/main/java/org/spongepowered/asm/mixin/gen/AccessorInfo.java @@ -24,15 +24,9 @@ */ package org.spongepowered.asm.mixin.gen; -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +import com.google.common.base.Joiner; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableSet; import org.objectweb.asm.Type; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; @@ -41,8 +35,8 @@ import org.spongepowered.asm.mixin.injection.selectors.ElementNode; import org.spongepowered.asm.mixin.injection.selectors.ISelectorContext; import org.spongepowered.asm.mixin.injection.selectors.ITargetSelector; -import org.spongepowered.asm.mixin.injection.selectors.TargetSelector; import org.spongepowered.asm.mixin.injection.selectors.ITargetSelector.Configure; +import org.spongepowered.asm.mixin.injection.selectors.TargetSelector; import org.spongepowered.asm.mixin.injection.selectors.TargetSelector.Result; import org.spongepowered.asm.mixin.injection.struct.MemberInfo; import org.spongepowered.asm.mixin.struct.SpecialMethodInfo; @@ -52,9 +46,10 @@ import org.spongepowered.asm.util.Bytecode; import org.spongepowered.asm.util.asm.MethodNodeEx; -import com.google.common.base.Joiner; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableSet; +import java.lang.annotation.Annotation; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Information about an accessor @@ -511,7 +506,7 @@ private FieldNode findTargetField() { * @return best match */ protected TNode findTarget(List> nodes) { - Result result = TargetSelector.run(this.target.configure(Configure.ORPHAN), nodes); + Result result = TargetSelector.run(this.mixin, this.target.configure(Configure.ORPHAN), nodes); try { return result.getSingleResult(true); diff --git a/src/main/java/org/spongepowered/asm/mixin/gen/InvokerInfo.java b/src/main/java/org/spongepowered/asm/mixin/gen/InvokerInfo.java index 64b6def92..cf4cca614 100644 --- a/src/main/java/org/spongepowered/asm/mixin/gen/InvokerInfo.java +++ b/src/main/java/org/spongepowered/asm/mixin/gen/InvokerInfo.java @@ -104,7 +104,7 @@ public void locate() { } private MethodNode findTargetMethod() { - Result result = TargetSelector.run(this.target.configure(Configure.ORPHAN), + Result result = TargetSelector.run(this.mixin, this.target.configure(Configure.ORPHAN), ElementNode.methodList(this.classNode)); try { diff --git a/src/main/java/org/spongepowered/asm/mixin/injection/selectors/TargetSelector.java b/src/main/java/org/spongepowered/asm/mixin/injection/selectors/TargetSelector.java index 2d7e61ce2..c826ab2c2 100644 --- a/src/main/java/org/spongepowered/asm/mixin/injection/selectors/TargetSelector.java +++ b/src/main/java/org/spongepowered/asm/mixin/injection/selectors/TargetSelector.java @@ -24,37 +24,33 @@ */ package org.spongepowered.asm.mixin.injection.selectors; -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.tools.Diagnostic.Kind; - +import com.google.common.base.Strings; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AnnotationNode; +import org.spongepowered.asm.mixin.FabricUtil; import org.spongepowered.asm.mixin.injection.selectors.ITargetSelectorDynamic.SelectorAnnotation; import org.spongepowered.asm.mixin.injection.selectors.ITargetSelectorDynamic.SelectorId; import org.spongepowered.asm.mixin.injection.selectors.dynamic.DynamicSelectorDesc; import org.spongepowered.asm.mixin.injection.selectors.throwables.SelectorConstraintException; import org.spongepowered.asm.mixin.injection.struct.MemberInfo; +import org.spongepowered.asm.mixin.refmap.IMixinContext; import org.spongepowered.asm.mixin.throwables.MixinError; import org.spongepowered.asm.mixin.throwables.MixinException; import org.spongepowered.asm.util.Annotations; import org.spongepowered.asm.util.asm.IAnnotationHandle; import org.spongepowered.asm.util.logging.MessageRouter; -import com.google.common.base.Strings; +import javax.tools.Diagnostic.Kind; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** * Utility class for parsing selectors @@ -450,32 +446,34 @@ public static String parseName(String name, ISelectorContext context) { /** * Run query on supplied target nodes - * + * + * @param mixin context * @param selector Target selector * @param nodes Node collection to enumerate * @param Node type * @return query result */ - public static Result run(ITargetSelector selector, Iterable> nodes) { + public static Result run(IMixinContext mixin, ITargetSelector selector, Iterable> nodes) { List> candidates = new ArrayList>(); - ElementNode exactMatch = TargetSelector.runSelector(selector, nodes, candidates); + ElementNode exactMatch = TargetSelector.runSelector(mixin, selector, nodes, candidates); return new Result(exactMatch, candidates); } /** * Run query on supplied target nodes - * + * + * @param mixin context * @param selector Target selector * @param nodes Node collection to enumerate * @param Node type * @return query result */ - public static Result run(Iterable selector, Iterable> nodes) { + public static Result run(IMixinContext mixin, Iterable selector, Iterable> nodes) { ElementNode exactMatch = null; List> candidates = new ArrayList>(); for (ITargetSelector target : selector) { - ElementNode selectorExactMatch = TargetSelector.runSelector(target, nodes, candidates); + ElementNode selectorExactMatch = TargetSelector.runSelector(mixin, target, nodes, candidates); if (exactMatch == null) { exactMatch = selectorExactMatch; } @@ -484,33 +482,30 @@ public static Result run(Iterable selector, Iter return new Result(exactMatch, candidates); } - private static ElementNode runSelector(ITargetSelector selector, Iterable> nodes, + private static ElementNode runSelector(IMixinContext mixin, ITargetSelector selector, Iterable> nodes, List> candidates) { - int matchCount = 0; - ElementNode exactMatch = null; - for (Iterator> iterator = nodes.iterator(); iterator.hasNext();) { - ElementNode element = iterator.next(); - MatchResult match = selector.match(element); - if (match.isMatch()) { - matchCount++; - if (matchCount > selector.getMaxMatchCount()) { - break; - } - if (!candidates.contains(element)) { - candidates.add(element); - } - if (exactMatch == null && match.isExactMatch()) { - exactMatch = element; - } - } + Stream, MatchResult>> stream = StreamSupport.stream(nodes.spliterator(), false) + .map(element -> new AbstractMap.SimpleImmutableEntry<>(element, selector.match(element))) + .filter(entry -> entry.getValue().isMatch()); + + if (FabricUtil.getCompatibility(mixin) >= FabricUtil.COMPATIBILITY_0_17_4) { + stream = stream.sorted(Comparator., MatchResult>, Boolean>comparing(entry -> entry.getValue().isExactMatch()).reversed()); } - - if (matchCount < selector.getMinMatchCount()) { + + List, MatchResult>> matches = stream + .limit(selector.getMaxMatchCount()) + .collect(Collectors.toList()); + + for (Map.Entry, MatchResult> match : matches) { + candidates.add(match.getKey()); + } + + if (matches.size() < selector.getMinMatchCount()) { throw new SelectorConstraintException(selector, String.format("%s did not match the required number of targets (required=%d, matched=%d)", - selector, selector.getMinMatchCount(), matchCount)); + selector, selector.getMinMatchCount(), matches.size())); } - return exactMatch; + return matches.stream().filter(entry -> entry.getValue().isExactMatch()).findFirst().map(Map.Entry::getKey).orElse(null); } } diff --git a/src/main/java/org/spongepowered/asm/mixin/injection/selectors/TargetSelectors.java b/src/main/java/org/spongepowered/asm/mixin/injection/selectors/TargetSelectors.java index b46ee143e..0fee945ac 100644 --- a/src/main/java/org/spongepowered/asm/mixin/injection/selectors/TargetSelectors.java +++ b/src/main/java/org/spongepowered/asm/mixin/injection/selectors/TargetSelectors.java @@ -269,7 +269,7 @@ protected void findNestedTargets() { } recursed = true; - Result result = TargetSelector.run(next, ElementNode.dynamicInsnList(target.getMethod().instructions)); + Result result = TargetSelector.run(this.mixin, next, ElementNode.dynamicInsnList(target.getMethod().instructions)); iter.remove(); for (ElementNode candidate : result.candidates) { if (candidate.getInsn().getOpcode() != Opcodes.INVOKEDYNAMIC) {