Skip to content

Commit 86958d2

Browse files
authored
Merge pull request #19 from supersaiyansubtlety/verify-simples
Verify simple type existence
2 parents 018dac6 + a9353a1 commit 86958d2

File tree

7 files changed

+108
-9
lines changed

7 files changed

+108
-9
lines changed

src/main/java/org/quiltmc/enigma_plugin/Arguments.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class Arguments {
3535
public static final String DISABLE_MAPPING_MERGE = "disable_mapping_merge";
3636
public static final String CUSTOM_CODECS = "custom_codecs";
3737
public static final String SIMPLE_TYPE_FIELD_NAMES_PATH = "simple_type_field_names_path";
38+
public static final String SIMPLE_TYPE_VERIFICATION_ERROR_LEVEL = "simple_type_verification_error_level";
3839
public static final String MERGED_MAPPING_PATH = "merged_mapping_path";
3940
public static final String PACKAGE_NAME_OVERRIDES_PATH = "package_name_overrides_path";
4041

src/main/java/org/quiltmc/enigma_plugin/index/simple_type_single/SimpleTypeFieldNamesRegistry.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.List;
3131
import java.util.Map;
3232
import java.util.function.Predicate;
33+
import java.util.stream.Stream;
3334

3435
public class SimpleTypeFieldNamesRegistry {
3536
private final Path path;
@@ -46,6 +47,10 @@ public SimpleTypeFieldNamesRegistry(Path path) {
4647
return this.entries.get(type);
4748
}
4849

50+
public Stream<String> streamTypes() {
51+
return this.entries.keySet().stream();
52+
}
53+
4954
public void read() {
5055
try (var reader = JsonReader.json5(this.path)) {
5156
if (reader.peek() != JsonToken.BEGIN_OBJECT) {
@@ -57,6 +62,11 @@ public void read() {
5762
while (reader.hasNext()) {
5863
String type = reader.nextName();
5964

65+
if (type.equals("$schema")) {
66+
reader.skipValue();
67+
continue;
68+
}
69+
6070
if (this.entries.containsKey(type)) {
6171
throw new IllegalArgumentException("Duplicate type " + type);
6272
}

src/main/java/org/quiltmc/enigma_plugin/index/simple_type_single/SimpleTypeSingleIndex.java

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,17 @@
3939
import org.quiltmc.enigma_plugin.index.simple_type_single.SimpleTypeFieldNamesRegistry.Name;
4040
import org.quiltmc.enigma_plugin.util.AsmUtil;
4141
import org.quiltmc.enigma_plugin.util.Descriptors;
42+
import org.tinylog.Logger;
4243

4344
import java.nio.file.Path;
4445
import java.util.ArrayList;
46+
import java.util.Arrays;
4547
import java.util.HashMap;
4648
import java.util.HashSet;
4749
import java.util.List;
4850
import java.util.Map;
4951
import java.util.Set;
52+
import java.util.stream.Collectors;
5053

5154
/**
5255
* Index of fields/local variables that are of a rather simple type (as-in easy to guess the variable name) and which
@@ -57,9 +60,11 @@ public class SimpleTypeSingleIndex extends Index {
5760
private final Map<LocalVariableEntry, List<String>> parameterFallbacks = new HashMap<>();
5861
private final Map<FieldEntry, String> fields = new HashMap<>();
5962
private final Map<ClassNode, Map<String, FieldBuildingEntry>> fieldCache = new HashMap<>();
60-
private SimpleTypeFieldNamesRegistry registry;
63+
private final Set<String> unverifiedTypes = new HashSet<>();
6164

65+
private SimpleTypeFieldNamesRegistry registry;
6266
private InheritanceIndex inheritance;
67+
private VerificationLevel verificationLevel = VerificationLevel.DEFAULT;
6368

6469
public SimpleTypeSingleIndex() {
6570
super(null);
@@ -69,6 +74,26 @@ public SimpleTypeSingleIndex() {
6974
public void withContext(EnigmaServiceContext<JarIndexerService> context) {
7075
super.withContext(context);
7176

77+
this.verificationLevel = context.getSingleArgument(Arguments.SIMPLE_TYPE_VERIFICATION_ERROR_LEVEL)
78+
.map(value -> {
79+
try {
80+
return VerificationLevel.valueOf(value);
81+
} catch (IllegalArgumentException e) {
82+
throw new IllegalStateException(
83+
"Invalid %s value: \"%s\"; must be one of %s".formatted(
84+
Arguments.SIMPLE_TYPE_VERIFICATION_ERROR_LEVEL,
85+
value,
86+
Arrays.stream(VerificationLevel.values())
87+
.map(Enum::name)
88+
.map(name -> '"' + name + '"')
89+
.collect(Collectors.joining(", "))
90+
),
91+
e
92+
);
93+
}
94+
})
95+
.orElse(VerificationLevel.DEFAULT);
96+
7297
this.loadRegistry(context.getSingleArgument(Arguments.SIMPLE_TYPE_FIELD_NAMES_PATH)
7398
.map(context::getPath).orElse(null));
7499
}
@@ -86,6 +111,11 @@ public void loadRegistry(Path path) {
86111

87112
this.registry = new SimpleTypeFieldNamesRegistry(path);
88113
this.registry.read();
114+
115+
this.unverifiedTypes.clear();
116+
if (this.verificationLevel != VerificationLevel.NONE) {
117+
this.registry.streamTypes().forEach(this.unverifiedTypes::add);
118+
}
89119
}
90120

91121
@Override
@@ -117,6 +147,29 @@ public Set<LocalVariableEntry> getParams() {
117147
return this.parameters.keySet();
118148
}
119149

150+
public void verifyTypes() {
151+
if (this.verificationLevel != VerificationLevel.NONE) {
152+
if (!this.unverifiedTypes.isEmpty()) {
153+
boolean single = this.unverifiedTypes.size() == 1;
154+
StringBuilder message = new StringBuilder("The following simple type field name type");
155+
message.append(single ? " is" : "s are");
156+
message.append(" missing:");
157+
158+
if (single) {
159+
message.append(' ').append(this.unverifiedTypes.iterator().next());
160+
} else {
161+
this.unverifiedTypes.forEach(type -> message.append("\n\t").append(type));
162+
}
163+
164+
if (this.verificationLevel == VerificationLevel.WARN) {
165+
Logger.warn(message);
166+
} else {
167+
throw new IllegalStateException(message.toString());
168+
}
169+
}
170+
}
171+
}
172+
120173
@TestOnly
121174
public List<LocalVariableEntry> getParamsOf(MethodEntry methodEntry) {
122175
var params = new ArrayList<LocalVariableEntry>();
@@ -141,6 +194,8 @@ public void visitClassNode(ClassProvider provider, ClassNode node) {
141194

142195
var parentEntry = new ClassEntry(node.name);
143196

197+
this.unverifiedTypes.remove(node.name);
198+
144199
this.collectMatchingFields(provider, node).forEach((name, entry) -> {
145200
if (!entry.isNull()) {
146201
var fieldEntry = new FieldEntry(parentEntry, entry.node().name, new TypeDescriptor(entry.node().desc));
@@ -207,8 +262,8 @@ private Map<String, FieldBuildingEntry> collectMatchingFields(ClassProvider clas
207262
}
208263
}
209264

210-
if (field.desc.charAt(0) != 'L') continue;
211-
String type = field.desc.substring(1, field.desc.length() - 1);
265+
String type = this.verifyTypeOrNull(field.desc);
266+
if (type == null) continue;
212267

213268
var entry = this.getEntry(type);
214269
if (entry != null) {
@@ -268,9 +323,8 @@ private Map<String, ParameterBuildingEntry> collectMatchingParameters(MethodNode
268323
if (bannedTypes.contains(parameters.get(index).type())) continue;
269324

270325
ParameterNode node = method.parameters.get(index);
271-
String desc = parameters.get(index).getDescriptor();
272-
if (desc.charAt(0) != 'L') continue;
273-
String type = desc.substring(1, desc.length() - 1);
326+
String type = this.verifyTypeOrNull(parameters.get(index).getDescriptor());
327+
if (type == null) continue;
274328

275329
var entry = this.getEntry(type);
276330
if (entry != null) {
@@ -334,6 +388,19 @@ private SimpleTypeFieldNamesRegistry.Entry getEntry(String type) {
334388
return null;
335389
}
336390

391+
@Nullable
392+
private String verifyTypeOrNull(String descriptor) {
393+
if (descriptor.charAt(0) != 'L') {
394+
return null;
395+
}
396+
397+
String type = descriptor.substring(1, descriptor.length() - 1);
398+
399+
this.unverifiedTypes.remove(type);
400+
401+
return type;
402+
}
403+
337404
private record FieldBuildingEntry(FieldNode node, Name name, SimpleTypeFieldNamesRegistry.Entry entry) {
338405
public static FieldBuildingEntry createNull(SimpleTypeFieldNamesRegistry.Entry entry) {
339406
return new FieldBuildingEntry(null, null, entry);
@@ -353,4 +420,10 @@ public boolean isNull() {
353420
return this.node == null;
354421
}
355422
}
423+
424+
private enum VerificationLevel {
425+
NONE, WARN, THROW;
426+
427+
static final VerificationLevel DEFAULT = WARN;
428+
}
356429
}

src/main/java/org/quiltmc/enigma_plugin/proposal/SimpleTypeFieldNameProposer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public SimpleTypeFieldNameProposer(JarIndexer index) {
3838

3939
@Override
4040
public void insertProposedNames(Enigma enigma, JarIndex index, Map<Entry<?>, EntryMapping> mappings) {
41+
this.index.verifyTypes();
42+
4143
for (FieldEntry field : this.index.getFields()) {
4244
String name = this.index.getField(field);
4345

src/test/java/org/quiltmc/enigma_plugin/NameProposalTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
import org.quiltmc.enigma.api.translation.representation.entry.MethodEntry;
3636
import org.quiltmc.enigma.util.validation.ValidationContext;
3737

38+
import java.io.ByteArrayOutputStream;
3839
import java.io.IOException;
40+
import java.io.PrintStream;
3941
import java.nio.file.Path;
4042

4143
public class NameProposalTest {
@@ -45,6 +47,10 @@ public class NameProposalTest {
4547

4648
@BeforeAll
4749
public static void setupEnigma() throws IOException {
50+
PrintStream originalErr = System.err;
51+
ByteArrayOutputStream testErr = new ByteArrayOutputStream();
52+
System.setErr(new PrintStream(testErr));
53+
4854
var profile = EnigmaProfile.read(PROFILE);
4955
var enigma = Enigma.builder().setProfile(profile).build();
5056

@@ -53,6 +59,11 @@ public static void setupEnigma() throws IOException {
5359

5460
// Manually fire dynamic proposals
5561
remapper.insertDynamicallyProposedMappings(null, null, null);
62+
63+
// simple_type_field_names_type_verification warning
64+
Assertions.assertTrue(testErr.toString().contains("[WARN]: The following simple type field name type is missing: not/present"));
65+
66+
System.setErr(originalErr);
5667
}
5768

5869
public static void assertProposal(String name, Entry<?> entry) {

src/testInputs/resources/profile.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"disable_constant_fields": "false",
2121
"disable_records": "false",
2222
"disable_codecs": "false",
23-
"simple_type_field_names_path": "./simple_type_field_names.json5"
23+
"simple_type_field_names_path": "./simple_type_field_names.json5",
24+
"simple_type_verification_error_level": "WARN"
2425
}
2526
}
2627
]

src/testInputs/resources/simple_type_field_names.json5

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,6 @@
8888
"com/a/b/l": { // ValueE
8989
local_name: "valueE",
9090
exclusive: true
91-
}
92-
}
91+
},
92+
"not/present": "missing"
93+
}

0 commit comments

Comments
 (0)