Skip to content

Commit 51a731b

Browse files
committed
more work on renaming
1 parent 5569ad7 commit 51a731b

File tree

13 files changed

+267
-108
lines changed

13 files changed

+267
-108
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ val filtered = tasks.register<FilterTestClasspath>("filteredTestClasspath") {
8989

9090
dependencies {
9191
implementation(mainForNewTargets.output)
92-
testImplementation(files(filtered.flatMap { it.outputDir }))
92+
testRuntimeOnly(files(filtered.flatMap { it.outputDir })) // only have access to old targets at runtime, don't use them in actual tests
9393
testImplementation(testDataNewTargets.output)
9494

9595
testDataNewTargets.implementationConfigurationName(mainForNewTargets.output)

src/main/java/io/papermc/asm/rules/rename/EnumRenameBuilder.java

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@
1010
public final class EnumRenameBuilder {
1111

1212
private final ClassDesc enumTypeDesc;
13-
private @Nullable ClassDesc optionalEnumReplacementImpl;
13+
private @Nullable ClassDesc alternateValueOfOwner;
1414
private final Map<String, String> enumFieldRenames = new HashMap<>();
1515

1616
EnumRenameBuilder(final ClassDesc enumTypeDesc) {
1717
this.enumTypeDesc = enumTypeDesc;
1818
}
1919

20-
public EnumRenameBuilder enumReplacementImpl(final Class<?> type) {
21-
return this.enumReplacementImpl(desc(type));
20+
public EnumRenameBuilder alternateValueOfOwner(final Class<?> type) {
21+
return this.alternateValueOfOwner(desc(type));
2222
}
2323

24-
public EnumRenameBuilder enumReplacementImpl(final ClassDesc type) {
24+
public EnumRenameBuilder alternateValueOfOwner(final ClassDesc type) {
2525
if (this.enumTypeDesc.equals(type)) {
2626
throw new IllegalArgumentException("Cannot replace an enum with itself");
2727
}
28-
this.optionalEnumReplacementImpl = type;
28+
this.alternateValueOfOwner = type;
2929
return this;
3030
}
3131

@@ -34,11 +34,7 @@ public EnumRenameBuilder rename(final String legacyName, final String newName) {
3434
return this;
3535
}
3636

37-
void apply(final RenameRuleBuilder renameRuleBuilder) {
38-
this.enumFieldRenames.forEach((legacyName, newName) -> {
39-
renameRuleBuilder.fieldByDesc(this.enumTypeDesc, legacyName, newName);
40-
});
41-
final Map<String, String> copy = Map.copyOf(this.enumFieldRenames);
42-
renameRuleBuilder.enumValueOfFieldRenames.put(this.enumTypeDesc, new EnumRenamer(this.enumTypeDesc, this.optionalEnumReplacementImpl, copy));
37+
EnumRenamer build() {
38+
return new EnumRenamer(this.enumTypeDesc, this.alternateValueOfOwner, Map.copyOf(this.enumFieldRenames));
4339
}
4440
}
Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
11
package io.papermc.asm.rules.rename;
22

33
import java.lang.constant.ClassDesc;
4+
import java.util.HashMap;
45
import java.util.Map;
6+
import java.util.Objects;
57
import org.checkerframework.checker.nullness.qual.Nullable;
68

7-
public record EnumRenamer(ClassDesc typeDesc, @Nullable ClassDesc optionalReplacementImpl, Map<String, String> fieldRenames) {
9+
public record EnumRenamer(ClassDesc typeDesc, @Nullable ClassDesc alternateValueOfOwner, Map<String, String> fieldRenames) {
10+
11+
public EnumRenamer {
12+
fieldRenames = Map.copyOf(fieldRenames);
13+
}
14+
15+
EnumRenamer overwrite(final EnumRenamer other) {
16+
if (!this.typeDesc.equals(other.typeDesc)) {
17+
throw new IllegalArgumentException("Cannot merge EnumRenamers with different typeDesc");
18+
} else if (!Objects.equals(this.alternateValueOfOwner, other.alternateValueOfOwner)) {
19+
throw new IllegalArgumentException("Cannot merge EnumRenamers with different alternateValueOfOwner");
20+
}
21+
final Map<String, String> newFieldRenames = new HashMap<>();
22+
newFieldRenames.putAll(this.fieldRenames);
23+
newFieldRenames.putAll(other.fieldRenames);
24+
return new EnumRenamer(this.typeDesc, this.alternateValueOfOwner, newFieldRenames);
25+
}
826
}

src/main/java/io/papermc/asm/rules/rename/EnumValueOfRewriteRule.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ final class EnumValueOfRewriteRule implements GeneratedStaticRewrite {
2828

2929
EnumValueOfRewriteRule(final EnumRenamer renamer) {
3030
this.owners.add(renamer.typeDesc());
31-
if (renamer.optionalReplacementImpl() != null) {
32-
this.owners.add(renamer.optionalReplacementImpl());
31+
if (renamer.alternateValueOfOwner() != null) {
32+
this.owners.add(renamer.alternateValueOfOwner());
3333
}
3434
this.matcher = MethodMatcher.builder()
3535
.match("valueOf", b -> b.statik().desc(MethodTypeDesc.of(renamer.typeDesc(), ConstantDescs.CD_String)))

src/main/java/io/papermc/asm/rules/rename/RenameRule.java

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,78 @@
22

33
import io.papermc.asm.rules.RewriteRule;
44
import io.papermc.asm.rules.rename.asm.FixedClassRemapper;
5+
import io.papermc.asm.versioned.ApiVersion;
6+
import io.papermc.asm.versioned.VersionedRuleFactory;
57
import java.lang.constant.ClassDesc;
68
import java.util.ArrayList;
9+
import java.util.Collections;
10+
import java.util.HashMap;
711
import java.util.List;
812
import java.util.Map;
13+
import java.util.NavigableMap;
14+
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
915
import org.objectweb.asm.commons.Remapper;
1016
import org.objectweb.asm.commons.SimpleRemapper;
1117

1218
public final class RenameRule implements RewriteRule.Delegate {
1319

14-
private final RewriteRule rule;
20+
public static RenameRuleBuilder builder() {
21+
return new RenameRuleBuilderImpl();
22+
}
1523

16-
public RenameRule(final Map<String, String> renames, final Map<ClassDesc, EnumRenamer> enumValueOfFieldRenames) {
17-
final Remapper remapper = new SimpleRemapper(Map.copyOf(renames));
24+
private final Map<String, String> renames;
25+
private final Map<ClassDesc, EnumRenamer> enumFieldRenames;
26+
private @MonotonicNonNull RewriteRule rule;
1827

19-
final List<RewriteRule> rules = new ArrayList<>(enumValueOfFieldRenames.size() + 1);
20-
enumValueOfFieldRenames.forEach((classDesc, enumRenamer) -> {
21-
rules.add(new EnumValueOfRewriteRule(enumRenamer));
22-
});
23-
rules.add((api, parent, context) -> new FixedClassRemapper(api, parent, remapper));
28+
public RenameRule(final Map<String, String> renames, final Map<ClassDesc, EnumRenamer> enumFieldRenames) {
29+
this.renames = Map.copyOf(renames);
30+
this.enumFieldRenames = Map.copyOf(enumFieldRenames);
31+
}
2432

25-
this.rule = RewriteRule.chain(rules);
33+
public Map<String, String> renames() {
34+
return this.renames;
2635
}
2736

28-
public static RenameRuleBuilder builder() {
29-
return new RenameRuleBuilder();
37+
public Map<ClassDesc, EnumRenamer> enumFieldRenames() {
38+
return this.enumFieldRenames;
3039
}
3140

3241
@Override
3342
public RewriteRule delegate() {
43+
if (this.rule == null) {
44+
final Remapper remapper = new SimpleRemapper(Map.copyOf(this.renames));
45+
46+
final List<RewriteRule> rules = new ArrayList<>(this.enumFieldRenames.size() + 1);
47+
this.enumFieldRenames.forEach((classDesc, enumRenamer) -> {
48+
rules.add(new EnumValueOfRewriteRule(enumRenamer));
49+
});
50+
rules.add((api, parent, context) -> new FixedClassRemapper(api, parent, remapper));
51+
52+
this.rule = RewriteRule.chain(rules);
53+
}
3454
return this.rule;
3555
}
56+
57+
public record Versioned(NavigableMap<ApiVersion, RenameRule> versions) implements VersionedRuleFactory {
58+
59+
@Override
60+
public RewriteRule createRule(final ApiVersion apiVersion) {
61+
final List<RenameRule> toMerge = new ArrayList<>(this.versions.tailMap(apiVersion, true).values());
62+
if (toMerge.isEmpty()) {
63+
return RewriteRule.EMPTY;
64+
} else if (toMerge.size() == 1) {
65+
return toMerge.get(0);
66+
}
67+
Collections.reverse(toMerge);
68+
final Map<String, String> regularRenames = new HashMap<>();
69+
final Map<ClassDesc, EnumRenamer> enumFieldRenames = new HashMap<>();
70+
for (final RenameRule renameRule : toMerge) {
71+
regularRenames.putAll(renameRule.renames);
72+
renameRule.enumFieldRenames.forEach((classDesc, renamer) -> {
73+
enumFieldRenames.merge(classDesc, renamer, EnumRenamer::overwrite);
74+
});
75+
}
76+
return new RenameRule(regularRenames, enumFieldRenames);
77+
}
78+
}
3679
}
Lines changed: 34 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,86 @@
11
package io.papermc.asm.rules.rename;
22

3+
import io.papermc.asm.util.Builder;
34
import java.lang.constant.ClassDesc;
45
import java.lang.constant.MethodTypeDesc;
5-
import java.util.HashMap;
6-
import java.util.Map;
6+
import java.util.Set;
77
import java.util.function.Consumer;
88

99
import static io.papermc.asm.util.DescriptorUtils.desc;
10-
import static io.papermc.asm.util.DescriptorUtils.toOwner;
1110

12-
public final class RenameRuleBuilder implements io.papermc.asm.util.Builder<RenameRule> {
11+
public interface RenameRuleBuilder extends Builder<RenameRule> {
1312

14-
RenameRuleBuilder() {
15-
}
16-
17-
final Map<String, String> mappings = new HashMap<>();
18-
final Map<ClassDesc, EnumRenamer> enumValueOfFieldRenames = new HashMap<>();
19-
20-
public RenameRuleBuilder methodByDesc(final Iterable<ClassDesc> owners, final String legacyMethodName, final MethodTypeDesc desc, final String newMethodName) {
21-
for (final ClassDesc owner : owners) {
22-
this.methodByDesc(owner, legacyMethodName, desc, newMethodName);
13+
//<editor-fold desc="methods" defaultstate="collapsed">
14+
default RenameRuleBuilder methodByClass(final Set<Class<?>> owners, final String legacyMethodName, final MethodTypeDesc methodDesc, final String newMethodName) {
15+
for (final Class<?> owner : owners) {
16+
this.methodByClass(owner, legacyMethodName, methodDesc, newMethodName);
2317
}
2418
return this;
2519
}
2620

27-
public RenameRuleBuilder methodByDesc(final ClassDesc owner, final String legacyMethodName, final MethodTypeDesc desc, final String newMethodName) {
28-
return this.methodByInternal(toOwner(owner), legacyMethodName, desc.descriptorString(), newMethodName);
21+
default RenameRuleBuilder methodByClass(final Class<?> owner, final String legacyMethodName, final MethodTypeDesc methodDesc, final String newMethodName) {
22+
return this.method(desc(owner), legacyMethodName, methodDesc, newMethodName);
2923
}
3024

31-
public RenameRuleBuilder methodByInternal(final Iterable<String> owners, final String legacyMethodName, final MethodTypeDesc desc, final String newMethodName) {
32-
for (final String owner : owners) {
33-
this.methodByInternal(owner, legacyMethodName, desc.descriptorString(), newMethodName);
25+
default RenameRuleBuilder method(final Set<ClassDesc> owners, final String legacyMethodName, final MethodTypeDesc methodDesc, final String newMethodName) {
26+
for (final ClassDesc owner : owners) {
27+
this.method(owner, legacyMethodName, methodDesc, newMethodName);
3428
}
3529
return this;
3630
}
3731

38-
public RenameRuleBuilder methodByInternal(final String owner, final String legacyMethodName, final String desc, final String newMethodName) {
39-
this.mappings.put("%s.%s%s".formatted(owner, legacyMethodName, desc), newMethodName);
40-
return this;
41-
}
32+
RenameRuleBuilder method(ClassDesc owner, String legacyMethodName, MethodTypeDesc methodDesc, final String newMethodName);
33+
//</editor-fold>
4234

43-
public RenameRuleBuilder fieldByDesc(final Iterable<ClassDesc> owners, final String legacyFieldName, final String newFieldName) {
44-
for (final ClassDesc owner : owners) {
45-
this.fieldByDesc(owner, legacyFieldName, newFieldName);
35+
//<editor-fold desc="fields" defaultstate="collapsed">
36+
default RenameRuleBuilder fieldByClass(final Set<Class<?>> owners, final String legacyFieldName, final String newFieldName) {
37+
for (final Class<?> owner : owners) {
38+
this.fieldByClass(owner, legacyFieldName, newFieldName);
4639
}
4740
return this;
4841
}
4942

50-
public RenameRuleBuilder fieldByDesc(final ClassDesc owner, final String legacyFieldName, final String newFieldName) {
51-
return this.fieldByInternal(toOwner(owner), legacyFieldName, newFieldName);
43+
default RenameRuleBuilder fieldByClass(final Class<?> owner, final String legacyFieldName, final String newFieldName) {
44+
return this.field(desc(owner), legacyFieldName, newFieldName);
5245
}
5346

54-
public RenameRuleBuilder fieldByInternal(final Iterable<String> owners, final String legacyFieldName, final String newFieldName) {
55-
for (final String owner : owners) {
56-
this.fieldByInternal(owner, legacyFieldName, newFieldName);
47+
default RenameRuleBuilder field(final Set<ClassDesc> owners, final String legacyFieldName, final String newFieldName) {
48+
for (final ClassDesc owner : owners) {
49+
this.field(owner, legacyFieldName, newFieldName);
5750
}
5851
return this;
5952
}
6053

61-
public RenameRuleBuilder fieldByInternal(final String owner, final String legacyFieldName, final String newFieldName) {
62-
this.mappings.put("%s.%s".formatted(owner, legacyFieldName), newFieldName);
63-
return this;
64-
}
54+
RenameRuleBuilder field(ClassDesc owner, String legacyFieldName, String newFieldName);
55+
//</editor-fold>
6556

6657
/**
6758
* Note that you also have to remap the method for the annotation attribute.
6859
*/
69-
public RenameRuleBuilder annotationAttribute(final ClassDesc owner, final String legacyName, final String newName) {
70-
return this.annotationAttribute(owner.descriptorString(), legacyName, newName);
60+
default RenameRuleBuilder annotationAttribute(final Class<?> owner, final String legacyName, final String newName) {
61+
return this.annotationAttribute(desc(owner), legacyName, newName);
7162
}
7263

7364
/**
7465
* Note that you also have to remap the method for the annotation attribute.
7566
*/
76-
public RenameRuleBuilder annotationAttribute(final String ownerDescriptor, final String legacyName, final String newName) {
77-
if (!ownerDescriptor.startsWith("L") || !ownerDescriptor.endsWith(";")) {
78-
throw new IllegalArgumentException("Invalid owner descriptor: %s".formatted(ownerDescriptor));
79-
}
80-
// for some reason the remapper wants the Lpkg/name; format, but just for annotation attributes
81-
this.mappings.put("%s.%s".formatted(ownerDescriptor, legacyName), newName);
82-
return this;
83-
}
67+
RenameRuleBuilder annotationAttribute(ClassDesc owner, String legacyName, String newName);
8468

8569
/**
8670
* Use {@code /} instead of {@code .}.
8771
*/
88-
public RenameRuleBuilder type(final String legacyType, final ClassDesc newType) {
89-
this.mappings.put(legacyType, toOwner(newType));
90-
return this;
72+
default RenameRuleBuilder type(final String legacyType, final Class<?> newType) {
73+
return this.type(legacyType, desc(newType));
9174
}
9275

9376
/**
9477
* Use {@code /} instead of {@code .}.
9578
*/
96-
public RenameRuleBuilder type(final String legacyType, final String newType) {
97-
this.mappings.put(legacyType, newType);
98-
return this;
99-
}
79+
RenameRuleBuilder type(String legacyType, ClassDesc newType);
10080

101-
public RenameRuleBuilder editEnum(final Class<?> enumTypeDesc, final Consumer<EnumRenameBuilder> renamer) {
102-
return this.editEnum(desc(enumTypeDesc), renamer);
81+
default RenameRuleBuilder editEnum(final Class<?> enumType, final Consumer<EnumRenameBuilder> renameBuilder) {
82+
return this.editEnum(desc(enumType), renameBuilder);
10383
}
10484

105-
public RenameRuleBuilder editEnum(final ClassDesc enumTypeDesc, final Consumer<EnumRenameBuilder> renamer) {
106-
final EnumRenameBuilder enumRenamer = new EnumRenameBuilder(enumTypeDesc);
107-
renamer.accept(enumRenamer);
108-
enumRenamer.apply(this);
109-
return this;
110-
}
111-
112-
@Override
113-
public RenameRule build() {
114-
return new RenameRule(this.mappings, this.enumValueOfFieldRenames);
115-
}
85+
RenameRuleBuilder editEnum(ClassDesc enumTypeDesc, Consumer<EnumRenameBuilder> renameBuilder);
11686
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package io.papermc.asm.rules.rename;
2+
3+
import java.lang.constant.ClassDesc;
4+
import java.lang.constant.MethodTypeDesc;
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
import java.util.function.Consumer;
8+
9+
import static io.papermc.asm.util.DescriptorUtils.toOwner;
10+
11+
final class RenameRuleBuilderImpl implements RenameRuleBuilder {
12+
13+
RenameRuleBuilderImpl() {
14+
}
15+
16+
final Map<String, String> mappings = new HashMap<>();
17+
final Map<ClassDesc, EnumRenamer> enumValueOfFieldRenames = new HashMap<>();
18+
19+
@Override
20+
public RenameRuleBuilder method(final ClassDesc owner, final String legacyMethodName, final MethodTypeDesc methodDesc, final String newMethodName) {
21+
this.mappings.put("%s.%s%s".formatted(toOwner(owner), legacyMethodName, methodDesc.descriptorString()), newMethodName);
22+
return this;
23+
}
24+
25+
@Override
26+
public RenameRuleBuilder field(final ClassDesc owner, final String legacyFieldName, final String newFieldName) {
27+
this.mappings.put("%s.%s".formatted(toOwner(owner), legacyFieldName), newFieldName);
28+
return this;
29+
}
30+
31+
@Override
32+
public RenameRuleBuilder annotationAttribute(final ClassDesc owner, final String legacyName, final String newName) {
33+
final String ownerDescriptor = owner.descriptorString();
34+
if (!ownerDescriptor.startsWith("L") || !ownerDescriptor.endsWith(";")) {
35+
throw new IllegalArgumentException("Invalid owner descriptor: %s".formatted(ownerDescriptor));
36+
}
37+
// for some reason the remapper wants the Lpkg/name; format, but just for annotation attributes
38+
this.mappings.put("%s.%s".formatted(ownerDescriptor, legacyName), newName);
39+
return this;
40+
}
41+
42+
@Override
43+
public RenameRuleBuilder type(final String legacyType, final ClassDesc newType) {
44+
this.mappings.put(legacyType, toOwner(newType));
45+
return this;
46+
}
47+
48+
@Override
49+
public RenameRuleBuilder editEnum(final ClassDesc enumTypeDesc, final Consumer<EnumRenameBuilder> renamer) {
50+
final EnumRenameBuilder enumRenamerBuilder = new EnumRenameBuilder(enumTypeDesc);
51+
renamer.accept(enumRenamerBuilder);
52+
final EnumRenamer enumRenamer = enumRenamerBuilder.build();
53+
enumRenamer.fieldRenames().forEach((legacyName, newName) -> {
54+
this.field(enumTypeDesc, legacyName, newName);
55+
});
56+
this.enumValueOfFieldRenames.put(enumTypeDesc, enumRenamer);
57+
return this;
58+
}
59+
60+
@Override
61+
public RenameRule build() {
62+
return new RenameRule(this.mappings, this.enumValueOfFieldRenames);
63+
}
64+
}

0 commit comments

Comments
 (0)