diff --git a/src/main/java/net/fabricmc/tinyremapper/LocalInstance.java b/src/main/java/net/fabricmc/tinyremapper/LocalInstance.java new file mode 100644 index 00000000..c36037e9 --- /dev/null +++ b/src/main/java/net/fabricmc/tinyremapper/LocalInstance.java @@ -0,0 +1,56 @@ +/* + * 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; + +import net.fabricmc.tinyremapper.api.TrLocal; +import net.fabricmc.tinyremapper.api.TrMethod; + +public class LocalInstance implements TrLocal { + public LocalInstance(TrMethod owner, String name, String desc, int index) { + this.owner = owner; + this.name = name; + this.desc = desc; + this.index = index; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getDesc() { + return this.desc; + } + + @Override + public int getIndex() { + return this.index; + } + + @Override + public TrMethod getOwner() { + return this.owner; + } + + final TrMethod owner; + final String name; + final String desc; + final int index; +} diff --git a/src/main/java/net/fabricmc/tinyremapper/Main.java b/src/main/java/net/fabricmc/tinyremapper/Main.java index 727f8f38..da218771 100644 --- a/src/main/java/net/fabricmc/tinyremapper/Main.java +++ b/src/main/java/net/fabricmc/tinyremapper/Main.java @@ -61,6 +61,7 @@ public static void main(String[] rawArgs) { boolean renameInvalidLocals = false; Pattern invalidLvNamePattern = null; boolean inferNameFromSameLvIndex = false; + boolean disableLocalVariableTracking = false; NonClassCopyMode ncCopyMode = NonClassCopyMode.FIX_META_INF; int threads = -1; @@ -132,6 +133,9 @@ public static void main(String[] rawArgs) { case "infernamefromsamelvindex": inferNameFromSameLvIndex = true; break; + case "disablelocalvariabletracking": + disableLocalVariableTracking = true; + break; case "nonclasscopymode": switch (arg.substring(valueSepPos + 1).toLowerCase(Locale.ENGLISH)) { case "unchanged": ncCopyMode = NonClassCopyMode.UNCHANGED; break; @@ -270,6 +274,7 @@ public static void main(String[] rawArgs) { .renameInvalidLocals(renameInvalidLocals) .invalidLvNamePattern(invalidLvNamePattern) .inferNameFromSameLvIndex(inferNameFromSameLvIndex) + .disableLocalVariableTracking(disableLocalVariableTracking) .threads(threads); for (TinyRemapper.Extension ext : providedExtensions) { diff --git a/src/main/java/net/fabricmc/tinyremapper/MemberInstance.java b/src/main/java/net/fabricmc/tinyremapper/MemberInstance.java index dd312d86..6c3a551d 100644 --- a/src/main/java/net/fabricmc/tinyremapper/MemberInstance.java +++ b/src/main/java/net/fabricmc/tinyremapper/MemberInstance.java @@ -25,6 +25,7 @@ import net.fabricmc.tinyremapper.TinyRemapper.MrjState; import net.fabricmc.tinyremapper.api.TrClass; import net.fabricmc.tinyremapper.api.TrField; +import net.fabricmc.tinyremapper.api.TrLocal; import net.fabricmc.tinyremapper.api.TrMember; import net.fabricmc.tinyremapper.api.TrMethod; @@ -68,6 +69,11 @@ public int getIndex() { return index; } + @Override + public TrLocal[] getLocals() { + return this.locals.clone(); + } + public MrjState getContext() { return cls.getContext(); } @@ -113,6 +119,10 @@ public void forceSetNewName(String name) { newName = name; } + public void setLocals(TrLocal[] locals) { + this.locals = locals.clone(); + } + @Override public String toString() { return String.format("%s/%s%s", cls.getName(), name, desc); @@ -151,6 +161,7 @@ public static String getNameFromId(TrMember.MemberType type, String id, boolean final String desc; final int access; final int index; + TrLocal[] locals; private volatile String newName; private volatile String newBridgedName; String newNameOriginatingCls; diff --git a/src/main/java/net/fabricmc/tinyremapper/TinyRemapper.java b/src/main/java/net/fabricmc/tinyremapper/TinyRemapper.java index 998e4936..89b3dd80 100644 --- a/src/main/java/net/fabricmc/tinyremapper/TinyRemapper.java +++ b/src/main/java/net/fabricmc/tinyremapper/TinyRemapper.java @@ -57,6 +57,7 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.RecordComponentVisitor; @@ -67,9 +68,11 @@ import net.fabricmc.tinyremapper.IMappingProvider.Member; import net.fabricmc.tinyremapper.api.TrClass; import net.fabricmc.tinyremapper.api.TrEnvironment; +import net.fabricmc.tinyremapper.api.TrLocal; import net.fabricmc.tinyremapper.api.TrLogger; import net.fabricmc.tinyremapper.api.TrMember; import net.fabricmc.tinyremapper.api.TrMember.MemberType; +import net.fabricmc.tinyremapper.extension.mixin.common.data.Constant; public class TinyRemapper { public static class Builder { @@ -183,6 +186,14 @@ public Builder inferNameFromSameLvIndex(boolean value) { return this; } + /** + * Whether to disable the tracking of local variable names, used in ModifyVariable local name remapping. + */ + public Builder disableLocalVariableTracking(boolean value) { + this.disableLocalVariableTracking = value; + return this; + } + @Deprecated public Builder extraAnalyzeVisitor(ClassVisitor visitor) { return extraAnalyzeVisitor((mrjVersion, className, next) -> { @@ -233,7 +244,7 @@ public TinyRemapper build() { propagateBridges, propagateRecordComponents, removeFrames, ignoreConflicts, resolveMissing, checkPackageAccess || fixPackageAccess, fixPackageAccess, rebuildSourceFilenames, skipLocalMapping, renameInvalidLocals, invalidLvNamePattern, inferNameFromSameLvIndex, - analyzeVisitors, stateProcessors, preApplyVisitors, postApplyVisitors, + disableLocalVariableTracking || skipLocalMapping, analyzeVisitors, stateProcessors, preApplyVisitors, postApplyVisitors, extraRemapper, logger); return remapper; @@ -258,6 +269,7 @@ public TinyRemapper build() { private boolean renameInvalidLocals = false; private Pattern invalidLvNamePattern; private boolean inferNameFromSameLvIndex; + private boolean disableLocalVariableTracking = false; private final List analyzeVisitors = new ArrayList<>(); private final List stateProcessors = new ArrayList<>(); private final List preApplyVisitors = new ArrayList<>(); @@ -321,6 +333,7 @@ private TinyRemapper(Collection mappingProviders, boolean igno boolean rebuildSourceFilenames, boolean skipLocalMapping, boolean renameInvalidLocals, Pattern invalidLvNamePattern, boolean inferNameFromSameLvIndex, + boolean disableLocalVariableTracking, List analyzeVisitors, List stateProcessors, List preApplyVisitors, List postApplyVisitors, Remapper extraRemapper, TrLogger logger) { @@ -345,6 +358,7 @@ private TinyRemapper(Collection mappingProviders, boolean igno this.renameInvalidLocals = renameInvalidLocals; this.invalidLvNamePattern = invalidLvNamePattern; this.inferNameFromSameLvIndex = inferNameFromSameLvIndex; + this.disableLocalVariableTracking = disableLocalVariableTracking; this.analyzeVisitors = analyzeVisitors; this.stateProcessors = stateProcessors; this.preApplyVisitors = preApplyVisitors; @@ -643,10 +657,29 @@ public void visit(int version, int access, String name, String signature, String @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - MemberInstance prev = ret.addMember(new MemberInstance(TrMember.MemberType.METHOD, ret, name, desc, access, ret.getMembers().size())); + MemberInstance member = new MemberInstance(MemberType.METHOD, ret, name, desc, access, ret.getMembers().size()); + MemberInstance prev = ret.addMember(member); if (prev != null) throw new RuntimeException(String.format("duplicate method %s/%s%s in inputs", ret.getName(), name, desc)); - return super.visitMethod(access, name, desc, signature, exceptions); + if (TinyRemapper.this.disableLocalVariableTracking) { + return super.visitMethod(access, name, desc, signature, exceptions); + } else { + return new MethodVisitor(Constant.ASM_VERSION, super.visitMethod(access, name, desc, signature, exceptions)) { + final List locals = new ArrayList<>(); + + @Override + public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) { + this.locals.add(new LocalInstance(member, name, descriptor, index)); + super.visitLocalVariable(name, descriptor, signature, start, end, index); + } + + @Override + public void visitEnd() { + member.setLocals(locals.toArray(new TrLocal[0])); + super.visitEnd(); + } + }; + } } @Override @@ -662,7 +695,11 @@ public FieldVisitor visitField(int access, String name, String desc, String sign cv = analyzeVisitors.get(i).insertAnalyzeVisitor(isInput, mrjVersion, name, cv, tags); } - reader.accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE); + if (this.disableLocalVariableTracking) { + reader.accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE); + } else { + reader.accept(cv, ClassReader.SKIP_FRAMES); + } return ret; } @@ -1454,6 +1491,7 @@ public void propagate(TrMember m, String newName) { private final boolean renameInvalidLocals; private final Pattern invalidLvNamePattern; private final boolean inferNameFromSameLvIndex; + private final boolean disableLocalVariableTracking; private final List analyzeVisitors; private final List stateProcessors; private final List preApplyVisitors; diff --git a/src/main/java/net/fabricmc/tinyremapper/api/TrLocal.java b/src/main/java/net/fabricmc/tinyremapper/api/TrLocal.java new file mode 100644 index 00000000..eb74f0c9 --- /dev/null +++ b/src/main/java/net/fabricmc/tinyremapper/api/TrLocal.java @@ -0,0 +1,26 @@ +/* + * 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.api; + +public interface TrLocal { + String getName(); + String getDesc(); + int getIndex(); + TrMethod getOwner(); +} diff --git a/src/main/java/net/fabricmc/tinyremapper/api/TrMethod.java b/src/main/java/net/fabricmc/tinyremapper/api/TrMethod.java index 13ee30f0..03c50b2f 100644 --- a/src/main/java/net/fabricmc/tinyremapper/api/TrMethod.java +++ b/src/main/java/net/fabricmc/tinyremapper/api/TrMethod.java @@ -48,4 +48,6 @@ default boolean isAbstract() { default boolean isVirtual() { return getType().equals(MemberType.METHOD) && (getAccess() & (Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE)) == 0; } + + TrLocal[] getLocals(); } diff --git a/src/main/java/net/fabricmc/tinyremapper/extension/mixin/common/data/AnnotationElement.java b/src/main/java/net/fabricmc/tinyremapper/extension/mixin/common/data/AnnotationElement.java index e2c60408..9d4e38f0 100644 --- a/src/main/java/net/fabricmc/tinyremapper/extension/mixin/common/data/AnnotationElement.java +++ b/src/main/java/net/fabricmc/tinyremapper/extension/mixin/common/data/AnnotationElement.java @@ -34,6 +34,7 @@ public final class AnnotationElement { public static final String TO = "to"; public static final String SLICE = "slice"; public static final String METHOD = "method"; + public static final String NAME = "name"; public static final String DEFINITION_METHOD = "method"; public static final String DEFINITION_FIELD = "field"; } 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 47a531a3..5ac80e2a 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 @@ -46,8 +46,8 @@ * method with the first occurrence in ASM will be remapped. */ class CommonInjectionAnnotationVisitor extends AnnotationVisitor { - private final CommonData data; - private final List targets; + protected final CommonData data; + protected final List targets; CommonInjectionAnnotationVisitor(CommonData data, AnnotationVisitor delegate, List targets) { super(Constant.ASM_VERSION, Objects.requireNonNull(delegate)); diff --git a/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/annotation/injection/ModifyVariableAnnotationVisitor.java b/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/annotation/injection/ModifyVariableAnnotationVisitor.java index 8dc6714b..34286209 100644 --- a/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/annotation/injection/ModifyVariableAnnotationVisitor.java +++ b/src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/annotation/injection/ModifyVariableAnnotationVisitor.java @@ -18,14 +18,151 @@ package net.fabricmc.tinyremapper.extension.mixin.soft.annotation.injection; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.tree.AnnotationNode; +import net.fabricmc.tinyremapper.api.TrClass; +import net.fabricmc.tinyremapper.api.TrLocal; +import net.fabricmc.tinyremapper.api.TrMethod; +import net.fabricmc.tinyremapper.extension.mixin.common.ResolveUtility; +import net.fabricmc.tinyremapper.extension.mixin.common.data.Annotation; +import net.fabricmc.tinyremapper.extension.mixin.common.data.AnnotationElement; import net.fabricmc.tinyremapper.extension.mixin.common.data.CommonData; +import net.fabricmc.tinyremapper.extension.mixin.common.data.Constant; +import net.fabricmc.tinyremapper.extension.mixin.common.data.Message; +import net.fabricmc.tinyremapper.extension.mixin.soft.data.MemberInfo; + +public class ModifyVariableAnnotationVisitor extends AnnotationNode { + private final CommonData data; + private final AnnotationVisitor delegate; + private final List targets; + + private final List methods = new ArrayList<>(); -public class ModifyVariableAnnotationVisitor extends CommonInjectionAnnotationVisitor { public ModifyVariableAnnotationVisitor(CommonData data, AnnotationVisitor delegate, List targets) { - super(data, delegate, targets); + super(Constant.ASM_VERSION, Annotation.MODIFY_VARIABLE); + this.data = Objects.requireNonNull(data); + this.delegate = Objects.requireNonNull(delegate); + this.targets = Objects.requireNonNull(targets); + } + + @Override + public AnnotationVisitor visitArray(String name) { + AnnotationVisitor av = super.visitArray(name); + + if (name.equals(AnnotationElement.METHOD)) { + return new AnnotationVisitor(Constant.ASM_VERSION, av) { + @Override + public void visit(String name, Object value) { + MemberInfo info = MemberInfo.parse(Objects.requireNonNull((String) value).replaceAll("\\s", "")); + + if (info != null && (info.getOwner().isEmpty() || ModifyVariableAnnotationVisitor.this.targets.contains(info.getOwner()))) { + ModifyVariableAnnotationVisitor.this.methods.add(info); + } + + super.visit(name, value); + } + }; + } + + return av; + } + + @Override + public void visitEnd() { + this.accept(new ModifyVariableSecondPassAnnotationVisitor(this.data, this.delegate, this.targets, this.methods)); + + super.visitEnd(); + } + + private static class ModifyVariableSecondPassAnnotationVisitor extends CommonInjectionAnnotationVisitor { + private final List methods; + private final List targets; + + ModifyVariableSecondPassAnnotationVisitor(CommonData data, AnnotationVisitor delegate, List targets, List methods) { + super(data, delegate, targets); + this.methods = methods; + this.targets = Objects.requireNonNull(targets).stream() + .map(data.resolver::resolveClass) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + } + + @Override + public AnnotationVisitor visitArray(String name) { + AnnotationVisitor av = super.visitArray(name); + + if (name.equals(AnnotationElement.NAME)) { + return new AnnotationVisitor(Constant.ASM_VERSION, av) { + @Override + public void visit(String name, Object value) { + String localName = Objects.requireNonNull((String) value).replaceAll("\\s", ""); + + List collection = targets.stream() + .flatMap(target -> methods.stream().map(info -> resolvePartial(target, info.getName(), info.getDesc()))) + .filter(Optional::isPresent) + .map(Optional::get) + .map(m -> { + TrLocal[] localVariables = m.getLocals(); + + if (localVariables == null || localVariables.length == 0) { + return localName; + } + + Map lvtName2Index = new HashMap<>(); + + for (TrLocal variable : localVariables) { + if (!lvtName2Index.containsKey(variable.getName())) { + lvtName2Index.put(variable.getName(), variable.getIndex()); + } else { + lvtName2Index.put(variable.getName(), -1); // TODO actually generate lvt for injection points, currently only handles unique names + } + } + + if (!lvtName2Index.containsKey(localName)) { + return localName; + } + + int lvIndex = lvtName2Index.get(localName); + + if (lvIndex < 0) { + return localName; + } + + return data.mapper.asTrRemapper().mapMethodArg(m.getOwner().getName(), m.getName(), m.getDesc(), lvIndex, localName); + }) + .distinct().collect(Collectors.toList()); + + if (collection.size() > 1) { + data.getLogger().error(Message.CONFLICT_MAPPING, localName, collection); + } else if (collection.isEmpty()) { + data.getLogger().warn(Message.NO_MAPPING_NON_RECURSIVE, localName, targets); + } + + super.visit(name, collection.stream().findFirst().orElse(localName)); + } + }; + } + + return av; + } + + private Optional resolvePartial(TrClass owner, String name, String desc) { + Objects.requireNonNull(owner); + + name = name.isEmpty() ? null : name; + desc = desc.isEmpty() ? null : desc; + + return data.resolver.resolveMethod(owner, name, desc, ResolveUtility.FLAG_FIRST | ResolveUtility.FLAG_NON_SYN).map(m -> m); + } } } diff --git a/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/MixinIntegrationTest.java b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/MixinIntegrationTest.java index 576f768c..62a27206 100644 --- a/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/MixinIntegrationTest.java +++ b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/MixinIntegrationTest.java @@ -42,9 +42,11 @@ import net.fabricmc.tinyremapper.TinyRemapper; import net.fabricmc.tinyremapper.extension.mixin.MixinExtension; import net.fabricmc.tinyremapper.extension.mixin.integration.mixins.AmbiguousRemappedNameMixin; +import net.fabricmc.tinyremapper.extension.mixin.integration.mixins.LvtRemapTargetMixin; import net.fabricmc.tinyremapper.extension.mixin.integration.mixins.NonObfuscatedOverrideMixin; import net.fabricmc.tinyremapper.extension.mixin.integration.mixins.WildcardTargetMixin; import net.fabricmc.tinyremapper.extension.mixin.integration.targets.AmbiguousRemappedNameTarget; +import net.fabricmc.tinyremapper.extension.mixin.integration.targets.LvtRemapTarget; import net.fabricmc.tinyremapper.extension.mixin.integration.targets.NonObfuscatedOverrideTarget; import net.fabricmc.tinyremapper.extension.mixin.integration.targets.WildcardTarget; @@ -91,6 +93,22 @@ public void remapAmbiuousRemappedName() throws IOException { assertTrue(remapped.contains("@Lorg/spongepowered/asm/mixin/injection/Inject;(method={\"add(Ljava/lang/String;)V\"")); } + @Test + public void remapLvtName() throws IOException { + String remapped = remap(LvtRemapTarget.class, LvtRemapTargetMixin.class, out -> { + String fqn = "net/fabricmc/tinyremapper/extension/mixin/integration/targets/LvtRemapTarget"; + out.acceptClass(fqn, "com/example/Remapped"); + IMappingProvider.Member member = new IMappingProvider.Member(fqn, "target", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + out.acceptMethod(member, "targetRemapped"); + out.acceptMethodArg(member, 1, "remappedStr1"); + out.acceptMethodArg(member, 2, "remappedStr2"); + out.acceptMethodArg(member, 3, "remappedStr3"); + out.acceptMethodArg(member, 4, "remappedStr4"); + }); + + assertTrue(remapped.contains("@Lorg/spongepowered/asm/mixin/injection/ModifyVariable;(method={\"targetRemapped\"}, at=@Lorg/spongepowered/asm/mixin/injection/At;(value=\"HEAD\"), name={\"remappedStr3\"})")); + } + 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/LvtRemapTargetMixin.java b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/mixins/LvtRemapTargetMixin.java new file mode 100644 index 00000000..5e94b6af --- /dev/null +++ b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/mixins/LvtRemapTargetMixin.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.ModifyVariable; + +import net.fabricmc.tinyremapper.extension.mixin.integration.targets.LvtRemapTarget; + +@Mixin(LvtRemapTarget.class) +public class LvtRemapTargetMixin { + @ModifyVariable(method = "target", at = @At("HEAD"), name = "str3") + private String modifyStr3(String str3) { + return "noice"; + } +} diff --git a/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/targets/LvtRemapTarget.java b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/targets/LvtRemapTarget.java new file mode 100644 index 00000000..f1d461d8 --- /dev/null +++ b/src/test/java/net/fabricmc/tinyremapper/extension/mixin/integration/targets/LvtRemapTarget.java @@ -0,0 +1,24 @@ +/* + * 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; + +public class LvtRemapTarget { + public void target(String str1, String str2, String str3, String str4) { + } +}