Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 204 additions & 1 deletion src/main/java/net/minecraftforge/coremod/api/ASMAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Objects;
import java.util.Optional;
Expand All @@ -29,8 +30,210 @@
* Helper methods for working with ASM.
*/
public class ASMAPI {
/**
* Creates a new empty {@link MethodNode}.
*
* @return The created method node
*
* @see MethodNode#MethodNode(int)
*/
public static MethodNode getMethodNode() {
return new MethodNode(Opcodes.ASM9);
var method = new MethodNode(Opcodes.ASM9);

// ASM usually creates an empty list for null exceptions on the other constructors
// let's do this as well, just to make sure we don't run into problems later.
method.exceptions = new ArrayList<>();

return method;
}

/**
* Creates a new empty {@link MethodNode} with the given access codes, name and descriptor.
*
* @param access The access codes
* @param name The method name
* @param descriptor The method descriptor
* @return The created method node
*
* @see MethodNode#MethodNode(int, int, String, String, String, String[])
*/
public static MethodNode getMethodNode(int access, String name, String descriptor) {
return new MethodNode(Opcodes.ASM9, access, name, descriptor, null, null);
}

/**
* Creates a new empty {@link MethodNode} with the given access codes, name, descriptor, and signature.
*
* @param access The access codes
* @param name The method name
* @param descriptor The method descriptor
* @param signature The method signature
* @return The created method node
*
* @see MethodNode#MethodNode(int, int, String, String, String, String[])
*/
public static MethodNode getMethodNode(int access, String name, String descriptor, @Nullable String signature) {
return new MethodNode(Opcodes.ASM9, access, name, descriptor, signature, null);
}

/**
* Creates a new empty {@link MethodNode} with the given access codes, name, descriptor, signature, and exceptions.
*
* @param access The access codes
* @param name The method name
* @param descriptor The method descriptor
* @param signature The method signature
* @param exceptions The internal names of the method's exceptions
* @return The created method node
*
* @see MethodNode#MethodNode(int, int, String, String, String, String[])
*/
public static MethodNode getMethodNode(int access, String name, String descriptor, @Nullable String signature, @Nullable String[] exceptions) {
return new MethodNode(Opcodes.ASM9, access, name, descriptor, signature, exceptions);
}

/**
* Creates a new empty {@link FieldNode} with the given access codes, name, and descriptor.
*
* @param access The access codes
* @param name The field name
* @param descriptor The field descriptor
* @return The created field node
*
* @see FieldNode#FieldNode(int, int, String, String, String, Object)
*/
public static FieldNode getFieldNode(int access, String name, String descriptor) {
return new FieldNode(Opcodes.ASM9, access, name, descriptor, null, null);
}

/**
* Creates a new empty {@link FieldNode} with the given access codes, name, descriptor, and signature.
*
* @param access The access codes
* @param name The field name
* @param descriptor The field descriptor
* @param signature The field signature
* @return The created field node
*
* @see FieldNode#FieldNode(int, int, String, String, String, Object)
*/
public static FieldNode getFieldNode(int access, String name, String descriptor, @Nullable String signature) {
return new FieldNode(Opcodes.ASM9, access, name, descriptor, signature, null);
}

/**
* Creates a new empty {@link FieldNode} with the given access codes, name, descriptor, signature, and initial
* object value.
*
* @param access The access codes
* @param name The field name
* @param descriptor The field descriptor
* @param signature The field signature
* @param value The initial value of the field
* @return The created field node
*
* @see FieldNode#FieldNode(int, int, String, String, String, Object)
*/
public static FieldNode getFieldNode(int access, String name, String descriptor, @Nullable String signature, String value) {
return new FieldNode(Opcodes.ASM9, access, name, descriptor, signature, value);
}

/**
* Creates a new empty {@link FieldNode} with the given access codes, name, descriptor, signature, and initial
* number value.
*
* @param access The access codes
* @param name The field name
* @param descriptor The field descriptor
* @param signature The field signature
* @param value The initial value of the field
* @param valueType The number type of the initial value
* @return The created field node
*
* @see FieldNode#FieldNode(int, int, String, String, String, Object)
*/
public static FieldNode getFieldNode(int access, String name, String descriptor, @Nullable String signature, Number value, NumberType valueType) {
return new FieldNode(Opcodes.ASM9, access, name, descriptor, signature, castNumber(value, valueType));
}

/**
* Finds the first method node from the given class node that matches the given name and descriptor.
*
* @param clazz The class node to search
* @param name The name of the desired method
* @param desc The descriptor of the desired method
* @return The found method node or null if none matched
*/
public static @Nullable MethodNode findMethodNode(ClassNode clazz, String name, String desc) {
return findMethodNode(clazz, name, desc, null, false);
}

/**
* Finds the first method node from the given class node that matches the given name, descriptor, and signature.
*
* @param clazz The class node to search
* @param name The name of the desired method
* @param desc The descriptor of the desired method
* @param signature The signature of the desired method
* @return The found method node or null if none matched
*
* @apiNote This method will attempt to match the signature of the method, even if it is {@code null}. It may be
* useful for that use case in particular. If you have no need to match the signature, consider using
* {@link #findMethodNode(ClassNode, String, String)}
*/
public static @Nullable MethodNode findMethodNode(ClassNode clazz, String name, String desc, @Nullable String signature) {
return findMethodNode(clazz, name, desc, signature, true);
}

private static @Nullable MethodNode findMethodNode(ClassNode clazz, String name, String desc, @Nullable String signature, boolean checkSignature) {
for (MethodNode method : clazz.methods) {
// we have to use Objects.equals here in case the found method has null attributes
if (Objects.equals(method.name, name) && Objects.equals(method.desc, desc) && (!checkSignature || Objects.equals(method.signature, signature))) {
return method;
}
}

return null;
}

/**
* Finds the first field node from the given class node that matches the given name and descriptor.
*
* @param clazz The class node to search
* @param name The name of the desired field
* @param desc The descriptor of the desired field
* @return The found field node or null if none matched
*/
public static @Nullable FieldNode findFieldNode(ClassNode clazz, String name, String desc) {
return findFieldNode(clazz, name, desc, null, false);
}

/**
* Finds the first field node from the given class node that matches the given name, descriptor, and signature.
*
* @param clazz The class node to search
* @param name The name of the desired field
* @param desc The descriptor of the desired field
* @param signature The signature of the desired field
* @return The found field node or null if none matched
*
* @apiNote This method will attempt to match the signature of the field, even if it is {@code null}. It may be
* useful for that use case in particular. If you have no need to match the signature, consider using
* {@link #findFieldNode(ClassNode, String, String)}
*/
public static @Nullable FieldNode findFieldNode(ClassNode clazz, String name, String desc, @Nullable String signature) {
return findFieldNode(clazz, name, desc, signature, true);
}

private static @Nullable FieldNode findFieldNode(ClassNode clazz, String name, String desc, @Nullable String signature, boolean checkSignature) {
for (FieldNode field : clazz.fields) {
// we have to use Objects.equals here in case the found field has null attributes
if (Objects.equals(field.name, name) && Objects.equals(field.desc, desc) && (!checkSignature || Objects.equals(field.signature, signature))) {
return field;
}
}

return null;
}

/**
Expand Down