Skip to content

Commit 269165f

Browse files
authored
Support method arg name remapping in @ModifyVariable (#160)
* feat: ModifyVariable lvt remap * change: allow disabling local variable tracking * fix: checkstyle
1 parent c9461d6 commit 269165f

File tree

12 files changed

+359
-8
lines changed

12 files changed

+359
-8
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2016, 2018, Player, asie
3+
* Copyright (c) 2026, FabricMC
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
package net.fabricmc.tinyremapper;
20+
21+
import net.fabricmc.tinyremapper.api.TrLocal;
22+
import net.fabricmc.tinyremapper.api.TrMethod;
23+
24+
public class LocalInstance implements TrLocal {
25+
public LocalInstance(TrMethod owner, String name, String desc, int index) {
26+
this.owner = owner;
27+
this.name = name;
28+
this.desc = desc;
29+
this.index = index;
30+
}
31+
32+
@Override
33+
public String getName() {
34+
return this.name;
35+
}
36+
37+
@Override
38+
public String getDesc() {
39+
return this.desc;
40+
}
41+
42+
@Override
43+
public int getIndex() {
44+
return this.index;
45+
}
46+
47+
@Override
48+
public TrMethod getOwner() {
49+
return this.owner;
50+
}
51+
52+
final TrMethod owner;
53+
final String name;
54+
final String desc;
55+
final int index;
56+
}

src/main/java/net/fabricmc/tinyremapper/Main.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public static void main(String[] rawArgs) {
6161
boolean renameInvalidLocals = false;
6262
Pattern invalidLvNamePattern = null;
6363
boolean inferNameFromSameLvIndex = false;
64+
boolean disableLocalVariableTracking = false;
6465
NonClassCopyMode ncCopyMode = NonClassCopyMode.FIX_META_INF;
6566
int threads = -1;
6667

@@ -132,6 +133,9 @@ public static void main(String[] rawArgs) {
132133
case "infernamefromsamelvindex":
133134
inferNameFromSameLvIndex = true;
134135
break;
136+
case "disablelocalvariabletracking":
137+
disableLocalVariableTracking = true;
138+
break;
135139
case "nonclasscopymode":
136140
switch (arg.substring(valueSepPos + 1).toLowerCase(Locale.ENGLISH)) {
137141
case "unchanged": ncCopyMode = NonClassCopyMode.UNCHANGED; break;
@@ -270,6 +274,7 @@ public static void main(String[] rawArgs) {
270274
.renameInvalidLocals(renameInvalidLocals)
271275
.invalidLvNamePattern(invalidLvNamePattern)
272276
.inferNameFromSameLvIndex(inferNameFromSameLvIndex)
277+
.disableLocalVariableTracking(disableLocalVariableTracking)
273278
.threads(threads);
274279

275280
for (TinyRemapper.Extension ext : providedExtensions) {

src/main/java/net/fabricmc/tinyremapper/MemberInstance.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import net.fabricmc.tinyremapper.TinyRemapper.MrjState;
2626
import net.fabricmc.tinyremapper.api.TrClass;
2727
import net.fabricmc.tinyremapper.api.TrField;
28+
import net.fabricmc.tinyremapper.api.TrLocal;
2829
import net.fabricmc.tinyremapper.api.TrMember;
2930
import net.fabricmc.tinyremapper.api.TrMethod;
3031

@@ -68,6 +69,11 @@ public int getIndex() {
6869
return index;
6970
}
7071

72+
@Override
73+
public TrLocal[] getLocals() {
74+
return this.locals.clone();
75+
}
76+
7177
public MrjState getContext() {
7278
return cls.getContext();
7379
}
@@ -113,6 +119,10 @@ public void forceSetNewName(String name) {
113119
newName = name;
114120
}
115121

122+
public void setLocals(TrLocal[] locals) {
123+
this.locals = locals.clone();
124+
}
125+
116126
@Override
117127
public String toString() {
118128
return String.format("%s/%s%s", cls.getName(), name, desc);
@@ -151,6 +161,7 @@ public static String getNameFromId(TrMember.MemberType type, String id, boolean
151161
final String desc;
152162
final int access;
153163
final int index;
164+
TrLocal[] locals;
154165
private volatile String newName;
155166
private volatile String newBridgedName;
156167
String newNameOriginatingCls;

src/main/java/net/fabricmc/tinyremapper/TinyRemapper.java

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import org.objectweb.asm.ClassVisitor;
5858
import org.objectweb.asm.ClassWriter;
5959
import org.objectweb.asm.FieldVisitor;
60+
import org.objectweb.asm.Label;
6061
import org.objectweb.asm.MethodVisitor;
6162
import org.objectweb.asm.Opcodes;
6263
import org.objectweb.asm.RecordComponentVisitor;
@@ -67,9 +68,11 @@
6768
import net.fabricmc.tinyremapper.IMappingProvider.Member;
6869
import net.fabricmc.tinyremapper.api.TrClass;
6970
import net.fabricmc.tinyremapper.api.TrEnvironment;
71+
import net.fabricmc.tinyremapper.api.TrLocal;
7072
import net.fabricmc.tinyremapper.api.TrLogger;
7173
import net.fabricmc.tinyremapper.api.TrMember;
7274
import net.fabricmc.tinyremapper.api.TrMember.MemberType;
75+
import net.fabricmc.tinyremapper.extension.mixin.common.data.Constant;
7376

7477
public class TinyRemapper {
7578
public static class Builder {
@@ -183,6 +186,14 @@ public Builder inferNameFromSameLvIndex(boolean value) {
183186
return this;
184187
}
185188

189+
/**
190+
* Whether to disable the tracking of local variable names, used in ModifyVariable local name remapping.
191+
*/
192+
public Builder disableLocalVariableTracking(boolean value) {
193+
this.disableLocalVariableTracking = value;
194+
return this;
195+
}
196+
186197
@Deprecated
187198
public Builder extraAnalyzeVisitor(ClassVisitor visitor) {
188199
return extraAnalyzeVisitor((mrjVersion, className, next) -> {
@@ -233,7 +244,7 @@ public TinyRemapper build() {
233244
propagateBridges, propagateRecordComponents,
234245
removeFrames, ignoreConflicts, resolveMissing, checkPackageAccess || fixPackageAccess, fixPackageAccess,
235246
rebuildSourceFilenames, skipLocalMapping, renameInvalidLocals, invalidLvNamePattern, inferNameFromSameLvIndex,
236-
analyzeVisitors, stateProcessors, preApplyVisitors, postApplyVisitors,
247+
disableLocalVariableTracking || skipLocalMapping, analyzeVisitors, stateProcessors, preApplyVisitors, postApplyVisitors,
237248
extraRemapper, logger);
238249

239250
return remapper;
@@ -258,6 +269,7 @@ public TinyRemapper build() {
258269
private boolean renameInvalidLocals = false;
259270
private Pattern invalidLvNamePattern;
260271
private boolean inferNameFromSameLvIndex;
272+
private boolean disableLocalVariableTracking = false;
261273
private final List<AnalyzeVisitorProvider> analyzeVisitors = new ArrayList<>();
262274
private final List<StateProcessor> stateProcessors = new ArrayList<>();
263275
private final List<ApplyVisitorProvider> preApplyVisitors = new ArrayList<>();
@@ -321,6 +333,7 @@ private TinyRemapper(Collection<IMappingProvider> mappingProviders, boolean igno
321333
boolean rebuildSourceFilenames,
322334
boolean skipLocalMapping,
323335
boolean renameInvalidLocals, Pattern invalidLvNamePattern, boolean inferNameFromSameLvIndex,
336+
boolean disableLocalVariableTracking,
324337
List<AnalyzeVisitorProvider> analyzeVisitors, List<StateProcessor> stateProcessors,
325338
List<ApplyVisitorProvider> preApplyVisitors, List<ApplyVisitorProvider> postApplyVisitors,
326339
Remapper extraRemapper, TrLogger logger) {
@@ -345,6 +358,7 @@ private TinyRemapper(Collection<IMappingProvider> mappingProviders, boolean igno
345358
this.renameInvalidLocals = renameInvalidLocals;
346359
this.invalidLvNamePattern = invalidLvNamePattern;
347360
this.inferNameFromSameLvIndex = inferNameFromSameLvIndex;
361+
this.disableLocalVariableTracking = disableLocalVariableTracking;
348362
this.analyzeVisitors = analyzeVisitors;
349363
this.stateProcessors = stateProcessors;
350364
this.preApplyVisitors = preApplyVisitors;
@@ -643,10 +657,29 @@ public void visit(int version, int access, String name, String signature, String
643657

644658
@Override
645659
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
646-
MemberInstance prev = ret.addMember(new MemberInstance(TrMember.MemberType.METHOD, ret, name, desc, access, ret.getMembers().size()));
660+
MemberInstance member = new MemberInstance(MemberType.METHOD, ret, name, desc, access, ret.getMembers().size());
661+
MemberInstance prev = ret.addMember(member);
647662
if (prev != null) throw new RuntimeException(String.format("duplicate method %s/%s%s in inputs", ret.getName(), name, desc));
648663

649-
return super.visitMethod(access, name, desc, signature, exceptions);
664+
if (TinyRemapper.this.disableLocalVariableTracking) {
665+
return super.visitMethod(access, name, desc, signature, exceptions);
666+
} else {
667+
return new MethodVisitor(Constant.ASM_VERSION, super.visitMethod(access, name, desc, signature, exceptions)) {
668+
final List<TrLocal> locals = new ArrayList<>();
669+
670+
@Override
671+
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
672+
this.locals.add(new LocalInstance(member, name, descriptor, index));
673+
super.visitLocalVariable(name, descriptor, signature, start, end, index);
674+
}
675+
676+
@Override
677+
public void visitEnd() {
678+
member.setLocals(locals.toArray(new TrLocal[0]));
679+
super.visitEnd();
680+
}
681+
};
682+
}
650683
}
651684

652685
@Override
@@ -662,7 +695,11 @@ public FieldVisitor visitField(int access, String name, String desc, String sign
662695
cv = analyzeVisitors.get(i).insertAnalyzeVisitor(isInput, mrjVersion, name, cv, tags);
663696
}
664697

665-
reader.accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE);
698+
if (this.disableLocalVariableTracking) {
699+
reader.accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE);
700+
} else {
701+
reader.accept(cv, ClassReader.SKIP_FRAMES);
702+
}
666703

667704
return ret;
668705
}
@@ -1454,6 +1491,7 @@ public void propagate(TrMember m, String newName) {
14541491
private final boolean renameInvalidLocals;
14551492
private final Pattern invalidLvNamePattern;
14561493
private final boolean inferNameFromSameLvIndex;
1494+
private final boolean disableLocalVariableTracking;
14571495
private final List<AnalyzeVisitorProvider> analyzeVisitors;
14581496
private final List<StateProcessor> stateProcessors;
14591497
private final List<ApplyVisitorProvider> preApplyVisitors;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2016, 2018, Player, asie
3+
* Copyright (c) 2026, FabricMC
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
package net.fabricmc.tinyremapper.api;
20+
21+
public interface TrLocal {
22+
String getName();
23+
String getDesc();
24+
int getIndex();
25+
TrMethod getOwner();
26+
}

src/main/java/net/fabricmc/tinyremapper/api/TrMethod.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,6 @@ default boolean isAbstract() {
4848
default boolean isVirtual() {
4949
return getType().equals(MemberType.METHOD) && (getAccess() & (Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE)) == 0;
5050
}
51+
52+
TrLocal[] getLocals();
5153
}

src/main/java/net/fabricmc/tinyremapper/extension/mixin/common/data/AnnotationElement.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public final class AnnotationElement {
3434
public static final String TO = "to";
3535
public static final String SLICE = "slice";
3636
public static final String METHOD = "method";
37+
public static final String NAME = "name";
3738
public static final String DEFINITION_METHOD = "method";
3839
public static final String DEFINITION_FIELD = "field";
3940
}

src/main/java/net/fabricmc/tinyremapper/extension/mixin/soft/annotation/injection/CommonInjectionAnnotationVisitor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646
* method with the first occurrence in ASM will be remapped.
4747
*/
4848
class CommonInjectionAnnotationVisitor extends AnnotationVisitor {
49-
private final CommonData data;
50-
private final List<String> targets;
49+
protected final CommonData data;
50+
protected final List<String> targets;
5151

5252
CommonInjectionAnnotationVisitor(CommonData data, AnnotationVisitor delegate, List<String> targets) {
5353
super(Constant.ASM_VERSION, Objects.requireNonNull(delegate));

0 commit comments

Comments
 (0)