Skip to content

Commit e8b9c18

Browse files
authored
add getId method to EnigmaService (#164)
* rework interface * work * work * somewhat functional * fix and improve server stuff * check the style * fix rare npe due to mishandling of flatlaf * misc * restore old save/load behaviour * fully working I think :D * fix checkstyle * port enigma-cli * delete recaf (it broke and I'm lazy) * fix * error handling for invalid token types * fix navigator issues * clarify javadoc * priority * fix npe * store proposed mappings separately * store proposed mappings separately * add a test for service ordering * malformed json test * start moving plugin ID into plugin code * fix error * finish * fix * lol * resolve comments * address review from iota * check the style
1 parent b154074 commit e8b9c18

File tree

11 files changed

+148
-79
lines changed

11 files changed

+148
-79
lines changed

enigma/src/main/java/org/quiltmc/enigma/api/Enigma.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,13 @@ public EnigmaProject openJar(Path path, ClassProvider libraryClassProvider, Prog
6969

7070
index.indexJar(scope, classProvider, progress);
7171

72-
var indexers = this.services.getWithIds(JarIndexerService.TYPE);
72+
var indexers = this.services.get(JarIndexerService.TYPE);
7373
progress.init(indexers.size(), I18n.translate("progress.jar.custom_indexing"));
7474

7575
int i = 1;
7676
for (var service : indexers) {
77-
progress.step(i++, I18n.translateFormatted("progress.jar.custom_indexing.indexer", service.id()));
78-
service.service().acceptJar(scope, classProvider, index);
77+
progress.step(i++, I18n.translateFormatted("progress.jar.custom_indexing.indexer", service.getId()));
78+
service.acceptJar(scope, classProvider, index);
7979
}
8080

8181
progress.step(i, I18n.translate("progress.jar.custom_indexing.finished"));
@@ -87,7 +87,7 @@ public EnigmaProject openJar(Path path, ClassProvider libraryClassProvider, Prog
8787

8888
int j = 1;
8989
for (var service : nameProposalServices) {
90-
progress.step(j++, I18n.translateFormatted("progress.jar.name_proposal"));
90+
progress.step(j++, I18n.translateFormatted("progress.jar.name_proposal.proposer", service.getId()));
9191
Map<Entry<?>, EntryMapping> proposed = service.getProposedNames(index);
9292

9393
if (proposed != null) {
@@ -123,7 +123,7 @@ public EnigmaServices getServices() {
123123
* @return the ordered list of services
124124
*/
125125
public List<NameProposalService> getNameProposalServices() {
126-
var proposalServices = new ArrayList<>(this.services.getWithIds(NameProposalService.TYPE).stream().map(EnigmaServices.RegisteredService::service).toList());
126+
var proposalServices = new ArrayList<>(this.services.get(NameProposalService.TYPE));
127127
Collections.reverse(proposalServices);
128128
return proposalServices;
129129
}
@@ -161,20 +161,20 @@ public Enigma build() {
161161
private static class PluginContext implements EnigmaPluginContext {
162162
private final EnigmaProfile profile;
163163

164-
private final ImmutableListMultimap.Builder<EnigmaServiceType<?>, EnigmaServices.RegisteredService<?>> services = ImmutableListMultimap.builder();
164+
private final ImmutableListMultimap.Builder<EnigmaServiceType<?>, EnigmaService> services = ImmutableListMultimap.builder();
165165

166166
PluginContext(EnigmaProfile profile) {
167167
this.profile = profile;
168168
}
169169

170170
@Override
171-
public <T extends EnigmaService> void registerService(String id, EnigmaServiceType<T> serviceType, EnigmaServiceFactory<T> factory) {
171+
public <T extends EnigmaService> void registerService(EnigmaServiceType<T> serviceType, EnigmaServiceFactory<T> factory) {
172172
List<EnigmaProfile.Service> serviceProfiles = this.profile.getServiceProfiles(serviceType);
173173

174174
for (EnigmaProfile.Service serviceProfile : serviceProfiles) {
175-
if (serviceProfile.matches(id)) {
176-
T service = factory.create(this.getServiceContext(serviceProfile));
177-
this.services.put(serviceType, new EnigmaServices.RegisteredService<>(id, service));
175+
T service = factory.create(this.getServiceContext(serviceProfile));
176+
if (serviceProfile.matches(service.getId())) {
177+
this.services.put(serviceType, service);
178178
break;
179179
}
180180
}
@@ -200,13 +200,13 @@ public Path getPath(String path) {
200200
*/
201201
EnigmaServices buildServices() {
202202
var builtServices = this.services.build();
203-
ImmutableListMultimap.Builder<EnigmaServiceType<?>, EnigmaServices.RegisteredService<?>> orderedServices = ImmutableListMultimap.builder();
203+
ImmutableListMultimap.Builder<EnigmaServiceType<?>, EnigmaService> orderedServices = ImmutableListMultimap.builder();
204204
for (EnigmaServiceType<?> type : builtServices.keySet()) {
205205
List<EnigmaProfile.Service> serviceProfiles = this.profile.getServiceProfiles(type);
206206

207207
for (EnigmaProfile.Service service : serviceProfiles) {
208-
for (EnigmaServices.RegisteredService<?> registeredService : builtServices.get(type)) {
209-
if (service.matches(registeredService.id())) {
208+
for (EnigmaService registeredService : builtServices.get(type)) {
209+
if (service.matches(registeredService.getId())) {
210210
orderedServices.put(type, registeredService);
211211
break;
212212
}

enigma/src/main/java/org/quiltmc/enigma/api/EnigmaPluginContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
import org.quiltmc.enigma.api.service.EnigmaServiceType;
66

77
public interface EnigmaPluginContext {
8-
<T extends EnigmaService> void registerService(String id, EnigmaServiceType<T> serviceType, EnigmaServiceFactory<T> factory);
8+
<T extends EnigmaService> void registerService(EnigmaServiceType<T> serviceType, EnigmaServiceFactory<T> factory);
99
}

enigma/src/main/java/org/quiltmc/enigma/api/EnigmaServices.java

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,14 @@
77
import java.util.List;
88

99
public final class EnigmaServices {
10-
private final ImmutableListMultimap<EnigmaServiceType<?>, RegisteredService<? extends EnigmaService>> services;
10+
private final ImmutableListMultimap<EnigmaServiceType<?>, EnigmaService> services;
1111

12-
EnigmaServices(ImmutableListMultimap<EnigmaServiceType<?>, RegisteredService<? extends EnigmaService>> services) {
12+
EnigmaServices(ImmutableListMultimap<EnigmaServiceType<?>, EnigmaService> services) {
1313
this.services = services;
1414
}
1515

16-
public <T extends EnigmaService> List<T> get(EnigmaServiceType<T> type) {
17-
List<RegisteredService<T>> withIds = this.getWithIds(type);
18-
return withIds.stream().map(RegisteredService::service).toList();
19-
}
20-
2116
@SuppressWarnings("unchecked")
22-
public <T extends EnigmaService> List<RegisteredService<T>> getWithIds(EnigmaServiceType<T> type) {
23-
return (List<RegisteredService<T>>) (Object) this.services.get(type);
24-
}
25-
26-
public record RegisteredService<T extends EnigmaService>(String id, T service) {
17+
public <T extends EnigmaService> List<T> get(EnigmaServiceType<T> type) {
18+
return (List<T>) this.services.get(type);
2719
}
2820
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
package org.quiltmc.enigma.api.service;
22

33
public interface EnigmaService {
4+
/**
5+
* The ID of this service. This should satisfy a few criteria:
6+
* <ul>
7+
* <li>Be namespaced, with the plugin name and service name separated by a colon. The {@code enigma} namespace is reserved for builtin plugins.</li>
8+
* <li>Be all lowercase, with words separated by underscores. Slashes are allowed only after the namespace.</li>
9+
* <li>Be constant and unique: it should never change.</li>
10+
* </ul>
11+
* <p>Examples: {@code enigma:cfr}, {@code enigma:enum_name_proposer}, {@code your_plugin:custom_indexer}</p>
12+
*
13+
* @return the constant ID
14+
*/
15+
String getId();
416
}

enigma/src/main/java/org/quiltmc/enigma/api/service/JarIndexerService.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.quiltmc.enigma.api.service;
22

3+
import org.objectweb.asm.tree.ClassNode;
34
import org.quiltmc.enigma.api.analysis.index.jar.JarIndex;
45
import org.quiltmc.enigma.api.class_provider.ClassProvider;
56
import org.objectweb.asm.ClassVisitor;
@@ -11,10 +12,21 @@ public interface JarIndexerService extends EnigmaService {
1112

1213
void acceptJar(Set<String> scope, ClassProvider classProvider, JarIndex jarIndex);
1314

14-
static JarIndexerService fromVisitor(ClassVisitor visitor) {
15-
return (scope, classProvider, jarIndex) -> {
16-
for (String className : scope) {
17-
classProvider.get(className).accept(visitor);
15+
static JarIndexerService fromVisitor(ClassVisitor visitor, String id) {
16+
return new JarIndexerService() {
17+
@Override
18+
public void acceptJar(Set<String> scope, ClassProvider classProvider, JarIndex jarIndex) {
19+
for (String className : scope) {
20+
ClassNode node = classProvider.get(className);
21+
if (node != null) {
22+
node.accept(visitor);
23+
}
24+
}
25+
}
26+
27+
@Override
28+
public String getId() {
29+
return id;
1830
}
1931
};
2032
}

enigma/src/main/java/org/quiltmc/enigma/api/service/NameProposalService.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,18 @@ public interface NameProposalService extends EnigmaService {
3939
*/
4040
@Nullable
4141
Map<Entry<?>, EntryMapping> getDynamicProposedNames(EntryRemapper remapper, @Nullable Entry<?> obfEntry, @Nullable EntryMapping oldMapping, @Nullable EntryMapping newMapping);
42+
43+
/**
44+
* Creates a proposed mapping, with no javadoc and using {@link #getId()} as the source plugin ID.
45+
* @param name the name
46+
* @param tokenType the token type - must be either {@link TokenType#JAR_PROPOSED} or {@link TokenType#DYNAMIC_PROPOSED}
47+
* @return the newly created mapping
48+
*/
49+
default EntryMapping createMapping(String name, TokenType tokenType) {
50+
if (!tokenType.isProposed()) {
51+
throw new IllegalArgumentException("token type must be proposed!");
52+
}
53+
54+
return new EntryMapping(name, null, tokenType, this.getId());
55+
}
4256
}
Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
package org.quiltmc.enigma.api.source;
22

3+
import org.quiltmc.enigma.api.class_provider.ClassProvider;
34
import org.quiltmc.enigma.impl.source.bytecode.BytecodeDecompiler;
45
import org.quiltmc.enigma.impl.source.cfr.CfrDecompiler;
56
import org.quiltmc.enigma.impl.source.procyon.ProcyonDecompiler;
67
import org.quiltmc.enigma.impl.source.vineflower.VineflowerDecompiler;
78

9+
import java.util.function.BiFunction;
10+
811
public class Decompilers {
9-
public static final DecompilerService VINEFLOWER = VineflowerDecompiler::new;
10-
public static final DecompilerService PROCYON = ProcyonDecompiler::new;
11-
public static final DecompilerService CFR = CfrDecompiler::new;
12-
public static final DecompilerService BYTECODE = BytecodeDecompiler::new;
12+
public static final DecompilerService VINEFLOWER = create("enigma:vineflower", VineflowerDecompiler::new);
13+
public static final DecompilerService PROCYON = create("enigma:procyon", ProcyonDecompiler::new);
14+
public static final DecompilerService CFR = create("enigma:cfr", CfrDecompiler::new);
15+
public static final DecompilerService BYTECODE = create("enigma:bytecode", BytecodeDecompiler::new);
16+
17+
private static DecompilerService create(String id, BiFunction<ClassProvider, SourceSettings, Decompiler> factory) {
18+
return new DecompilerService() {
19+
@Override
20+
public Decompiler create(ClassProvider classProvider, SourceSettings settings) {
21+
return factory.apply(classProvider, settings);
22+
}
23+
24+
@Override
25+
public String getId() {
26+
return id;
27+
}
28+
};
29+
}
1330
}

enigma/src/main/java/org/quiltmc/enigma/api/translation/mapping/EntryMapping.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public EntryMapping(@Nullable String targetName, @Nullable String javadoc) {
2121
}
2222

2323
public EntryMapping {
24+
validateSourcePluginId(sourcePluginId);
25+
2426
if (tokenType == TokenType.OBFUSCATED && targetName != null) {
2527
throw new RuntimeException("cannot create a named mapping with an obfuscated token type!");
2628
} else if (targetName == null && tokenType != TokenType.OBFUSCATED) {
@@ -34,6 +36,12 @@ public EntryMapping(@Nullable String targetName, @Nullable String javadoc) {
3436
}
3537
}
3638

39+
private static void validateSourcePluginId(String id) {
40+
if (id != null && !id.matches("([a-z0-9_]+:[a-z0-9_/]+)")) {
41+
throw new IllegalArgumentException("invalid plugin ID: '" + id + "! plugin ID should be all lowercase, only contain letters, numbers, underscores and slashes, and be namespaced separated by a colon.");
42+
}
43+
}
44+
3745
public EntryMapping withName(@Nullable String newName) {
3846
return new EntryMapping(newName, this.javadoc, this.tokenType, this.sourcePluginId);
3947
}

enigma/src/main/java/org/quiltmc/enigma/impl/analysis/BuiltinPlugin.java

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import java.util.List;
4141
import java.util.Map;
4242
import java.util.Set;
43-
import java.util.function.Function;
4443

4544
public final class BuiltinPlugin implements EnigmaPlugin {
4645
@Override
@@ -54,64 +53,69 @@ private void registerEnumNamingService(EnigmaPluginContext ctx) {
5453
final Map<Entry<?>, String> names = new HashMap<>();
5554
final EnumFieldNameFindingVisitor visitor = new EnumFieldNameFindingVisitor(names);
5655

57-
ctx.registerService("enigma:enum_initializer_indexer", JarIndexerService.TYPE, ctx1 -> JarIndexerService.fromVisitor(visitor));
56+
ctx.registerService(JarIndexerService.TYPE, ctx1 -> JarIndexerService.fromVisitor(visitor, "enigma:enum_initializer_indexer"));
5857

59-
String id = "enigma:enum_name_proposer";
60-
ctx.registerService(id, NameProposalService.TYPE, ctx1 -> new NameProposalFunction() {
58+
ctx.registerService(NameProposalService.TYPE, ctx1 -> new NameProposalService() {
6159
@Override
62-
public Map<Entry<?>, EntryMapping> apply(JarIndex jarIndex) {
60+
public Map<Entry<?>, EntryMapping> getProposedNames(JarIndex index) {
6361
Map<Entry<?>, EntryMapping> mappings = new HashMap<>();
6462

65-
jarIndex.getIndex(EntryIndex.class).getFields().forEach(field -> {
63+
index.getIndex(EntryIndex.class).getFields().forEach(field -> {
6664
if (names.containsKey(field)) {
67-
mappings.put(field, new EntryMapping(names.get(field), null, TokenType.JAR_PROPOSED, id));
65+
mappings.put(field, this.createMapping(names.get(field), TokenType.JAR_PROPOSED));
6866
}
6967
});
7068

7169
return mappings;
7270
}
71+
72+
@Override
73+
public Map<Entry<?>, EntryMapping> getDynamicProposedNames(EntryRemapper remapper, @Nullable Entry<?> obfEntry, @Nullable EntryMapping oldMapping, @Nullable EntryMapping newMapping) {
74+
return null;
75+
}
76+
77+
@Override
78+
public String getId() {
79+
return "enigma:enum_name_proposer";
80+
}
7381
});
7482
}
7583

7684
private void registerSpecializedMethodNamingService(EnigmaPluginContext ctx) {
77-
String id = "enigma:specialized_method_name_proposer";
85+
ctx.registerService(NameProposalService.TYPE, ctx1 -> new NameProposalService() {
86+
@Override
87+
public Map<Entry<?>, EntryMapping> getProposedNames(JarIndex index) {
88+
BridgeMethodIndex bridgeMethodIndex = index.getIndex(BridgeMethodIndex.class);
89+
Map<Entry<?>, EntryMapping> mappings = new HashMap<>();
7890

79-
ctx.registerService(id, NameProposalService.TYPE, ctx1 -> new NameProposalFunction() {
80-
@Override
81-
public Map<Entry<?>, EntryMapping> apply(JarIndex jarIndex) {
82-
BridgeMethodIndex bridgeMethodIndex = jarIndex.getIndex(BridgeMethodIndex.class);
83-
Map<Entry<?>, EntryMapping> mappings = new HashMap<>();
91+
bridgeMethodIndex.getSpecializedToBridge().forEach((specialized, bridge) -> {
92+
EntryMapping mapping = this.createMapping(bridge.getName(), TokenType.JAR_PROPOSED);
8493

85-
bridgeMethodIndex.getSpecializedToBridge().forEach((specialized, bridge) -> {
86-
EntryMapping mapping = new EntryMapping(bridge.getName(), null, TokenType.JAR_PROPOSED, id);
94+
mappings.put(specialized, mapping);
95+
// IndexEntryResolver#resolveEntry can return the bridge method, so we can just use the name
96+
mappings.put(bridge, mapping);
97+
});
8798

88-
mappings.put(specialized, mapping);
89-
// IndexEntryResolver#resolveEntry can return the bridge method, so we can just use the name
90-
mappings.put(bridge, mapping);
91-
});
99+
return mappings;
100+
}
92101

93-
return mappings;
94-
}
102+
@Override
103+
public Map<Entry<?>, EntryMapping> getDynamicProposedNames(EntryRemapper remapper, @Nullable Entry<?> obfEntry, @Nullable EntryMapping oldMapping, @Nullable EntryMapping newMapping) {
104+
return null;
105+
}
106+
107+
@Override
108+
public String getId() {
109+
return "enigma:specialized_method_name_proposer";
110+
}
95111
});
96112
}
97113

98114
private void registerDecompilerServices(EnigmaPluginContext ctx) {
99-
ctx.registerService("enigma:vineflower", DecompilerService.TYPE, ctx1 -> Decompilers.VINEFLOWER);
100-
ctx.registerService("enigma:procyon", DecompilerService.TYPE, ctx1 -> Decompilers.PROCYON);
101-
ctx.registerService("enigma:cfr", DecompilerService.TYPE, ctx1 -> Decompilers.CFR);
102-
ctx.registerService("enigma:bytecode", DecompilerService.TYPE, ctx1 -> Decompilers.BYTECODE);
103-
}
104-
105-
private abstract static class NameProposalFunction implements NameProposalService, Function<JarIndex, Map<Entry<?>, EntryMapping>> {
106-
@Override
107-
public Map<Entry<?>, EntryMapping> getProposedNames(JarIndex index) {
108-
return this.apply(index);
109-
}
110-
111-
@Override
112-
public Map<Entry<?>, EntryMapping> getDynamicProposedNames(EntryRemapper remapper, @Nullable Entry<?> obfEntry, @Nullable EntryMapping oldMapping, @Nullable EntryMapping newMapping) {
113-
return null;
114-
}
115+
ctx.registerService(DecompilerService.TYPE, ctx1 -> Decompilers.VINEFLOWER);
116+
ctx.registerService(DecompilerService.TYPE, ctx1 -> Decompilers.PROCYON);
117+
ctx.registerService(DecompilerService.TYPE, ctx1 -> Decompilers.CFR);
118+
ctx.registerService(DecompilerService.TYPE, ctx1 -> Decompilers.BYTECODE);
115119
}
116120

117121
private static final class EnumFieldNameFindingVisitor extends ClassVisitor {

enigma/src/test/java/org/quiltmc/enigma/name_proposal/TestNameProposal.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,12 @@ public void init(EnigmaPluginContext ctx) {
111111
nameAllFields(ctx, "c");
112112
nameAllFields(ctx, "b");
113113

114-
String id = "test:q_to_w";
115-
ctx.registerService(id, NameProposalService.TYPE, ctx1 -> new TestDynamicNameProposer(id));
114+
ctx.registerService(NameProposalService.TYPE, ctx1 -> new TestDynamicNameProposer("test:q_to_w"));
116115
}
117116

118117
private static void nameAllFields(EnigmaPluginContext ctx, String prefix) {
119118
String id = "test:name_all_fields_" + prefix;
120-
ctx.registerService(id, NameProposalService.TYPE, ctx1 -> new TestJarNameProposer(prefix, id));
119+
ctx.registerService(NameProposalService.TYPE, ctx1 -> new TestJarNameProposer(prefix, id));
121120
}
122121

123122
private record TestJarNameProposer(String prefix, String id) implements NameProposalService {
@@ -135,6 +134,11 @@ public Map<Entry<?>, EntryMapping> getProposedNames(JarIndex index) {
135134
public Map<Entry<?>, EntryMapping> getDynamicProposedNames(EntryRemapper remapper, @Nullable Entry<?> obfEntry, @Nullable EntryMapping oldMapping, @Nullable EntryMapping newMapping) {
136135
return null;
137136
}
137+
138+
@Override
139+
public String getId() {
140+
return this.id;
141+
}
138142
}
139143

140144
private record TestDynamicNameProposer(String id) implements NameProposalService {
@@ -155,6 +159,11 @@ public Map<Entry<?>, EntryMapping> getDynamicProposedNames(EntryRemapper remappe
155159

156160
return null;
157161
}
162+
163+
@Override
164+
public String getId() {
165+
return this.id;
166+
}
158167
}
159168
}
160169
}

0 commit comments

Comments
 (0)