Skip to content

Commit

Permalink
finish all 3 pos types
Browse files Browse the repository at this point in the history
  • Loading branch information
Machine-Maker committed Jul 28, 2023
1 parent 7919f6c commit c7f5c72
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 36 deletions.
137 changes: 102 additions & 35 deletions src/main/java/io/papermc/codebook/lvt/LvtAssignmentSuggester.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import static io.papermc.codebook.lvt.LvtUtil.capitalize;
import static io.papermc.codebook.lvt.LvtUtil.decapitalize;
import static io.papermc.codebook.lvt.LvtUtil.prevInsnIgnoringConvertCast;
import static io.papermc.codebook.lvt.LvtUtil.toJvmType;

import dev.denwav.hypo.asm.AsmClassData;
Expand Down Expand Up @@ -69,6 +70,7 @@ public class LvtAssignmentSuggester {
this::suggestNameForMcMthRandom,
LvtAssignmentSuggester::suggestNameForSectionPos,
LvtAssignmentSuggester::suggestNameForQuartPos,
LvtAssignmentSuggester::suggestNameForBlockPos,
LvtAssignmentSuggester::suggestNameFromGetter,
LvtAssignmentSuggester::suggestNameFromVerbBoolean,
this::suggestNameFromSingleWorldVerbBoolean,
Expand Down Expand Up @@ -273,7 +275,20 @@ enum PosType {
}
}

private record MethodPair(PosType returnType, PosType paramType) {}
private record MethodConfig(PosType returnType, PosType paramType, String prefix) {

private MethodConfig(final PosType returnType, final PosType paramType) {
this(returnType, paramType, "");
}

String varName(final String suffix) {
if (this.prefix.isEmpty()) {
return this.returnType.localName + suffix;
} else {
return this.prefix + capitalize(this.returnType.localName, 0) + suffix;
}
}
}

public static @Nullable String suggestNameForSectionPos(
final MethodNode enclosingMethodNode,
Expand All @@ -291,24 +306,25 @@ private record MethodPair(PosType returnType, PosType paramType) {}
case "x" -> "sectionX";
case "y" -> "sectionY";
case "z" -> "sectionZ";
case "blockToSection" -> "packedSectionPos";
case "blockToSection", "asLong" -> "packedSectionPos";
default -> null;
};
if (possibleSimpleName != null) {
return possibleSimpleName;
}

final @Nullable MethodPair methodPair =
final @Nullable MethodConfig methodConfig =
switch (method.name()) {
case "blockToSectionCoord" -> new MethodPair(PosType.SECTION, PosType.BLOCK);
case "sectionToBlockCoord" -> new MethodPair(PosType.BLOCK, PosType.SECTION);
case "blockToSectionCoord", "posToSectionCoord" -> new MethodConfig(PosType.SECTION, PosType.BLOCK);
case "sectionToBlockCoord" -> new MethodConfig(PosType.BLOCK, PosType.SECTION);
case "sectionRelative" -> new MethodConfig(PosType.BLOCK, PosType.BLOCK, "relative");
default -> null;
};

return getCoordLocalNameFromMethodPair(enclosingMethodNode, insn, methodPair);
return getCoordLocalNameFromMethodPair(enclosingMethodNode, insn, method, methodConfig);
}

public static @Nullable String suggestNameForQuartPos(
private static @Nullable String suggestNameForQuartPos(
final MethodNode enclosingMethodNode,
final AsmClassData owner,
final AsmMethodData method,
Expand All @@ -321,66 +337,117 @@ private record MethodPair(PosType returnType, PosType paramType) {}
return null;
}

final @Nullable MethodPair methodPair =
final @Nullable MethodConfig methodConfig =
switch (method.name()) {
case "fromBlock" -> new MethodPair(PosType.QUART, PosType.BLOCK);
case "toBlock" -> new MethodPair(PosType.BLOCK, PosType.QUART);
case "fromSection" -> new MethodPair(PosType.QUART, PosType.SECTION);
case "toSection" -> new MethodPair(PosType.SECTION, PosType.QUART);
case "fromBlock" -> new MethodConfig(PosType.QUART, PosType.BLOCK);
case "toBlock" -> new MethodConfig(PosType.BLOCK, PosType.QUART);
case "fromSection" -> new MethodConfig(PosType.QUART, PosType.SECTION);
case "toSection" -> new MethodConfig(PosType.SECTION, PosType.QUART);
default -> null;
};
if (methodPair == null) {
if (methodConfig == null) {
return null;
}

return getCoordLocalNameFromMethodPair(enclosingMethodNode, insn, methodPair);
return getCoordLocalNameFromMethodPair(enclosingMethodNode, insn, method, methodConfig);
}

private static @Nullable String suggestNameForBlockPos(
final MethodNode enclosingMethodNode,
final AsmClassData owner,
final AsmMethodData method,
final MethodInsnNode insn) {
if (!"net/minecraft/core/BlockPos".equals(owner.name())) {
return null;
}

final String suggestion;
if (method.name().equals("asLong")) {
suggestion = "packedBlockPos";
} else if (method.isStatic() && method.name().equals("offset") && method.returnType() == PrimitiveType.LONG) {
suggestion = "offsetPackedBlockPos";
} else {
return null;
}
return suggestion;
}

private static final String[] COMMON_PERSISTENT_PREFIXES = new String[] {"min", "max"};

private static @Nullable String getCoordLocalNameFromMethodPair(
final MethodNode enclosingMethodNode, final MethodInsnNode insn, final @Nullable MethodPair methodPair) {
if (methodPair == null) {
final MethodNode enclosingMethodNode,
final MethodInsnNode insn,
final AsmMethodData method,
final @Nullable MethodConfig methodConfig) {
if (methodConfig == null) {
return null;
}

final AbstractInsnNode prev = insn.getPrevious();
if (method.params().size() != 1) {
// add "Coord" since we don't know if its x, y, or z and more
// than 1 param makes it too complex to figure out
return methodConfig.varName("Coord");
}

final AbstractInsnNode prev = Objects.requireNonNull(prevInsnIgnoringConvertCast(insn));
@Nullable String suggestion = null;
if (prev instanceof final VarInsnNode varNode) {
final LocalVariableNode paramNode = findLocalVar(enclosingMethodNode, insn, varNode.var);
// get last character to account for "blockX", "biomeZ", etc.
final int possibleCoordIdx = getPossibleCoordIdx(paramNode.name);
if (possibleCoordIdx > -1
&& (paramNode.name.length() == 1
|| methodPair.paramType.possibleNames.contains(paramNode
.name
.substring(0, possibleCoordIdx)
.toLowerCase(Locale.ENGLISH)))) {
return methodPair.returnType.localName + Character.toUpperCase(paramNode.name.charAt(possibleCoordIdx));
}
final LocalVariableNode paramVarNode = findLocalVar(enclosingMethodNode, insn, varNode.var);
suggestion = suggestSpecificCoordName(methodConfig, paramVarNode.name, COMMON_PERSISTENT_PREFIXES);
} else if (prev instanceof final MethodInsnNode methodNode) {
final String name = methodNode.name.startsWith("get") ? methodNode.name.substring(3) : methodNode.name;
final int possibleCoordIdx = getPossibleCoordIdx(name);
if (possibleCoordIdx > -1) {
return methodPair.returnType.localName + Character.toUpperCase(name.charAt(possibleCoordIdx));
final @Nullable String strippedName =
methodNode.name.startsWith("get") ? decapitalize(methodNode.name, 3) : methodNode.name;
if (strippedName != null) {
suggestion = suggestSpecificCoordName(methodConfig, strippedName, COMMON_PERSISTENT_PREFIXES);
}
} else if (prev instanceof final FieldInsnNode fieldNode && fieldNode.getOpcode() == Opcodes.GETFIELD) {
suggestion = suggestSpecificCoordName(methodConfig, fieldNode.name, COMMON_PERSISTENT_PREFIXES);
}
return Objects.requireNonNullElseGet(
suggestion, () -> methodConfig.varName("Coord")); // add "Coord" since we don't know if its x, y, or z
}

return methodPair.returnType.localName;
private static @Nullable String suggestSpecificCoordName(
final MethodConfig methodConfig, final String fullName, final String... persistentPrefixes) {
String prefix = "";
if (fullName.length() > 1) {
for (final String persistentPrefix : persistentPrefixes) {
if (fullName.startsWith(persistentPrefix)) {
prefix = persistentPrefix;
break;
}
}
}
final String nameWithoutPrefix = fullName.substring(prefix.length());
final int possibleCoordIdx = getPossibleCoordIdx(nameWithoutPrefix);
if (possibleCoordIdx > -1
&& (nameWithoutPrefix.length() == 1
|| methodConfig.paramType.possibleNames.contains(
nameWithoutPrefix.substring(0, possibleCoordIdx).toLowerCase(Locale.ENGLISH)))) {
return methodConfig.varName(
capitalize(prefix, 0) + Character.toUpperCase(nameWithoutPrefix.charAt(possibleCoordIdx)));
}
return null;
}

private static int getPossibleCoordIdx(final String name) {
for (int i = name.length() - 1; i >= 0; i--) {
final char ch = Character.toUpperCase(name.charAt(i));
final char ch = name.charAt(i);
if (!Character.isAlphabetic(ch)) {
continue;
}
if (ch == 'X' || ch == 'Y' || ch == 'Z') {
if (isCoord(ch)) {
return i;
}
return -1;
}
return -1; // don't think this is possible
}

private static boolean isCoord(final char ch) {
return ch == 'X' || ch == 'Y' || ch == 'Z' || ch == 'x' || ch == 'y' || ch == 'z';
}

private static LocalVariableNode findLocalVar(
final MethodNode enclosingMethod, final AbstractInsnNode insn, final int varIdx) {
final List<LocalVariableNode> matching = new ArrayList<>();
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/io/papermc/codebook/lvt/LvtSuggester.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
package io.papermc.codebook.lvt;

import static dev.denwav.hypo.model.data.MethodDescriptor.parseDescriptor;
import static io.papermc.codebook.lvt.LvtUtil.prevInsnIgnoringConvertCast;
import static io.papermc.codebook.lvt.LvtUtil.toJvmType;

import dev.denwav.hypo.asm.AsmClassData;
Expand Down Expand Up @@ -127,7 +128,10 @@ private static String determineFinalName(final String suggestedName, final Set<S

private @Nullable String suggestNameFromFirstAssignment(
final MethodNode enclosingMethodNode, final VarInsnNode varInsn) throws IOException {
final AbstractInsnNode prev = varInsn.getPrevious();
final @Nullable AbstractInsnNode prev = prevInsnIgnoringConvertCast(varInsn);
if (prev == null) {
return null;
}
final int op = prev.getOpcode();
if (op != Opcodes.INVOKESTATIC && op != Opcodes.INVOKEVIRTUAL && op != Opcodes.INVOKEINTERFACE) {
return null;
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/io/papermc/codebook/lvt/LvtUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import dev.denwav.hypo.asm.HypoAsmUtil;
import dev.denwav.hypo.model.data.types.JvmType;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;

public final class LvtUtil {

Expand All @@ -36,6 +38,9 @@ public static JvmType toJvmType(final String desc) {
}

public static String capitalize(final String name, final int index) {
if (name.isEmpty()) {
return name;
}
return Character.toUpperCase(name.charAt(index)) + name.substring(index + 1);
}

Expand All @@ -49,4 +54,14 @@ public static String capitalize(final String name, final int index) {
return Character.toLowerCase(name.charAt(index)) + name.substring(index + 1);
}
}

public static @Nullable AbstractInsnNode prevInsnIgnoringConvertCast(final AbstractInsnNode insn) {
@Nullable AbstractInsnNode prev = insn.getPrevious();
while (prev != null
&& (prev.getOpcode() == Opcodes.CHECKCAST
|| (prev.getOpcode() >= Opcodes.I2L && prev.getOpcode() <= Opcodes.I2S))) {
prev = prev.getPrevious();
}
return prev;
}
}

0 comments on commit c7f5c72

Please sign in to comment.