diff --git a/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/annotation/injection/CommonInjectionAnnotationVisitor.java b/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/annotation/injection/CommonInjectionAnnotationVisitor.java index 3722a6ca..e03e1737 100644 --- a/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/annotation/injection/CommonInjectionAnnotationVisitor.java +++ b/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/annotation/injection/CommonInjectionAnnotationVisitor.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -48,6 +49,7 @@ import net.fabricmc.tinyremapper.extension.mixin.common.data.Message; import net.fabricmc.tinyremapper.extension.mixin.common.data.Pair; import net.fabricmc.tinyremapper.extension.mixin.soft.data.MemberInfo; +import net.fabricmc.tinyremapper.extension.mixin.soft.util.RegexMatcher; /** * If the {@code method} element does not contain a name, then do not remap it; If the @@ -96,6 +98,21 @@ public AnnotationVisitor visitArray(String name) { public void visit(String name, Object value) { String string = Objects.requireNonNull((String) value); + // ending slash -> regex target + if (string.endsWith("/")) { + List resolved = resolveAndRemapMixinRegex(string); + + if (resolved == null) { + super.visit(name, value); + } else { + for (String remappedSelector : resolved) { + super.visit(name, remappedSelector); + } + } + + return; + } + MemberInfo info = MemberInfo.parse(string.replaceAll("\\s", "")); if (info == null) { @@ -155,6 +172,42 @@ public AnnotationVisitor visitAnnotation(String name, String descriptor) { return av; } + private List resolveAndRemapMixinRegex(String input) { + RegexMatcher matcher; + + try { + matcher = RegexMatcher.parse(input); + } catch (RegexMatcher.ParsingException e) { + data.getLogger().warn("Error parsing mixin regex %s: %s", input, e.toString()); + return null; + } + + List matchedMethods = Objects.requireNonNull(targets).stream() + .map(data.resolver::resolveClass) + .filter(Optional::isPresent) + .map(Optional::get) + .flatMap(trClass -> trClass.getMethods().stream()) + .filter(trMethod -> matcher.matches(trMethod.getOwner().getName(), trMethod.getName(), trMethod.getDesc())) + .sorted( + Comparator + .comparing(trMethod -> trMethod.getOwner().getName()) + .thenComparing(TrMember::getName) + .thenComparing(TrMember::getDesc) + ) + .collect(Collectors.toList()); + + List result = new ArrayList<>(); + + for (TrMethod matchedMethod : matchedMethods) { + String mappedOwner = data.mapper.mapName(matchedMethod.getOwner()); + String mappedName = data.mapper.mapName(matchedMethod); + String mappedDesc = data.mapper.mapDesc(matchedMethod); + result.add(String.format("L%s;%s%s", mappedOwner, mappedName, mappedDesc)); + } + + return result; + } + private static class InjectMethodMappable implements IMappable> { private final CommonData data; private final MemberInfo info; diff --git a/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/util/RegexMatcher.java b/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/util/RegexMatcher.java new file mode 100644 index 00000000..6c65eecd --- /dev/null +++ b/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/util/RegexMatcher.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, 2018, Player, asie + * Copyright (c) 2026, FabricMC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package net.fabricmc.tinyremapper.extension.mixin.soft.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class RegexMatcher { + private static final Pattern PATTERN = Pattern.compile("((owner|name|desc)\\s*=\\s*)?/(.*?)(? { + String fqn = "net/fabricmc/tinyremapper/extension/mixin/integration/targets/RegexMethodTarget"; + out.acceptClass(fqn, "com/example/Remapped"); + out.acceptMethod(new IMappingProvider.Member(fqn, "target0", "()Ljava/lang/String;"), "t0"); + out.acceptMethod(new IMappingProvider.Member(fqn, "target0", "(Ljava/lang/String;)Ljava/lang/String;"), "t00"); + out.acceptMethod(new IMappingProvider.Member(fqn, "target1", "()Ljava/lang/String;"), "t1"); + out.acceptMethod(new IMappingProvider.Member(fqn, "target2", "(Ljava/util/List;)Ljava/lang/String;"), "t2"); + out.acceptMethod(new IMappingProvider.Member(fqn, "target3", "(Ljava/lang/String;)V"), "t3"); + out.acceptMethod(new IMappingProvider.Member(fqn, "thing4", "()Ljava/lang/String;"), "thing"); + }); + + assertTrue(remapped.contains("method={\"Lcom/example/Remapped;t0()Ljava/lang/String;\", \"Lcom/example/Remapped;t00(Ljava/lang/String;)Ljava/lang/String;\", \"Lcom/example/Remapped;t1()Ljava/lang/String;\", \"Lcom/example/Remapped;t2(Ljava/util/List;)Ljava/lang/String;\"}")); + } + private String remap(Class target, Class mixin, IMappingProvider mappings) throws IOException { Path classpath = createJar(target); Path input = createJar(mixin); diff --git a/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/mixins/RegexMethodTargetMixin.java b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/mixins/RegexMethodTargetMixin.java new file mode 100644 index 00000000..0e9c7066 --- /dev/null +++ b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/mixins/RegexMethodTargetMixin.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, 2018, Player, asie + * Copyright (c) 2026, FabricMC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package net.fabricmc.tinyremapper.extension.mixin.integration.mixins; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.fabricmc.tinyremapper.extension.mixin.integration.targets.RegexMethodTarget; + +@Mixin(RegexMethodTarget.class) +public class RegexMethodTargetMixin { + @Inject(method = "/^target/ desc=/String;$/", at = @At("RETURN")) + private void onTargets(CallbackInfoReturnable cir) { + } +} diff --git a/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/targets/RegexMethodTarget.java b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/targets/RegexMethodTarget.java new file mode 100644 index 00000000..5a0b88e6 --- /dev/null +++ b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/targets/RegexMethodTarget.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 2018, Player, asie + * Copyright (c) 2026, FabricMC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package net.fabricmc.tinyremapper.extension.mixin.integration.targets; + +import java.util.List; + +public class RegexMethodTarget { + private String target0() { + return "target0"; + } + + private String target0(String input) { + return input; + } + + private String target1() { + return "target1"; + } + + private String target2(List input) { + return input.toString(); + } + + private void target3(String input) { + } + + private String thing4() { + return "thing4"; + } +}