Skip to content

Commit 9f857d8

Browse files
authored
Add the ability to remap mixin annotation as an extension of tiny-remapper (FabricMC#63)
1 parent f00529c commit 9f857d8

51 files changed

Lines changed: 2964 additions & 9 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,11 @@ public Builder extraAnalyzeVisitor(ClassVisitor visitor) {
165165
}
166166

167167
public Builder extraAnalyzeVisitor(AnalyzeVisitorProvider provider) {
168-
extraAnalyzeVisitors.add(provider);
168+
analyzeVisitors.add(provider);
169169
return this;
170170
}
171171

172-
public Builder stateProcessor(StateProcessor processor) {
172+
public Builder extraStateProcessor(StateProcessor processor) {
173173
stateProcessors.add(processor);
174174
return this;
175175
}
@@ -189,14 +189,19 @@ public Builder extraPostApplyVisitor(ApplyVisitorProvider provider) {
189189
return this;
190190
}
191191

192+
public Builder extension(TinyRemapper.Extension extension) {
193+
extension.attach(this);
194+
return this;
195+
}
196+
192197
public TinyRemapper build() {
193198
TinyRemapper remapper = new TinyRemapper(mappingProviders, ignoreFieldDesc, threadCount,
194199
keepInputData,
195200
forcePropagation, propagatePrivate,
196201
propagateBridges, propagateRecordComponents,
197202
removeFrames, ignoreConflicts, resolveMissing, checkPackageAccess || fixPackageAccess, fixPackageAccess,
198203
rebuildSourceFilenames, skipLocalMapping, renameInvalidLocals,
199-
extraAnalyzeVisitors, stateProcessors, preApplyVisitors, postApplyVisitors,
204+
analyzeVisitors, stateProcessors, preApplyVisitors, postApplyVisitors,
200205
extraRemapper);
201206

202207
return remapper;
@@ -218,13 +223,17 @@ public TinyRemapper build() {
218223
private boolean rebuildSourceFilenames = false;
219224
private boolean skipLocalMapping = false;
220225
private boolean renameInvalidLocals = false;
221-
private final List<AnalyzeVisitorProvider> extraAnalyzeVisitors = new ArrayList<>();
226+
private final List<AnalyzeVisitorProvider> analyzeVisitors = new ArrayList<>();
222227
private final List<StateProcessor> stateProcessors = new ArrayList<>();
223228
private final List<ApplyVisitorProvider> preApplyVisitors = new ArrayList<>();
224229
private final List<ApplyVisitorProvider> postApplyVisitors = new ArrayList<>();
225230
private Remapper extraRemapper;
226231
}
227232

233+
public interface Extension {
234+
void attach(TinyRemapper.Builder builder);
235+
}
236+
228237
public interface AnalyzeVisitorProvider {
229238
ClassVisitor insertAnalyzeVisitor(int mrjVersion, String className, ClassVisitor next);
230239
}
@@ -250,7 +259,7 @@ private TinyRemapper(Collection<IMappingProvider> mappingProviders, boolean igno
250259
boolean rebuildSourceFilenames,
251260
boolean skipLocalMapping,
252261
boolean renameInvalidLocals,
253-
List<AnalyzeVisitorProvider> extraAnalyzeVisitors, List<StateProcessor> stateProcessors,
262+
List<AnalyzeVisitorProvider> analyzeVisitors, List<StateProcessor> stateProcessors,
254263
List<ApplyVisitorProvider> preApplyVisitors, List<ApplyVisitorProvider> postApplyVisitors,
255264
Remapper extraRemapper) {
256265
this.mappingProviders = mappingProviders;
@@ -270,7 +279,7 @@ private TinyRemapper(Collection<IMappingProvider> mappingProviders, boolean igno
270279
this.rebuildSourceFilenames = rebuildSourceFilenames;
271280
this.skipLocalMapping = skipLocalMapping;
272281
this.renameInvalidLocals = renameInvalidLocals;
273-
this.extraAnalyzeVisitors = extraAnalyzeVisitors;
282+
this.analyzeVisitors = analyzeVisitors;
274283
this.stateProcessors = stateProcessors;
275284
this.preApplyVisitors = preApplyVisitors;
276285
this.postApplyVisitors = postApplyVisitors;
@@ -549,8 +558,8 @@ public void visit(int version, int access, String name, String signature, String
549558
int mrjVersion = analyzeMrjVersion(file, name);
550559
ret.init(mrjVersion, name, signature, superName, access, interfaces);
551560

552-
for (int i = extraAnalyzeVisitors.size() - 1; i >= 0; i--) {
553-
cv = extraAnalyzeVisitors.get(i).insertAnalyzeVisitor(mrjVersion, name, cv);
561+
for (int i = analyzeVisitors.size() - 1; i >= 0; i--) {
562+
cv = analyzeVisitors.get(i).insertAnalyzeVisitor(mrjVersion, name, cv);
554563
}
555564

556565
super.visit(version, access, name, signature, superName, interfaces);
@@ -1276,7 +1285,7 @@ public void propagate(TrMember m, String newName) {
12761285
private final boolean rebuildSourceFilenames;
12771286
private final boolean skipLocalMapping;
12781287
private final boolean renameInvalidLocals;
1279-
private final List<AnalyzeVisitorProvider> extraAnalyzeVisitors;
1288+
private final List<AnalyzeVisitorProvider> analyzeVisitors;
12801289
private final List<StateProcessor> stateProcessors;
12811290
private final List<ApplyVisitorProvider> preApplyVisitors;
12821291
private final List<ApplyVisitorProvider> postApplyVisitors;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package net.fabricmc.tinyremapper.extension.mixin;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.function.Consumer;
8+
9+
import org.objectweb.asm.ClassVisitor;
10+
11+
import net.fabricmc.tinyremapper.TinyRemapper;
12+
import net.fabricmc.tinyremapper.TinyRemapper.Builder;
13+
import net.fabricmc.tinyremapper.api.TrClass;
14+
import net.fabricmc.tinyremapper.api.TrEnvironment;
15+
import net.fabricmc.tinyremapper.extension.mixin.common.Logger;
16+
import net.fabricmc.tinyremapper.extension.mixin.common.data.CommonData;
17+
import net.fabricmc.tinyremapper.extension.mixin.hard.HardTargetMixinClassVisitor;
18+
import net.fabricmc.tinyremapper.extension.mixin.soft.SoftTargetMixinClassVisitor;
19+
20+
/**
21+
* A extension for remapping mixin annotation.
22+
*/
23+
public class MixinExtension implements TinyRemapper.Extension {
24+
private final Logger logger;
25+
private final Map<Integer, List<Consumer<CommonData>>> tasks;
26+
27+
/**
28+
* Remap mixin annotation.
29+
* <p>Soft-target: Mixin, Invoker, Accessor, Inject, ModifyArg, ModifyArgs, Redirect, ModifyVariable, ModifyConstant, At, Slice.</p>
30+
* <p>Hard-target: Shadow, Overwrite, Accessor, Invoker, Implements.</p>
31+
*/
32+
public MixinExtension() {
33+
this.logger = new Logger();
34+
this.tasks = new HashMap<>();
35+
}
36+
37+
public MixinExtension(Logger.Level logLevel) {
38+
this.logger = new Logger(logLevel);
39+
this.tasks = new HashMap<>();
40+
}
41+
42+
@Override
43+
public void attach(Builder builder) {
44+
builder.extraAnalyzeVisitor(this::analyzeVisitor)
45+
.extraStateProcessor(this::stateProcessor)
46+
.extraPreApplyVisitor(this::preApplyVisitor);
47+
}
48+
49+
/**
50+
* Hard-target: Shadow, Overwrite, Accessor, Invoker, Implements.
51+
*/
52+
private ClassVisitor analyzeVisitor(int mrjVersion, String className, ClassVisitor next) {
53+
tasks.putIfAbsent(mrjVersion, new ArrayList<>());
54+
return new HardTargetMixinClassVisitor(tasks.get(mrjVersion), next);
55+
}
56+
57+
private void stateProcessor(TrEnvironment environment) {
58+
CommonData data = new CommonData(environment, logger);
59+
tasks.get(environment.getMrjVersion()).forEach(task -> {
60+
try {
61+
task.accept(data);
62+
} catch (RuntimeException e) {
63+
logger.error(e.getMessage());
64+
}
65+
});
66+
}
67+
68+
/**
69+
* Soft-target: Mixin, Invoker, Accessor, Inject, ModifyArg, ModifyArgs, Redirect, ModifyVariable, ModifyConstant, At, Slice.
70+
*/
71+
public ClassVisitor preApplyVisitor(TrClass cls, ClassVisitor next) {
72+
return new SoftTargetMixinClassVisitor(new CommonData(cls.getEnvironment(), logger), next);
73+
}
74+
}
75+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package net.fabricmc.tinyremapper.extension.mixin.common;
2+
3+
public interface IMappable<T> {
4+
T result();
5+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package net.fabricmc.tinyremapper.extension.mixin.common;
2+
3+
public final class Logger {
4+
public enum Level {
5+
INFO, WARN, ERROR
6+
}
7+
8+
private final Level level;
9+
10+
public Logger() {
11+
this(Level.WARN);
12+
}
13+
14+
public Logger(Level level) {
15+
this.level = level;
16+
}
17+
18+
public void info(String message) {
19+
if (this.level.compareTo(Level.INFO) <= 0) {
20+
System.out.println("[INFO] [MIXIN] " + message);
21+
}
22+
}
23+
24+
public void warn(String message) {
25+
if (this.level.compareTo(Level.WARN) <= 0) {
26+
System.out.println(ANSI_YELLOW + "[WARN] [MIXIN] " + ANSI_RESET + message);
27+
}
28+
}
29+
30+
public void error(String message) {
31+
if (this.level.compareTo(Level.ERROR) <= 0) {
32+
System.out.println(ANSI_RED + "[ERROR] [MIXIN] " + ANSI_RESET + message);
33+
}
34+
}
35+
36+
private static final String ANSI_RESET = "\u001B[0m";
37+
private static final String ANSI_BLACK = "\u001B[30m";
38+
private static final String ANSI_RED = "\u001B[31m";
39+
private static final String ANSI_GREEN = "\u001B[32m";
40+
private static final String ANSI_YELLOW = "\u001B[33m";
41+
private static final String ANSI_BLUE = "\u001B[34m";
42+
private static final String ANSI_PURPLE = "\u001B[35m";
43+
private static final String ANSI_CYAN = "\u001B[36m";
44+
private static final String ANSI_WHITE = "\u001B[37m";
45+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package net.fabricmc.tinyremapper.extension.mixin.common;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
import java.util.Objects;
6+
7+
import net.fabricmc.tinyremapper.api.TrClass;
8+
import net.fabricmc.tinyremapper.api.TrMember;
9+
import net.fabricmc.tinyremapper.api.TrRemapper;
10+
11+
public final class MapUtility {
12+
private final TrRemapper remapper;
13+
private final Logger logger;
14+
15+
public static final List<String> IGNORED_NAME = Arrays.asList("<init>", "<clinit>");
16+
17+
public MapUtility(TrRemapper remapper, Logger logger) {
18+
this.remapper = Objects.requireNonNull(remapper);
19+
this.logger = Objects.requireNonNull(logger);
20+
}
21+
22+
public String mapName(TrClass _class) {
23+
return remapper.map(_class.getName());
24+
}
25+
26+
public String mapName(TrMember member) {
27+
if (member.isField()) {
28+
return remapper.mapFieldName(member.getOwner().getName(), member.getName(), member.getDesc());
29+
} else {
30+
return remapper.mapMethodName(member.getOwner().getName(), member.getName(), member.getDesc());
31+
}
32+
}
33+
34+
public String mapDesc(TrClass _class) {
35+
return StringUtility.classNameToDesc(mapName(_class));
36+
}
37+
38+
public String mapDesc(TrMember member) {
39+
if (member.isField()) {
40+
return remapper.mapDesc(member.getDesc());
41+
} else {
42+
return remapper.mapMethodDesc(member.getDesc());
43+
}
44+
}
45+
46+
public String mapOwner(TrMember member) {
47+
return mapName(member.getOwner());
48+
}
49+
50+
public TrRemapper asTrRemapper() {
51+
return this.remapper;
52+
}
53+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package net.fabricmc.tinyremapper.extension.mixin.common;
2+
3+
import java.util.Collection;
4+
import java.util.Comparator;
5+
import java.util.Objects;
6+
import java.util.Optional;
7+
import java.util.function.Supplier;
8+
9+
import net.fabricmc.tinyremapper.api.TrClass;
10+
import net.fabricmc.tinyremapper.api.TrEnvironment;
11+
import net.fabricmc.tinyremapper.api.TrField;
12+
import net.fabricmc.tinyremapper.api.TrMember;
13+
import net.fabricmc.tinyremapper.api.TrMember.MemberType;
14+
import net.fabricmc.tinyremapper.api.TrMethod;
15+
import net.fabricmc.tinyremapper.extension.mixin.common.data.Message;
16+
17+
public final class ResolveUtility {
18+
/**
19+
* Raise error if the result is not unique.
20+
*/
21+
public static int FLAG_UNIQUE = 0x1;
22+
/**
23+
* Return first member based on asm ordinal if the result is not unique.
24+
*/
25+
public static int FLAG_FIRST = 0x2;
26+
/**
27+
* Recursively resolve the the member including super-class and super-interface.
28+
*/
29+
public static int FLAG_RECURSIVE = 0x4;
30+
/**
31+
* Prefer non-synthetic member. This has higher priority than {@link ResolveUtility#FLAG_FIRST};
32+
*/
33+
public static int FLAG_NON_SYN = 0x8;
34+
35+
private final TrEnvironment environment;
36+
private final Logger logger;
37+
38+
public ResolveUtility(TrEnvironment environment, Logger logger) {
39+
this.environment = Objects.requireNonNull(environment);
40+
this.logger = Objects.requireNonNull(logger);
41+
}
42+
43+
public Optional<TrClass> resolveClass(String name) {
44+
TrClass _class = environment.getClass(name);
45+
46+
if (_class == null && !StringUtility.isInternalClassName(name)) {
47+
logger.error(String.format(Message.CANNOT_RESOLVE_CLASS, name));
48+
}
49+
50+
return Optional.ofNullable(_class);
51+
}
52+
53+
private <T extends TrMember> Optional<T> resolveMember0(TrClass owner, String name, String desc, int flag, Supplier<Collection<T>> get, Supplier<Collection<T>> resolve) {
54+
if ((flag & (FLAG_UNIQUE | FLAG_FIRST)) == 0) {
55+
throw new RuntimeException("Unspecified resolution strategy, please use FLAG_UNIQUE or FLAG_FIRST.");
56+
} else if (owner == null) {
57+
return Optional.empty();
58+
}
59+
60+
Collection<T> collection;
61+
62+
if ((flag & FLAG_RECURSIVE) != 0) {
63+
collection = resolve.get();
64+
} else {
65+
collection = get.get();
66+
}
67+
68+
if ((flag & FLAG_UNIQUE) != 0) {
69+
if (collection.size() > 1) {
70+
throw new RuntimeException(String.format("The member %s:%s is ambiguous in class %s for FLAG_UNIQUE. Please use FLAG_FIRST.", name, desc, owner.getName()));
71+
} else {
72+
return collection.stream().findFirst();
73+
}
74+
}
75+
76+
Comparator<T> comparator;
77+
78+
if ((flag & FLAG_NON_SYN) != 0) {
79+
comparator = (x, y) -> Boolean.compare(x.isSynthetic(), y.isSynthetic()) != 0
80+
? Boolean.compare(x.isSynthetic(), y.isSynthetic()) : Integer.compare(x.getIndex(), y.getIndex());
81+
} else {
82+
comparator = Comparator.comparingInt(TrMember::getIndex);
83+
}
84+
85+
return collection.stream().min(comparator);
86+
}
87+
88+
public Optional<TrField> resolveField(TrClass owner, String name, String desc, int flag) {
89+
return resolveMember0(owner, name, desc, flag,
90+
() -> owner.getFields(name, desc, false, null, null),
91+
() -> owner.resolveFields(name, desc, false, null, null));
92+
}
93+
94+
public Optional<TrField> resolveField(String owner, String name, String desc, int flag) {
95+
return resolveClass(owner).flatMap(cls -> resolveField(cls, name, desc, flag));
96+
}
97+
98+
public Optional<TrMethod> resolveMethod(TrClass owner, String name, String desc, int flag) {
99+
return resolveMember0(owner, name, desc, flag,
100+
() -> owner.getMethods(name, desc, false, null, null),
101+
() -> owner.resolveMethods(name, desc, false, null, null));
102+
}
103+
104+
public Optional<TrMethod> resolveMethod(String owner, String name, String desc, int flag) {
105+
return resolveClass(owner).flatMap(cls -> resolveMethod(cls, name, desc, flag));
106+
}
107+
108+
public Optional<TrMember> resolveMember(TrClass owner, String name, String desc, int flag) {
109+
if (desc == null) throw new RuntimeException("desc cannot be null for resolveMember. Please use resolveMethod or resolveField.");
110+
111+
MemberType type = StringUtility.getTypeByDesc(desc);
112+
113+
if (type.equals(MemberType.FIELD)) {
114+
return resolveField(owner, name, desc, flag).map(m -> m);
115+
} else if (type.equals(MemberType.METHOD)) {
116+
return resolveMethod(owner, name, desc, flag).map(m -> m);
117+
} else {
118+
throw new RuntimeException(String.format("Unknown member type %s", type.name()));
119+
}
120+
}
121+
122+
public Optional<TrMember> resolveMember(String owner, String name, String desc, int flag) {
123+
return resolveClass(owner).flatMap(cls -> resolveMember(cls, name, desc, flag));
124+
}
125+
}

0 commit comments

Comments
 (0)