Skip to content

Commit 495823a

Browse files
skip primitive unboxing (#26)
1 parent 8e81698 commit 495823a

3 files changed

Lines changed: 146 additions & 1 deletion

File tree

codebook-lvt/src/main/java/io/papermc/codebook/lvt/LvtUtil.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import dev.denwav.hypo.asm.HypoAsmUtil;
2626
import dev.denwav.hypo.model.data.types.JvmType;
2727
import java.util.List;
28+
import java.util.Locale;
2829
import java.util.function.Predicate;
2930
import org.checkerframework.checker.nullness.qual.Nullable;
3031
import org.objectweb.asm.Opcodes;
@@ -168,4 +169,14 @@ public static String parseSimpleTypeNameFromMethod(final String methodName, int
168169
}
169170
return prev;
170171
}
172+
173+
public static String staticFinalFieldNameToLocalName(final String fieldName) {
174+
final String[] split = fieldName.split("_");
175+
final StringBuilder builder = new StringBuilder();
176+
builder.append(split[0].toLowerCase(Locale.ENGLISH));
177+
for (int i = 1; i < split.length; i++) {
178+
builder.append(capitalize(split[i].toLowerCase(Locale.ENGLISH), 0));
179+
}
180+
return builder.toString();
181+
}
171182
}

codebook-lvt/src/main/java/io/papermc/codebook/lvt/RootLvtSuggester.java

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import dev.denwav.hypo.model.data.MethodData;
3434
import dev.denwav.hypo.model.data.MethodDescriptor;
3535
import dev.denwav.hypo.model.data.types.JvmType;
36+
import io.papermc.codebook.lvt.suggestion.ComplexGetSuggester;
3637
import io.papermc.codebook.lvt.suggestion.FluentGetterSuggester;
3738
import io.papermc.codebook.lvt.suggestion.GenericSuggester;
3839
import io.papermc.codebook.lvt.suggestion.LvtSuggester;
@@ -56,6 +57,7 @@
5657
import java.io.IOException;
5758
import java.util.List;
5859
import java.util.Set;
60+
import java.util.stream.Collectors;
5961
import org.checkerframework.checker.nullness.qual.Nullable;
6062
import org.objectweb.asm.Opcodes;
6163
import org.objectweb.asm.tree.AbstractInsnNode;
@@ -75,6 +77,7 @@ public final class RootLvtSuggester extends AbstractModule implements LvtSuggest
7577
MathSuggester.class,
7678
StringSuggester.class,
7779
PositionsSuggester.class,
80+
ComplexGetSuggester.class,
7881
NewPrefixSuggester.class,
7982
SingleVerbSuggester.class,
8083
VerbPrefixBooleanSuggester.class,
@@ -171,9 +174,53 @@ public static String determineFinalName(final String suggestedName, final Set<St
171174
}
172175
}
173176

177+
private static final Set<BoxMethod> BOX_METHODS = Set.of(
178+
new BoxMethod("java/lang/Byte", "byteValue", "()B"),
179+
new BoxMethod("java/lang/Short", "shortValue", "()S"),
180+
new BoxMethod("java/lang/Integer", "intValue", "()I"),
181+
new BoxMethod("java/lang/Long", "longValue", "()J"),
182+
new BoxMethod("java/lang/Float", "floatValue", "()F"),
183+
new BoxMethod("java/lang/Double", "doubleValue", "()D"),
184+
new BoxMethod("java/lang/Boolean", "booleanValue", "()Z"),
185+
new BoxMethod("java/lang/Character", "charValue", "()C"));
186+
private static final Set<String> BOX_METHOD_NAMES =
187+
BOX_METHODS.stream().map(BoxMethod::name).collect(Collectors.toUnmodifiableSet());
188+
189+
private record BoxMethod(String owner, String name, String desc) {
190+
boolean is(final MethodInsnNode node) {
191+
return this.owner.equals(node.owner)
192+
&& this.name.equals(node.name)
193+
&& this.desc.equals(node.desc)
194+
&& !node.itf;
195+
}
196+
}
197+
198+
private @Nullable AbstractInsnNode walkBack(final VarInsnNode assignmentNode) {
199+
AbstractInsnNode prev = assignmentNode.getPrevious();
200+
if (prev != null) {
201+
final int op = prev.getOpcode();
202+
if (op == Opcodes.INVOKEVIRTUAL) {
203+
final MethodInsnNode methodInsnNode = (MethodInsnNode) prev;
204+
if (BOX_METHOD_NAMES.contains(methodInsnNode.name)
205+
&& BOX_METHODS.stream().anyMatch(bm -> bm.is(methodInsnNode))) {
206+
prev = prev.getPrevious();
207+
if (prev != null && prev.getOpcode() == Opcodes.CHECKCAST) {
208+
return prev.getPrevious();
209+
}
210+
return prev;
211+
}
212+
}
213+
return prev;
214+
}
215+
return null;
216+
}
217+
174218
private @Nullable String suggestNameFromFirstAssignment(final MethodData parent, final VarInsnNode varInsn)
175219
throws IOException {
176-
final AbstractInsnNode prev = varInsn.getPrevious();
220+
final @Nullable AbstractInsnNode prev = this.walkBack(varInsn);
221+
if (prev == null) {
222+
return null;
223+
}
177224
final int op = prev.getOpcode();
178225
if (op != Opcodes.INVOKESTATIC && op != Opcodes.INVOKEVIRTUAL && op != Opcodes.INVOKEINTERFACE) {
179226
return null;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* codebook is a remapper utility for the PaperMC project.
3+
*
4+
* Copyright (c) 2023 Kyle Wood (DenWav)
5+
* Contributors
6+
*
7+
* This library is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU Lesser General Public
9+
* License as published by the Free Software Foundation;
10+
* version 3 only, no later versions.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20+
* USA
21+
*/
22+
23+
package io.papermc.codebook.lvt.suggestion;
24+
25+
import static io.papermc.codebook.lvt.LvtUtil.staticFinalFieldNameToLocalName;
26+
27+
import io.papermc.codebook.lvt.suggestion.context.ContainerContext;
28+
import io.papermc.codebook.lvt.suggestion.context.method.MethodCallContext;
29+
import io.papermc.codebook.lvt.suggestion.context.method.MethodInsnContext;
30+
import java.io.IOException;
31+
import java.util.Map;
32+
import java.util.Map.Entry;
33+
import java.util.Set;
34+
import org.checkerframework.checker.nullness.qual.Nullable;
35+
import org.objectweb.asm.Opcodes;
36+
import org.objectweb.asm.tree.AbstractInsnNode;
37+
import org.objectweb.asm.tree.FieldInsnNode;
38+
import org.objectweb.asm.tree.MethodInsnNode;
39+
40+
public class ComplexGetSuggester implements LvtSuggester {
41+
42+
private static final StaticFieldEntry BLOCK_STATE_PROPERTY = new StaticFieldEntry(
43+
Set.of(
44+
"net/minecraft/world/level/block/state/StateHolder",
45+
"net/minecraft/world/level/block/state/BlockState",
46+
"net/minecraft/world/level/block/state/BlockBehaviour$Properties",
47+
"net/minecraft/world/level/material/FluidState"),
48+
Set.of(Map.entry(
49+
"getValue", "(Lnet/minecraft/world/level/block/state/properties/Property;)Ljava/lang/Comparable;")),
50+
Set.of(
51+
"Lnet/minecraft/world/level/block/state/properties/IntegerProperty;",
52+
"Lnet/minecraft/world/level/block/state/properties/BooleanProperty;"),
53+
"Value");
54+
55+
@Override
56+
public @Nullable String suggestFromMethod(
57+
final MethodCallContext call, final MethodInsnContext insn, final ContainerContext container)
58+
throws IOException {
59+
final MethodInsnNode node = insn.node();
60+
if (BLOCK_STATE_PROPERTY.test(node)) {
61+
return BLOCK_STATE_PROPERTY.transform(node);
62+
}
63+
return null;
64+
}
65+
66+
private record StaticFieldEntry(
67+
Set<String> owners, Set<Entry<String, String>> methods, Set<String> fieldTypes, @Nullable String suffix) {
68+
69+
boolean test(final MethodInsnNode node) {
70+
return this.owners.contains(node.owner)
71+
&& this.methods.stream()
72+
.anyMatch(e ->
73+
e.getKey().equals(node.name) && e.getValue().equals(node.desc));
74+
}
75+
76+
@Nullable
77+
String transform(final MethodInsnNode node) {
78+
final AbstractInsnNode prev = node.getPrevious();
79+
if (prev instanceof final FieldInsnNode fieldInsnNode
80+
&& fieldInsnNode.getOpcode() == Opcodes.GETSTATIC
81+
&& this.fieldTypes.contains(fieldInsnNode.desc)) {
82+
return staticFinalFieldNameToLocalName(fieldInsnNode.name) + (this.suffix == null ? "" : this.suffix);
83+
}
84+
return null;
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)