From 2cdad9a48281540b7b0573c5fcb2185c772f8298 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Tue, 7 Feb 2023 16:20:36 +0100 Subject: feat: implemented descriptorbuilder, added feature to InsnSequence --- .../java/ftbsc/lll/tools/DescriptorBuilder.java | 141 +++++++++++++++++++++ src/main/java/ftbsc/lll/tools/InsnSequence.java | 17 +++ 2 files changed, 158 insertions(+) create mode 100644 src/main/java/ftbsc/lll/tools/DescriptorBuilder.java (limited to 'src/main/java/ftbsc/lll/tools') diff --git a/src/main/java/ftbsc/lll/tools/DescriptorBuilder.java b/src/main/java/ftbsc/lll/tools/DescriptorBuilder.java new file mode 100644 index 0000000..5cb6c6f --- /dev/null +++ b/src/main/java/ftbsc/lll/tools/DescriptorBuilder.java @@ -0,0 +1,141 @@ +package ftbsc.lll.tools; + +import jdk.internal.org.objectweb.asm.Type; + +import java.util.ArrayList; + +/** + * Builds a method descriptor for you. + * Parameters must be given in a specific order. + * Return type should always be specified for clarity, but defaults to void. + */ +public class DescriptorBuilder { + /** + * The descriptor of the return type. + */ + private String returnType; + + /** + * The descriptors of the parameters. + */ + private final ArrayList params; + + /** + * Public constructor. + * Initialises default values. + */ + public DescriptorBuilder() { + + this.returnType = Type.getDescriptor(void.class); + this.params = new ArrayList<>(); + } + + /** + * Sets the return type to the given type. + * WARNING: will most likely cause problems if used with objects outside the + * Java SDK. Pass the fully qualified name as a String rather than the Class + * object for non-standard types (such as Minecraft classes). + * @param returnType the Class object corresponding to the return type + * @return the builder's state after the change + */ + public DescriptorBuilder setReturnType(Class returnType) { + this.returnType = Type.getDescriptor(returnType); + return this; + } + + /** + * Sets the return type to the Object specified here as a fully + * qualified name. Example: java.lang.String. + * No validity checks are performed: it's up to the user to ensure the name is correct. + * @param returnType the fully qualified name of the desired Object. + * @return the builder's state after the change + */ + public DescriptorBuilder setReturnType(String returnType) { + return this.setReturnType(returnType, 0); + } + + /** + * Sets the return type to the Object specified here as a fully + * qualified name (example: java.lang.String), with the specified array level. + * No validity checks are performed: it's up to the user to ensure the name is correct. + * @param returnType the fully qualified name of the desired Object. + * @param arrayLevel how many levels of array are there + * (example: String is 0, String[] is 1, String[][] is 2, etc.) + * @return the builder's state after the change + */ + public DescriptorBuilder setReturnType(String returnType, int arrayLevel) { + this.returnType = nameToDescriptor(returnType, arrayLevel); + return this; + } + + /** + * Adds a parameter of the given class type to the method. + * Parameter order matters. + * WARNING: will most likely cause problems if used with objects outside the + * Java SDK. Pass the fully qualified name as a String rather than the Class + * object for non-standard types (such as Minecraft classes). + * @param param the Class object corresponding to the parameter + * @return the builder's state after the change + */ + public DescriptorBuilder addParameter(Class param) { + this.params.add(Type.getDescriptor(param)); + return this; + } + + /** + * Adds a parameter with the type specified by the given fully + * qualified name to the method. Example: java.lang.String. + * Parameter order matters. + * No validity checks are performed: it's up to the user to ensure the name is correct. + * @param param the fully qualified name of the parameter type + * @return the builder's state after the change + */ + public DescriptorBuilder addParameter(String param) { + return this.addParameter(param, 0); + } + + /** + * Adds a parameter with the type specified by the given fully + * qualified name (example: java.lang.String) to the method, with + * the specified array level. + * Parameter order matters. + * No validity checks are performed: it's up to the user to ensure the name is correct. + * @param param the fully qualified name of the parameter type + * @param arrayLevel how many levels of array are there + * (example: String is 0, String[] is 1, String[][] is 2, etc.) + * @return the builder's state after the change + */ + public DescriptorBuilder addParameter(String param, int arrayLevel) { + this.params.add(nameToDescriptor(param, arrayLevel)); + return this; + } + + /** + * Builds the descriptor into a string. + * Example result: int m(Object[] o) -> ([Ljava/lang/Object;)I + * @return the resulting descriptor + */ + public String build() { + StringBuilder sb = new StringBuilder(); + sb.append('('); + for(String p : params) + sb.append(p); + sb.append(')').append(returnType); + return sb.toString(); + } + + /** + * Converts a fully qualified name and array level to a descriptor. + * @param name the fully qualified name of the object type + * @param arrayLevel how many levels of array are there + * (example: String is 0, String[] is 1, String[][] is 2, etc.) + * @return object descriptor + */ + public static String nameToDescriptor(String name, int arrayLevel) { + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < arrayLevel; i++) + sb.append('['); + sb.append('L').append(name.replace('.', '/')).append(';'); + return sb.toString(); + } +} diff --git a/src/main/java/ftbsc/lll/tools/InsnSequence.java b/src/main/java/ftbsc/lll/tools/InsnSequence.java index f778590..4afd626 100644 --- a/src/main/java/ftbsc/lll/tools/InsnSequence.java +++ b/src/main/java/ftbsc/lll/tools/InsnSequence.java @@ -11,6 +11,14 @@ import java.util.Objects; * Extends InsnList, but provides additional flexibility. */ public class InsnSequence extends InsnList { + /** + * Public constructor. + * This creates an empty sequence. + */ + public InsnSequence() { + super(); + } + /** * Public constructor. * Must be given two non-null, connected nodes. @@ -41,6 +49,15 @@ public class InsnSequence extends InsnList { return this.toArray()[size() - index]; } + /** + * Adds an array of nodes to the list. + * @param nodes the nodes to add + */ + public void add(AbstractInsnNode... nodes) { + for(AbstractInsnNode node : nodes) + super.add(node); + } + /** * Replaces a node with another one. Mostly used internally. * @param oldNode node to replace -- cgit v1.2.3-56-ga3b1