Skip to content

Commit f21db75

Browse files
Handle fluent getters for primitive return types (#9)
Co-authored-by: MiniDigger | Martin <admin@benndorf.dev>
1 parent 71c74c5 commit f21db75

4 files changed

Lines changed: 107 additions & 1 deletion

File tree

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ private String suggestNameFromClassType(final ClassType type) throws IOException
104104
// TODO Try to determine name from signature, rather than just descriptor
105105
final @Nullable ClassData typeClass = this.context.getContextProvider().findClass(type);
106106
if (typeClass != null) {
107-
if (typeClass.doesExtendOrImplement(this.listClass) && !typeClass.name().startsWith("net/minecraft/nbt/")) { // exclude nbt lists
107+
if (typeClass.doesExtendOrImplement(this.listClass)
108+
&& !typeClass.name().startsWith("net/minecraft/nbt/")) { // exclude nbt lists
108109
return "list";
109110
} else if (typeClass.doesExtendOrImplement(this.setClass)) {
110111
return "set";

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

Lines changed: 2 additions & 0 deletions
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.FluentGetterSuggester;
3637
import io.papermc.codebook.lvt.suggestion.GenericSuggester;
3738
import io.papermc.codebook.lvt.suggestion.LvtSuggester;
3839
import io.papermc.codebook.lvt.suggestion.MathSuggester;
@@ -76,6 +77,7 @@ public final class RootLvtSuggester extends AbstractModule implements LvtSuggest
7677
SingleVerbSuggester.class,
7778
VerbPrefixBooleanSuggester.class,
7879
SingleVerbBooleanSuggester.class,
80+
FluentGetterSuggester.class,
7981
RecordComponentSuggester.class,
8082
GenericSuggester.class);
8183

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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 dev.denwav.hypo.model.data.types.PrimitiveType;
26+
import io.papermc.codebook.lvt.suggestion.context.ContainerContext;
27+
import io.papermc.codebook.lvt.suggestion.context.method.MethodCallContext;
28+
import io.papermc.codebook.lvt.suggestion.context.method.MethodInsnContext;
29+
import java.io.IOException;
30+
import java.util.Set;
31+
import java.util.function.IntPredicate;
32+
import org.checkerframework.checker.nullness.qual.Nullable;
33+
import org.objectweb.asm.Opcodes;
34+
import org.objectweb.asm.tree.AbstractInsnNode;
35+
import org.objectweb.asm.tree.InsnList;
36+
37+
public class FluentGetterSuggester implements LvtSuggester {
38+
39+
private static final Set<String> ignored = Set.of(
40+
"byteValue",
41+
"shortValue",
42+
"intValue",
43+
"longValue",
44+
"floatValue",
45+
"doubleValue",
46+
"booleanValue",
47+
"charValue",
48+
"get");
49+
50+
// 3 instructions, load "this" local var, getfield, return - TODO maybe if there is a CAST,
51+
private static final IntPredicate[] OPCODES_IN_ORDER = new IntPredicate[] {
52+
i -> i == Opcodes.ALOAD, i -> i == Opcodes.GETFIELD, i -> i >= Opcodes.IRETURN && i <= Opcodes.RETURN
53+
};
54+
55+
@Override
56+
public @Nullable String suggestFromMethod(
57+
final MethodCallContext call, final MethodInsnContext insn, final ContainerContext container)
58+
throws IOException {
59+
// I think it's best to only work with primitive types here, as other types should already have names
60+
// and this dramatically cuts down on the number of methods analyzed because we aren't filtering by
61+
// method name
62+
if (!(call.data().returnType() instanceof PrimitiveType)
63+
|| !call.data().params().isEmpty()) {
64+
return null;
65+
}
66+
int opcodeIndex = 0;
67+
final InsnList instructions = call.node().instructions;
68+
if (instructions.size() == 0) {
69+
return null;
70+
}
71+
for (final AbstractInsnNode methodInsn : instructions) {
72+
if (methodInsn.getOpcode() == -1) {
73+
continue;
74+
}
75+
if (opcodeIndex == OPCODES_IN_ORDER.length) {
76+
break; // matched the correct order
77+
}
78+
if (OPCODES_IN_ORDER[opcodeIndex].test(methodInsn.getOpcode())) {
79+
opcodeIndex++;
80+
} else {
81+
return null;
82+
}
83+
}
84+
if (call.data().isStatic()) { // limit static matches
85+
if ("java/lang/System".equals(insn.node().owner) && "currentTimeMillis".equals(insn.node().name)) {
86+
return "currentTimeMillis";
87+
}
88+
} else {
89+
final String name = call.data().name();
90+
if (ignored.contains(name)) {
91+
return null;
92+
}
93+
return name;
94+
}
95+
return null;
96+
}
97+
}

src/test/java/io/papermc/codebook/lvt/LvtAssignmentSuggesterTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@
5656
import org.mockito.junit.jupiter.MockitoSettings;
5757
import org.mockito.quality.Strictness;
5858
import org.objectweb.asm.Opcodes;
59+
import org.objectweb.asm.tree.InsnList;
5960
import org.objectweb.asm.tree.MethodInsnNode;
61+
import org.objectweb.asm.tree.MethodNode;
6062

6163
@ExtendWith(MockitoExtension.class)
6264
@MockitoSettings(strictness = Strictness.LENIENT)
@@ -125,6 +127,10 @@ void testSuggester(
125127
when(method.param(anyInt())).thenCallRealMethod();
126128
when(method.returnType()).thenCallRealMethod();
127129

130+
final MethodNode node = new MethodNode(Opcodes.ASM9, methodName, methodDescriptor, null, null);
131+
node.instructions = new InsnList();
132+
when(method.getNode()).thenReturn(node);
133+
128134
if (methodOwner.equals(HypoModelUtil.normalizedClassName(RANDOM_SOURCE_TYPE.asInternalName()))) {
129135
when(owner.doesExtendOrImplement(this.randomSourceClass)).thenReturn(true);
130136
} else {

0 commit comments

Comments
 (0)