-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathGenerateSanitizedExport.java
More file actions
96 lines (76 loc) · 3.98 KB
/
GenerateSanitizedExport.java
File metadata and controls
96 lines (76 loc) · 3.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package org.parchmentmc.compass.tasks;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.parchmentmc.compass.util.MappingUtil;
import org.parchmentmc.feather.mapping.MappingDataBuilder;
import org.parchmentmc.feather.mapping.MappingDataContainer;
import org.parchmentmc.feather.metadata.ClassMetadata;
import org.parchmentmc.feather.metadata.MethodMetadata;
import org.parchmentmc.feather.metadata.SourceMetadata;
import java.io.IOException;
import java.util.Map;
public abstract class GenerateSanitizedExport extends GenerateExport {
public GenerateSanitizedExport() {
getParameterPrefix().convention("p");
getSkipLambdaParameters().convention(Boolean.TRUE);
getSkipAnonymousClassParameters().convention(Boolean.TRUE);
getIntermediate().convention("official"); // Required for us to work.
}
@Override
protected MappingDataContainer modifyData(MappingDataContainer container) throws IOException {
final String paramPrefix = getParameterPrefix().get();
final MappingDataBuilder builder = MappingDataBuilder.copyOf(container);
final SourceMetadata metadata = getSourceMetadata();
final boolean skipLambdas = getSkipLambdaParameters().get();
final boolean skipAnonClasses = getSkipAnonymousClassParameters().get();
final Map<String, ClassMetadata> classMetadataMap = MappingUtil.buildClassMetadataMap(metadata);
// Cascade parent methods first separately so that prefixes don't get applied multiple times
builder.getClasses().forEach(clsData -> cascadeParentMethods(builder, classMetadataMap, clsData, classMetadataMap.get(clsData.getName())));
builder.getClasses().forEach(clsData -> copyRecordData(clsData, classMetadataMap.get(clsData.getName())));
builder.getClasses().forEach(clsData -> {
final ClassMetadata clsMeta = classMetadataMap.get(clsData.getName());
boolean anonClass = withinAnonymousClass(clsData.getName());
clsData.getMethods().forEach(methodData -> {
final MethodMetadata methodMeta = MappingUtil.getMethodMetadata(clsMeta, methodData.getName(), methodData.getDescriptor());
// Simple heuristic; if it starts with `lambda$`, it's a lambda.
boolean lambda = (methodMeta != null && methodMeta.isLambda())
|| (methodMeta == null && methodData.getName().startsWith("lambda$"));
methodData.getParameters().forEach(paramData -> {
if (paramData.getName() != null) {
if ((skipAnonClasses && anonClass) || (skipLambdas && lambda)) {
paramData.setName(null);
} else {
paramData.setName(paramPrefix + capitalize(paramData.getName()));
}
}
});
});
});
return builder;
}
@Input
public abstract Property<String> getParameterPrefix();
@Input
public abstract Property<Boolean> getSkipLambdaParameters();
@Input
public abstract Property<Boolean> getSkipAnonymousClassParameters();
private static String capitalize(String input) {
return Character.toTitleCase(input.charAt(0)) + input.substring(1);
}
private static boolean withinAnonymousClass(String className) {
for (String name : className.split("\\$")) {
/*
* Anonymous classes have a simple heuristic for detection
* According to JLS, class names must be defined by `[letter][letter or digit]*` identifiers
* So, it stands to reason that if a class name starts with a digit, then it is an anonymous (or at least
* synthetic) class.
*/
int firstChar = name.codePointAt(0);
// See Character#isJavaIdentifierPart
if (Character.isDigit(firstChar)) {
return true;
}
}
return false;
}
}