From 12955162326c89f1c6cf44e130efa80c9145f934 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Tue, 21 Mar 2023 12:27:27 +0100 Subject: feat: initial proxy rework, replaced getters with public constants, rely more on ow2 Types instead of homebrew solutions --- src/main/java/ftbsc/lll/proxies/AbstractProxy.java | 98 ++++++++++++---------- 1 file changed, 54 insertions(+), 44 deletions(-) (limited to 'src/main/java/ftbsc/lll/proxies/AbstractProxy.java') diff --git a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java index 1ee19a8..4dd2a72 100644 --- a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java +++ b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java @@ -1,5 +1,7 @@ package ftbsc.lll.proxies; +import org.objectweb.asm.Type; + /** * Abstract proxy class, implementing common aspects * of {@link MethodProxy} and {@link FieldProxy}. @@ -8,57 +10,38 @@ package ftbsc.lll.proxies; public abstract class AbstractProxy { /** - * The name of the corresponding class member. + * The name of the corresponding element. */ - private final String name; + public final String name; - /** - * The fully qualified name (i.e. java.lang.String) of - * the parent class. - */ - private final String parent; /** - * The modifiers of the member, as a packed int. - * @see java.lang.reflect.Modifier + * The {@link Type} corresponding to this element. */ - private final int modifiers; + public final Type type; /** - * @return the name of the item + * The fully qualified name (i.e. java.lang.String) of + * the parent class. */ - public String getName() { - return this.name; - } + public final String parent; /** - * @return the modifiers of the member, as a packed int + * The modifiers of the element, as a packed int. * @see java.lang.reflect.Modifier */ - public int getModifiers() { - return this.modifiers; - } - - /** - * @return the fully qualified name of the parent class - */ - public String getParent() { - return this.parent; - } - - /** - * @return the descriptor of the member - */ - public abstract String getDescriptor(); + public final int modifiers; /** * The private constructor, should be called by all classes extending this in theirs. - * @param name the name of the member + * @param name the name of the element + * @param type the {@link Type} for the element * @param modifiers the modifiers, as a packed int * @param parent the FQN of the parent class */ - protected AbstractProxy(String name, int modifiers, String parent) { + protected AbstractProxy(String name, Type type, int modifiers, String parent) { this.name = name; + this.type = type; this.modifiers = modifiers; this.parent = parent; } @@ -70,12 +53,12 @@ public abstract class AbstractProxy { public abstract static class Builder { /** - * The name of the member. + * The name of the element. */ - protected final String name; + protected String name; /** - * The modifiers of the member, as a packed int. + * The modifiers of the element, as a packed int. */ protected int modifiers; @@ -84,15 +67,39 @@ public abstract class AbstractProxy { */ protected String parent; + /** + * The {@link Type} corresponding to the element. + */ + protected Type type; + /** * The constructor. - * @param name the name of the member + * @param name the name of the element */ protected Builder(String name) { this.name = name; this.modifiers = 0; } + + /** + * @param newModifier the modifier to add + * @return the current state of the builder + */ + public Builder addModifier(int newModifier) { + this.modifiers |= newModifier; + return this; + } + + /** + * @param newModifier the new modifier value + * @return the current state of the builder + */ + public Builder setModifiers(int newModifier) { + this.modifiers = newModifier; + return this; + } + /** * @param parentFQN the fully qualified name of the parent * @return the current state of the builder @@ -103,23 +110,26 @@ public abstract class AbstractProxy { } /** - * @param newModifier the modifier to add + * @param type the {@link Type} corresponding to the element * @return the current state of the builder */ - public Builder addModifier(int newModifier) { - this.modifiers |= newModifier; + public Builder setType(Type type) { + this.type = type; return this; } + /** - * @param newModifier the new modifier value - * @return the current state of the builder + * Sets {@link Type} for this element from the descriptor, passed as a {@link String}. + * @param descriptor the descriptor passed as a {@link String} + * @return the builder's state after the change */ - public Builder setModifier(int newModifier) { - this.modifiers = newModifier; - return this; + public Builder setDescriptor(String descriptor) { + return this.setType(Type.getType(descriptor)); } + + /** * @return the built proxy object */ -- cgit v1.2.3-56-ga3b1 From 884cefead9e4fede7243650afc4f22f08f8e5090 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Tue, 21 Mar 2023 16:32:19 +0100 Subject: feat: expanded ClassProxies, now all fields and methods include classproxies to represent their parents (as well as parameters and return type for methods) --- src/main/java/ftbsc/lll/proxies/AbstractProxy.java | 33 ++++-- src/main/java/ftbsc/lll/proxies/ClassProxy.java | 122 ++++++++++----------- src/main/java/ftbsc/lll/proxies/FieldProxy.java | 37 ++++++- src/main/java/ftbsc/lll/proxies/MethodProxy.java | 86 +++++++++++---- src/main/java/ftbsc/lll/proxies/PackageProxy.java | 51 +++++++++ .../java/ftbsc/lll/proxies/QualifiableProxy.java | 68 ++++++++++++ .../ftbsc/lll/tools/nodes/FieldProxyInsnNode.java | 7 +- .../ftbsc/lll/tools/nodes/MethodProxyInsnNode.java | 7 +- 8 files changed, 298 insertions(+), 113 deletions(-) create mode 100644 src/main/java/ftbsc/lll/proxies/PackageProxy.java create mode 100644 src/main/java/ftbsc/lll/proxies/QualifiableProxy.java (limited to 'src/main/java/ftbsc/lll/proxies/AbstractProxy.java') diff --git a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java index 4dd2a72..93eaec8 100644 --- a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java +++ b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java @@ -14,7 +14,6 @@ public abstract class AbstractProxy { */ public final String name; - /** * The {@link Type} corresponding to this element. */ @@ -24,7 +23,7 @@ public abstract class AbstractProxy { * The fully qualified name (i.e. java.lang.String) of * the parent class. */ - public final String parent; + public final QualifiableProxy parent; /** * The modifiers of the element, as a packed int. @@ -39,13 +38,29 @@ public abstract class AbstractProxy { * @param modifiers the modifiers, as a packed int * @param parent the FQN of the parent class */ - protected AbstractProxy(String name, Type type, int modifiers, String parent) { + protected AbstractProxy(String name, Type type, int modifiers, QualifiableProxy parent) { this.name = name; this.type = type; this.modifiers = modifiers; this.parent = parent; } + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + if(obj instanceof AbstractProxy) { + AbstractProxy p = (AbstractProxy) obj; + return p.parent.equals(this.parent) + && p.name.equals(this.name) + && p.modifiers == this.modifiers + && p.type.equals(this.type); + } else return false; + } + /** * A Builder for the generic proxy. * @param the type of proxy @@ -65,7 +80,7 @@ public abstract class AbstractProxy { /** * The fully qualified name of the parent. */ - protected String parent; + protected QualifiableProxy parent; /** * The {@link Type} corresponding to the element. @@ -81,7 +96,6 @@ public abstract class AbstractProxy { this.modifiers = 0; } - /** * @param newModifier the modifier to add * @return the current state of the builder @@ -101,11 +115,11 @@ public abstract class AbstractProxy { } /** - * @param parentFQN the fully qualified name of the parent + * @param parent the {@link QualifiableProxy} representing the parent * @return the current state of the builder */ - public Builder setParent(String parentFQN) { - this.parent = parentFQN; + public Builder setParent(QualifiableProxy parent) { + this.parent = parent; return this; } @@ -118,7 +132,6 @@ public abstract class AbstractProxy { return this; } - /** * Sets {@link Type} for this element from the descriptor, passed as a {@link String}. * @param descriptor the descriptor passed as a {@link String} @@ -128,8 +141,6 @@ public abstract class AbstractProxy { return this.setType(Type.getType(descriptor)); } - - /** * @return the built proxy object */ diff --git a/src/main/java/ftbsc/lll/proxies/ClassProxy.java b/src/main/java/ftbsc/lll/proxies/ClassProxy.java index c369231..41e9bb8 100644 --- a/src/main/java/ftbsc/lll/proxies/ClassProxy.java +++ b/src/main/java/ftbsc/lll/proxies/ClassProxy.java @@ -2,36 +2,25 @@ package ftbsc.lll.proxies; import org.objectweb.asm.Type; +import java.lang.reflect.Modifier; + +import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; + /** * A container for information about classes to be used * in ASM patching. * @since 0.4.0 */ -public class ClassProxy extends AbstractProxy { - - /** - * The fully-qualified name of the class represented by this proxy. - */ - public final String fqn; - - /** - * The {@link ClassProxy} representing the class which contains the - * class represented by this proxy. May be null if the class represented - * by this proxy is not an inner class. - */ - public final ClassProxy containerClass; - +public class ClassProxy extends QualifiableProxy { /** * Protected constructor, called only from the builder. * @param name the name of the class * @param type the {@link Type} of the class * @param modifiers the modifiers of the class - * @param parent the FQN of the parent class of the class + * @param parent the package containing this class */ protected ClassProxy(String name, Type type, int modifiers, String parent) { - super(name, type, modifiers, parent); - this.fqn = String.format("%s.%s", name, parent); - this.containerClass = null; + super(type, modifiers, PackageProxy.from(parent), String.format("%s.%s", name, parent)); } /** @@ -41,31 +30,35 @@ public class ClassProxy extends AbstractProxy { * @param modifiers the modifiers of the class * @param containerClass the FQN of the parent class of the class */ - protected ClassProxy(String name, Type type, int modifiers, ClassProxy containerClass) { - super(name, type, modifiers, containerClass.fqn); - this.fqn = String.format("%s$%s", name, parent); - this.containerClass = containerClass; + protected ClassProxy(String name, Type type, int modifiers, QualifiableProxy containerClass) { + super(type, modifiers, containerClass, String.format("%s$%s", name, containerClass.fullyQualifiedName)); + } + + /** + * Builds a {@link ClassProxy} from a {@link Type} and modifiers. + * @param type the {@link Type} representing this Class + * @param modifiers the modifiers of the class + */ + public static ClassProxy from(Type type, int modifiers) { + String fqn = type.getInternalName().replace('/', '.'); + String simpleName = extractSimpleNameFromFQN(fqn); + String parent = extractParentFromFQN(fqn); + if(fqn.contains("$")) + return new ClassProxy(simpleName, type, modifiers, from(parent, 0, Modifier.PUBLIC)); + else return new ClassProxy(simpleName, type, modifiers, parent); } /** * Builds a {@link ClassProxy} given only the fully-qualified name and modifiers. * @param fqn the fully qualified name of the desired class + * @param arrayLevel the array level for this type * @param modifiers the access modifiers of the desired class + * @implNote If present, parent classes will be assumed to have {@code public} as + * their only modifier. * @return the built {@link ClassProxy} */ - protected static ClassProxy from(String fqn, int modifiers) { - Type type = Type.getObjectType(fqn.replace('.', '/')); - if(fqn.contains("$")) { - String[] split = fqn.split("\\$"); - String simpleName = split[split.length - 1]; - ClassProxy parentClass = from(fqn.replace("$" + simpleName, ""), 0); - return new ClassProxy(simpleName, type, modifiers, parentClass); - } else { - String[] split = fqn.split("\\."); - String simpleName = split[split.length - 1]; - String parent = fqn.replace("." + simpleName, ""); - return new ClassProxy(simpleName, type, modifiers, parent); - } + protected static ClassProxy from(String fqn, int arrayLevel, int modifiers) { + return from(Type.getObjectType(nameToDescriptor(fqn, arrayLevel)), modifiers); } /** @@ -73,8 +66,9 @@ public class ClassProxy extends AbstractProxy { * @param clazz the {@link Class} object representing the target class * @return the built {@link ClassProxy} */ - protected static ClassProxy from(Class clazz) { - if(clazz.getEnclosingClass() == null) + public static ClassProxy from(Class clazz) { + Class parentClass = clazz.getEnclosingClass(); + if(parentClass == null) return new ClassProxy( clazz.getSimpleName(), Type.getType(clazz), @@ -86,7 +80,7 @@ public class ClassProxy extends AbstractProxy { clazz.getSimpleName(), Type.getType(clazz), clazz.getModifiers(), - from(clazz.getEnclosingClass()) + from(parentClass) ); } @@ -99,20 +93,27 @@ public class ClassProxy extends AbstractProxy { return new Builder(name); } + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof ClassProxy && super.equals(obj); + } + /** * A builder object for {@link ClassProxy}. */ public static class Builder extends AbstractProxy.Builder { - - private ClassProxy containerClass; - + /** * The constructor of the builder, used only internally. * @param name the "simple name" of the class */ Builder(String name) { super(name); - this.containerClass = null; } /** @@ -122,42 +123,33 @@ public class ClassProxy extends AbstractProxy { * container class * @return the builder's state after the change */ - public Builder setContainerClass(Class containerClass) { - this.containerClass = ClassProxy.from(containerClass); - return this; - } - - /** - * Sets this class as an inner class and sets the containing - * class to the given proxy. - * @param containerClass the {@link ClassProxy} representing - * the container class - * @return the builder's state after the change - */ - public Builder setContainerClass(ClassProxy containerClass) { - this.containerClass = containerClass; + public Builder setParent(Class containerClass) { + super.setParent(ClassProxy.from(containerClass)); return this; } /** * Sets this class as an inner class and builds a {@link ClassProxy} * from the given parent and modifiers. - * @param parentFQN the fully qualified name of the parent + * @param parentFQN the fully qualified name of the parent + * @param modifiers the modifiers of the parent (if it's a class) + * @param isParentPackage whether this parent should be interpreted as a package or class * @return the builder's state after the change */ - public Builder setParent(String parentFQN, int modifiers) { - return this.setContainerClass(ClassProxy.from(parentFQN, modifiers)); + public Builder setParent(String parentFQN, int modifiers, boolean isParentPackage) { + super.setParent(isParentPackage ? PackageProxy.from(parentFQN) : ClassProxy.from(parentFQN, 0, modifiers)); + return this; } /** * Sets this class as an inner class and builds a {@link ClassProxy} * from the given parent. - * @param parentFQN the fully qualified name of the parent + * @param parentFQN the fully qualified name of the parent + * @param isParentPackage whether this parent should be interpreted as a package or class * @return the builder's state after the change */ - @Override - public Builder setParent(String parentFQN) { - return this.setParent(parentFQN, 0); + public Builder setParent(String parentFQN, boolean isParentPackage) { + return this.setParent(parentFQN, 0, isParentPackage); } /** @@ -166,9 +158,7 @@ public class ClassProxy extends AbstractProxy { */ @Override public ClassProxy build() { - if(this.containerClass == null) - return new ClassProxy(this.name, this.type, this.modifiers, this.parent); - else return new ClassProxy(this.name, this.type, this.modifiers, this.containerClass); + return new ClassProxy(this.name, this.type, this.modifiers, this.parent); } } } \ No newline at end of file diff --git a/src/main/java/ftbsc/lll/proxies/FieldProxy.java b/src/main/java/ftbsc/lll/proxies/FieldProxy.java index 72a4e40..8855cd8 100644 --- a/src/main/java/ftbsc/lll/proxies/FieldProxy.java +++ b/src/main/java/ftbsc/lll/proxies/FieldProxy.java @@ -16,7 +16,7 @@ public class FieldProxy extends AbstractProxy { * @param f the {@link Field} object corresponding to this. */ public FieldProxy(Field f) { - super(f.getName(), Type.getType(f.getType()), f.getModifiers(), Type.getInternalName(f.getDeclaringClass())); + super(f.getName(), Type.getType(f.getType()), f.getModifiers(), ClassProxy.from(f.getDeclaringClass())); } /** @@ -24,9 +24,9 @@ public class FieldProxy extends AbstractProxy { * @param name the name of the field * @param type the {@link Type} of the field * @param modifiers the modifiers of the field - * @param parent the FQN of the parent class of the field + * @param parent the {@link QualifiableProxy} for the parent */ - protected FieldProxy(String name, Type type, int modifiers, String parent) { + protected FieldProxy(String name, Type type, int modifiers, QualifiableProxy parent) { super(name, type, modifiers, parent); } @@ -39,6 +39,16 @@ public class FieldProxy extends AbstractProxy { return new Builder(name); } + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof FieldProxy && super.equals(obj); + } + /** * A builder object for {@link FieldProxy}. */ @@ -51,6 +61,27 @@ public class FieldProxy extends AbstractProxy { super(name); } + /** + * Sets the parent class of this field to the one described by the + * fully qualified name and with the given modifiers. + * @param parentFQN the fully qualified name of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, int modifiers) { + super.setParent(ClassProxy.from(parentFQN, 0, modifiers)); + return this; + } + + /** + * Sets the parent class of this field to the one described by the + * fully qualified name. + * @param parentFQN the fully qualified name of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN) { + return this.setParent(parentFQN, 0); + } + /** * Builds a {@link FieldProxy} of the given kind. * @return the built {@link FieldProxy} diff --git a/src/main/java/ftbsc/lll/proxies/MethodProxy.java b/src/main/java/ftbsc/lll/proxies/MethodProxy.java index 5f80c08..5d014e9 100644 --- a/src/main/java/ftbsc/lll/proxies/MethodProxy.java +++ b/src/main/java/ftbsc/lll/proxies/MethodProxy.java @@ -4,6 +4,7 @@ import org.objectweb.asm.Type; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; @@ -16,39 +17,43 @@ import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; public class MethodProxy extends AbstractProxy { /** - * The parameters of the method. + * An array of {@link ClassProxy} each representing the parameters of the method. */ - public final Type[] parameters; + public final ClassProxy[] parameters; /** - * The return type of the method. + * The {@link ClassProxy} for the return type of the method. */ - public final Type returnType; - - /** - * A public constructor, builds a proxy from a {@link Method} - * obtained from reflection. - * @param m the {@link Method} object corresponding to this. - */ - public MethodProxy(Method m) { - super(m.getName(), Type.getType(m), m.getModifiers(), Type.getInternalName(m.getDeclaringClass())); - Type mt = Type.getType(m); - this.parameters = mt.getArgumentTypes(); - this.returnType = mt.getReturnType(); - } + public final ClassProxy returnType; /** * A protected constructor, called only from the builder. * @param name the name of the method * @param modifiers the modifiers of the method - * @param parent the FQN of the parent class of the method + * @param parent the {@link QualifiableProxy} for the parent * @param parameters the parameters of the method * @param returnType the return type of the method */ - protected MethodProxy(String name, int modifiers, String parent, Type[] parameters, Type returnType) { + protected MethodProxy(String name, int modifiers, QualifiableProxy parent, Type[] parameters, Type returnType) { super(name, Type.getMethodType(returnType, parameters), modifiers, parent); - this.parameters = parameters; - this.returnType = returnType; + this.parameters = Arrays.stream(parameters) + .map(t -> ClassProxy.from(t, 0)) + .toArray(ClassProxy[]::new); + this.returnType = ClassProxy.from(returnType, 0); + } + + /** + * A public constructor, builds a proxy from a {@link Method} + * obtained from reflection. + * @param m the {@link Method} object corresponding to this. + */ + public MethodProxy(Method m) { + this(m.getName(), + m.getModifiers(), + ClassProxy.from(m.getDeclaringClass()), + Type.getArgumentTypes(m), + Type.getReturnType(m) + ); } /** @@ -60,6 +65,19 @@ public class MethodProxy extends AbstractProxy { return new Builder(name); } + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + if(obj instanceof MethodProxy) { + MethodProxy m = (MethodProxy) obj; + return super.equals(obj) && m.returnType.equals(this.returnType) && Arrays.equals(m.parameters, this.parameters); + } else return false; + } + /** * A builder object for {@link MethodProxy}. */ @@ -117,6 +135,27 @@ public class MethodProxy extends AbstractProxy { return this; } + /** + * Sets the parent class of this method to the one described by the + * fully qualified name and with the given modifiers. + * @param parentFQN the fully qualified name of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, int modifiers) { + super.setParent(ClassProxy.from(parentFQN, 0, modifiers)); + return this; + } + + /** + * Sets the parent class of this method to the one described by the + * fully qualified name. + * @param parentFQN the fully qualified name of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN) { + return this.setParent(parentFQN, 0); + } + /** * Sets the return type to the given type. * @param returnType the {@link Class} object corresponding to @@ -134,7 +173,12 @@ public class MethodProxy extends AbstractProxy { */ @Override public MethodProxy build() { - return new MethodProxy(name, modifiers, parent, parameters.toArray(new Type[0]), returnType); + return new MethodProxy( + this.name, + this.modifiers, + this.parent, + this.parameters.toArray(new Type[0]), + this.returnType); } } } diff --git a/src/main/java/ftbsc/lll/proxies/PackageProxy.java b/src/main/java/ftbsc/lll/proxies/PackageProxy.java new file mode 100644 index 0000000..fbfe6c0 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/PackageProxy.java @@ -0,0 +1,51 @@ +package ftbsc.lll.proxies; + +/** + * A container for information about a package. + * @since 0.4.0 + */ +public class PackageProxy extends QualifiableProxy { + + /** + * The {@link PackageProxy} representing the root package. + */ + public static final PackageProxy ROOT = new PackageProxy(null, ""); + + /** + * The protected constructor, called only from {@link PackageProxy#from(String)}. + * @param parent the {@link PackageProxy} representing the parent + * @param fqn the fully-qualified name of this package + */ + protected PackageProxy(PackageProxy parent, String fqn) { + super(null, 0, parent, fqn); + } + + /** + * Builds a {@link PackageProxy} from its fully-qualified name. + * @param fqn the fully-qualified name of the package + * @return the built {@link PackageProxy} + */ + protected static PackageProxy from(String fqn) { + if(fqn == null || fqn.equals("")) return ROOT; + return new PackageProxy(from(extractParentFromFQN(fqn)), fqn); + } + + /** + * Builds a {@link PackageProxy} from a reflective {@link Package} object. + * @param p the {@link Package} object + * @return the built {@link PackageProxy} + */ + protected static PackageProxy from(Package p) { + return from(extractParentFromFQN(p.getName())); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof PackageProxy && super.equals(obj); + } +} diff --git a/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java b/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java new file mode 100644 index 0000000..2efada8 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java @@ -0,0 +1,68 @@ +package ftbsc.lll.proxies; + +import org.objectweb.asm.Type; + +/** + * A container for information about an element which has a fully-qualified name. + * @see ClassProxy + * @see PackageProxy + * @since 0.4.0 + */ +public abstract class QualifiableProxy extends AbstractProxy { + /** + * The fully-qualified name of the element represented by this proxy. + */ + public final String fullyQualifiedName; + + /** + * The "internal name" (fully-qualified with slashes) of the element + * represented by this proxy. + */ + public final String internalName; + + /** + * The protected constructor, should be called by all classes extending this in theirs. + * @param type the {@link Type} for the element + * @param modifiers the modifiers, as a packed int + * @param parent the {@link QualifiableProxy} representing the parent of this element + * @param fullyQualifiedName the FQN of the element + */ + protected QualifiableProxy(Type type, int modifiers, QualifiableProxy parent, String fullyQualifiedName) { + super(extractSimpleNameFromFQN(fullyQualifiedName), type, modifiers, parent); + this.fullyQualifiedName = fullyQualifiedName; + this.internalName = this.fullyQualifiedName.replace('.', '/'); + } + + /** + * Returns a {@link String} containing the FQN of the parent element + * to this, which may represent a package or class. + * @return the parent, or null if the parent was the root element + */ + protected static String extractParentFromFQN(String fqn) { + String lastSeparator = fqn.contains("$") ? "\\$" : "\\."; + String[] split = fqn.split(lastSeparator); + if(split.length == 1) return null; + return fqn.substring(0, split[split.length - 1].length() - 1); + } + + /** + * Returns a {@link String} containing the simple name of the element + * @return the simple name + */ + protected static String extractSimpleNameFromFQN(String fqn) { + String lastSeparator = fqn.contains("$") ? "\\$" : "\\."; + String[] split = fqn.split(lastSeparator); + if(split.length == 1) return fqn; + else return split[split.length - 1]; + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof QualifiableProxy && super.equals(obj) && ((QualifiableProxy) obj).fullyQualifiedName.equals(fullyQualifiedName); + } +} diff --git a/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java b/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java index d23686d..479e651 100644 --- a/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java +++ b/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java @@ -17,11 +17,6 @@ public class FieldProxyInsnNode extends FieldInsnNode { * @param f a {@link FieldProxy} representing the field to call */ public FieldProxyInsnNode(int opcode, FieldProxy f) { - super( - opcode, - f.parent.replace('.', '/'), - f.name, - f.type.getDescriptor() - ); + super(opcode, f.parent.internalName, f.name, f.type.getDescriptor()); } } diff --git a/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java b/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java index 904615d..4fb3b89 100644 --- a/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java +++ b/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java @@ -18,11 +18,6 @@ public class MethodProxyInsnNode extends MethodInsnNode { * @param m a {@link MethodProxy} representing the method to call */ public MethodProxyInsnNode(int opcode, MethodProxy m) { - super( - opcode, - m.parent.replace('.', '/'), - m.name, - m.type.getDescriptor() - ); + super(opcode, m.parent.internalName, m.name, m.type.getDescriptor()); } } -- cgit v1.2.3-56-ga3b1 From ff47129cf3ac12817bf4ca9af8753592298f03e4 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Tue, 21 Mar 2023 18:24:29 +0100 Subject: feat: restored flat descriptors, implemented primitive proxies --- src/main/java/ftbsc/lll/proxies/AbstractProxy.java | 34 ++-- src/main/java/ftbsc/lll/proxies/ClassProxy.java | 164 ----------------- src/main/java/ftbsc/lll/proxies/FieldProxy.java | 12 +- src/main/java/ftbsc/lll/proxies/MethodProxy.java | 20 +-- .../java/ftbsc/lll/proxies/QualifiableProxy.java | 6 +- src/main/java/ftbsc/lll/proxies/TypeProxy.java | 193 +++++++++++++++++++++ .../ftbsc/lll/tools/nodes/FieldProxyInsnNode.java | 2 +- .../ftbsc/lll/tools/nodes/MethodProxyInsnNode.java | 2 +- .../ftbsc/lll/tools/nodes/TypeProxyInsnNode.java | 23 +++ 9 files changed, 254 insertions(+), 202 deletions(-) delete mode 100644 src/main/java/ftbsc/lll/proxies/ClassProxy.java create mode 100644 src/main/java/ftbsc/lll/proxies/TypeProxy.java create mode 100644 src/main/java/ftbsc/lll/tools/nodes/TypeProxyInsnNode.java (limited to 'src/main/java/ftbsc/lll/proxies/AbstractProxy.java') diff --git a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java index 93eaec8..d60f3d5 100644 --- a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java +++ b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java @@ -15,9 +15,9 @@ public abstract class AbstractProxy { public final String name; /** - * The {@link Type} corresponding to this element. + * The descriptor for this element. */ - public final Type type; + public final String descriptor; /** * The fully qualified name (i.e. java.lang.String) of @@ -34,13 +34,13 @@ public abstract class AbstractProxy { /** * The private constructor, should be called by all classes extending this in theirs. * @param name the name of the element - * @param type the {@link Type} for the element + * @param descriptor the descriptor for the element * @param modifiers the modifiers, as a packed int * @param parent the FQN of the parent class */ - protected AbstractProxy(String name, Type type, int modifiers, QualifiableProxy parent) { + protected AbstractProxy(String name, String descriptor, int modifiers, QualifiableProxy parent) { this.name = name; - this.type = type; + this.descriptor = descriptor; this.modifiers = modifiers; this.parent = parent; } @@ -57,7 +57,7 @@ public abstract class AbstractProxy { return p.parent.equals(this.parent) && p.name.equals(this.name) && p.modifiers == this.modifiers - && p.type.equals(this.type); + && p.descriptor.equals(this.descriptor); } else return false; } @@ -83,9 +83,9 @@ public abstract class AbstractProxy { protected QualifiableProxy parent; /** - * The {@link Type} corresponding to the element. + * The descriptor of the element. */ - protected Type type; + protected String descriptor; /** * The constructor. @@ -124,21 +124,21 @@ public abstract class AbstractProxy { } /** - * @param type the {@link Type} corresponding to the element - * @return the current state of the builder + * Sets {@link Type} for this element from the descriptor, passed as a {@link String}. + * @param descriptor the descriptor passed as a {@link String} + * @return the builder's state after the change */ - public Builder setType(Type type) { - this.type = type; + public Builder setDescriptor(String descriptor) { + this.descriptor = descriptor; return this; } /** - * Sets {@link Type} for this element from the descriptor, passed as a {@link String}. - * @param descriptor the descriptor passed as a {@link String} - * @return the builder's state after the change + * @param type the {@link Type} corresponding to the element + * @return the current state of the builder */ - public Builder setDescriptor(String descriptor) { - return this.setType(Type.getType(descriptor)); + public Builder setType(Type type) { + return this.setDescriptor(type.getDescriptor()); } /** diff --git a/src/main/java/ftbsc/lll/proxies/ClassProxy.java b/src/main/java/ftbsc/lll/proxies/ClassProxy.java deleted file mode 100644 index 41e9bb8..0000000 --- a/src/main/java/ftbsc/lll/proxies/ClassProxy.java +++ /dev/null @@ -1,164 +0,0 @@ -package ftbsc.lll.proxies; - -import org.objectweb.asm.Type; - -import java.lang.reflect.Modifier; - -import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; - -/** - * A container for information about classes to be used - * in ASM patching. - * @since 0.4.0 - */ -public class ClassProxy extends QualifiableProxy { - /** - * Protected constructor, called only from the builder. - * @param name the name of the class - * @param type the {@link Type} of the class - * @param modifiers the modifiers of the class - * @param parent the package containing this class - */ - protected ClassProxy(String name, Type type, int modifiers, String parent) { - super(type, modifiers, PackageProxy.from(parent), String.format("%s.%s", name, parent)); - } - - /** - * Protected constructor, called only from the builder. - * @param name the name of the class - * @param type the {@link Type} of the class - * @param modifiers the modifiers of the class - * @param containerClass the FQN of the parent class of the class - */ - protected ClassProxy(String name, Type type, int modifiers, QualifiableProxy containerClass) { - super(type, modifiers, containerClass, String.format("%s$%s", name, containerClass.fullyQualifiedName)); - } - - /** - * Builds a {@link ClassProxy} from a {@link Type} and modifiers. - * @param type the {@link Type} representing this Class - * @param modifiers the modifiers of the class - */ - public static ClassProxy from(Type type, int modifiers) { - String fqn = type.getInternalName().replace('/', '.'); - String simpleName = extractSimpleNameFromFQN(fqn); - String parent = extractParentFromFQN(fqn); - if(fqn.contains("$")) - return new ClassProxy(simpleName, type, modifiers, from(parent, 0, Modifier.PUBLIC)); - else return new ClassProxy(simpleName, type, modifiers, parent); - } - - /** - * Builds a {@link ClassProxy} given only the fully-qualified name and modifiers. - * @param fqn the fully qualified name of the desired class - * @param arrayLevel the array level for this type - * @param modifiers the access modifiers of the desired class - * @implNote If present, parent classes will be assumed to have {@code public} as - * their only modifier. - * @return the built {@link ClassProxy} - */ - protected static ClassProxy from(String fqn, int arrayLevel, int modifiers) { - return from(Type.getObjectType(nameToDescriptor(fqn, arrayLevel)), modifiers); - } - - /** - * Builds a {@link ClassProxy} from a {@link Class} object. - * @param clazz the {@link Class} object representing the target class - * @return the built {@link ClassProxy} - */ - public static ClassProxy from(Class clazz) { - Class parentClass = clazz.getEnclosingClass(); - if(parentClass == null) - return new ClassProxy( - clazz.getSimpleName(), - Type.getType(clazz), - clazz.getModifiers(), - clazz.getPackage().getName() - ); - else - return new ClassProxy( - clazz.getSimpleName(), - Type.getType(clazz), - clazz.getModifiers(), - from(parentClass) - ); - } - - /** - * Returns a new instance of {@link ClassProxy.Builder}. - * @param name the name of the class - * @return the builder object for class proxies - */ - public static Builder builder(String name) { - return new Builder(name); - } - - /** - * Indicates whether the given object is a proxy for the same element as this. - * @param obj the object to perform - * @return true if it's equal - */ - @Override - public boolean equals(Object obj) { - return obj instanceof ClassProxy && super.equals(obj); - } - - /** - * A builder object for {@link ClassProxy}. - */ - public static class Builder extends AbstractProxy.Builder { - - /** - * The constructor of the builder, used only internally. - * @param name the "simple name" of the class - */ - Builder(String name) { - super(name); - } - - /** - * Sets this class as an inner class and sets the containing - * class to the given class object. - * @param containerClass the {@link Class} representing the - * container class - * @return the builder's state after the change - */ - public Builder setParent(Class containerClass) { - super.setParent(ClassProxy.from(containerClass)); - return this; - } - - /** - * Sets this class as an inner class and builds a {@link ClassProxy} - * from the given parent and modifiers. - * @param parentFQN the fully qualified name of the parent - * @param modifiers the modifiers of the parent (if it's a class) - * @param isParentPackage whether this parent should be interpreted as a package or class - * @return the builder's state after the change - */ - public Builder setParent(String parentFQN, int modifiers, boolean isParentPackage) { - super.setParent(isParentPackage ? PackageProxy.from(parentFQN) : ClassProxy.from(parentFQN, 0, modifiers)); - return this; - } - - /** - * Sets this class as an inner class and builds a {@link ClassProxy} - * from the given parent. - * @param parentFQN the fully qualified name of the parent - * @param isParentPackage whether this parent should be interpreted as a package or class - * @return the builder's state after the change - */ - public Builder setParent(String parentFQN, boolean isParentPackage) { - return this.setParent(parentFQN, 0, isParentPackage); - } - - /** - * Builds a {@link ClassProxy} of the given kind. - * @return the built {@link ClassProxy} - */ - @Override - public ClassProxy build() { - return new ClassProxy(this.name, this.type, this.modifiers, this.parent); - } - } -} \ No newline at end of file diff --git a/src/main/java/ftbsc/lll/proxies/FieldProxy.java b/src/main/java/ftbsc/lll/proxies/FieldProxy.java index 8855cd8..d374bf7 100644 --- a/src/main/java/ftbsc/lll/proxies/FieldProxy.java +++ b/src/main/java/ftbsc/lll/proxies/FieldProxy.java @@ -16,18 +16,18 @@ public class FieldProxy extends AbstractProxy { * @param f the {@link Field} object corresponding to this. */ public FieldProxy(Field f) { - super(f.getName(), Type.getType(f.getType()), f.getModifiers(), ClassProxy.from(f.getDeclaringClass())); + super(f.getName(), Type.getDescriptor(f.getType()), f.getModifiers(), TypeProxy.from(f.getDeclaringClass())); } /** * Protected constructor, called only from the builder. * @param name the name of the field - * @param type the {@link Type} of the field + * @param descriptor the descriptor of the field * @param modifiers the modifiers of the field * @param parent the {@link QualifiableProxy} for the parent */ - protected FieldProxy(String name, Type type, int modifiers, QualifiableProxy parent) { - super(name, type, modifiers, parent); + protected FieldProxy(String name, String descriptor, int modifiers, QualifiableProxy parent) { + super(name, descriptor, modifiers, parent); } /** @@ -68,7 +68,7 @@ public class FieldProxy extends AbstractProxy { * @return the builder's state after the change */ public Builder setParent(String parentFQN, int modifiers) { - super.setParent(ClassProxy.from(parentFQN, 0, modifiers)); + super.setParent(TypeProxy.from(parentFQN, 0, modifiers)); return this; } @@ -88,7 +88,7 @@ public class FieldProxy extends AbstractProxy { */ @Override public FieldProxy build() { - return new FieldProxy(this.name, this.type, this.modifiers, this.parent); + return new FieldProxy(this.name, this.descriptor, this.modifiers, this.parent); } } } diff --git a/src/main/java/ftbsc/lll/proxies/MethodProxy.java b/src/main/java/ftbsc/lll/proxies/MethodProxy.java index 5d014e9..b4c329a 100644 --- a/src/main/java/ftbsc/lll/proxies/MethodProxy.java +++ b/src/main/java/ftbsc/lll/proxies/MethodProxy.java @@ -17,14 +17,14 @@ import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; public class MethodProxy extends AbstractProxy { /** - * An array of {@link ClassProxy} each representing the parameters of the method. + * An array of {@link TypeProxy} each representing the parameters of the method. */ - public final ClassProxy[] parameters; + public final TypeProxy[] parameters; /** - * The {@link ClassProxy} for the return type of the method. + * The {@link TypeProxy} for the return type of the method. */ - public final ClassProxy returnType; + public final TypeProxy returnType; /** * A protected constructor, called only from the builder. @@ -35,11 +35,11 @@ public class MethodProxy extends AbstractProxy { * @param returnType the return type of the method */ protected MethodProxy(String name, int modifiers, QualifiableProxy parent, Type[] parameters, Type returnType) { - super(name, Type.getMethodType(returnType, parameters), modifiers, parent); + super(name, Type.getMethodDescriptor(returnType, parameters), modifiers, parent); this.parameters = Arrays.stream(parameters) - .map(t -> ClassProxy.from(t, 0)) - .toArray(ClassProxy[]::new); - this.returnType = ClassProxy.from(returnType, 0); + .map(t -> TypeProxy.from(t, 0)) + .toArray(TypeProxy[]::new); + this.returnType = TypeProxy.from(returnType, 0); } /** @@ -50,7 +50,7 @@ public class MethodProxy extends AbstractProxy { public MethodProxy(Method m) { this(m.getName(), m.getModifiers(), - ClassProxy.from(m.getDeclaringClass()), + TypeProxy.from(m.getDeclaringClass()), Type.getArgumentTypes(m), Type.getReturnType(m) ); @@ -142,7 +142,7 @@ public class MethodProxy extends AbstractProxy { * @return the builder's state after the change */ public Builder setParent(String parentFQN, int modifiers) { - super.setParent(ClassProxy.from(parentFQN, 0, modifiers)); + super.setParent(TypeProxy.from(parentFQN, 0, modifiers)); return this; } diff --git a/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java b/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java index 2efada8..adeb83d 100644 --- a/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java +++ b/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java @@ -4,7 +4,7 @@ import org.objectweb.asm.Type; /** * A container for information about an element which has a fully-qualified name. - * @see ClassProxy + * @see TypeProxy * @see PackageProxy * @since 0.4.0 */ @@ -27,8 +27,8 @@ public abstract class QualifiableProxy extends AbstractProxy { * @param parent the {@link QualifiableProxy} representing the parent of this element * @param fullyQualifiedName the FQN of the element */ - protected QualifiableProxy(Type type, int modifiers, QualifiableProxy parent, String fullyQualifiedName) { - super(extractSimpleNameFromFQN(fullyQualifiedName), type, modifiers, parent); + protected QualifiableProxy(String descriptor, int modifiers, QualifiableProxy parent, String fullyQualifiedName) { + super(extractSimpleNameFromFQN(fullyQualifiedName), descriptor, modifiers, parent); this.fullyQualifiedName = fullyQualifiedName; this.internalName = this.fullyQualifiedName.replace('.', '/'); } diff --git a/src/main/java/ftbsc/lll/proxies/TypeProxy.java b/src/main/java/ftbsc/lll/proxies/TypeProxy.java new file mode 100644 index 0000000..d621465 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/TypeProxy.java @@ -0,0 +1,193 @@ +package ftbsc.lll.proxies; + +import org.objectweb.asm.Type; + +import java.lang.reflect.Modifier; + +import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; + +/** + * A container for information about classes to be used + * in ASM patching. + * @since 0.4.0 + */ +public class TypeProxy extends QualifiableProxy { + /** + * Whether this proxy represents a primitive. + */ + public final boolean primitive; + + /** + * Protected constructor, called only from the builder. + * @param name the name of the class + * @param descriptor the descriptor of the class + * @param modifiers the modifiers of the class + * @param parent the package containing this class + */ + protected TypeProxy(String name, String descriptor, int modifiers, String parent, boolean primitive) { + super(descriptor, modifiers, PackageProxy.from(parent), String.format("%s.%s", name, parent)); + this.primitive = primitive; + } + + /** + * Protected constructor, called only from the builder. + * @param name the name of the class + * @param descriptor the descriptor of the element + * @param modifiers the modifiers of the class + * @param containerClass the FQN of the parent class of the class + */ + protected TypeProxy(String name, String descriptor, int modifiers, QualifiableProxy containerClass, boolean primitive) { + super(descriptor, modifiers, containerClass, String.format("%s$%s", name, containerClass.fullyQualifiedName)); + this.primitive = primitive; + } + + /** + * Builds a {@link TypeProxy} from a {@link Type} and modifiers. + * @param type the {@link Type} representing this Class + * @param modifiers the modifiers of the class + */ + public static TypeProxy from(Type type, int modifiers) { + while(type.getSort() == Type.ARRAY) + type = type.getElementType(); + String fqn = type.getInternalName().replace('/', '.'); + String simpleName = extractSimpleNameFromFQN(fqn); + String parent = extractParentFromFQN(fqn); + boolean primitive = type.getSort() < Type.ARRAY; + if(fqn.contains("$")) + return new TypeProxy(simpleName, type.getDescriptor(), modifiers, from(type, Modifier.PUBLIC), primitive); + else return new TypeProxy(simpleName, type.getDescriptor(), modifiers, parent, primitive); + } + + /** + * Builds a {@link TypeProxy} given only the fully-qualified name and modifiers. + * @param fqn the fully qualified name of the desired class + * @param arrayLevel the array level for this type + * @param modifiers the access modifiers of the desired class + * @implNote If present, parent classes will be assumed to have {@code public} as + * their only modifier. + * @return the built {@link TypeProxy} + */ + protected static TypeProxy from(String fqn, int arrayLevel, int modifiers) { + return from(Type.getObjectType(nameToDescriptor(fqn, arrayLevel)), modifiers); + } + + /** + * Builds a {@link TypeProxy} from a {@link Class} object. + * @param clazz the {@link Class} object representing the target class + * @return the built {@link TypeProxy} + */ + public static TypeProxy from(Class clazz) { + Class parentClass = clazz.getEnclosingClass(); + if(parentClass == null) + return new TypeProxy( + clazz.getSimpleName(), + Type.getDescriptor(clazz), + clazz.getModifiers(), + clazz.getPackage().getName(), + clazz.isPrimitive() + ); + else + return new TypeProxy( + clazz.getSimpleName(), + Type.getDescriptor(clazz), + clazz.getModifiers(), + from(parentClass), + clazz.isPrimitive() + ); + } + + /** + * Returns a new instance of {@link TypeProxy.Builder}. + * @param name the name of the class + * @return the builder object for class proxies + */ + public static Builder builder(String name) { + return new Builder(name); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof TypeProxy && super.equals(obj); + } + + /** + * A builder object for {@link TypeProxy}. + */ + public static class Builder extends AbstractProxy.Builder { + + /** + * Whether the proxy represents a primitive. + */ + private boolean primitive; + + /** + * The constructor of the builder, used only internally. + * @param name the "simple name" of the class + */ + Builder(String name) { + super(name); + this.primitive = false; + } + + /** + * Sets this class as an inner class and sets the containing + * class to the given class object. + * @param containerClass the {@link Class} representing the + * container class + * @return the builder's state after the change + */ + public Builder setParent(Class containerClass) { + super.setParent(TypeProxy.from(containerClass)); + return this; + } + + /** + * Sets this class as an inner class and builds a {@link TypeProxy} + * from the given parent and modifiers. + * @param parentFQN the fully qualified name of the parent + * @param modifiers the modifiers of the parent (if it's a class) + * @param isParentPackage whether this parent should be interpreted as a package or class + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, int modifiers, boolean isParentPackage) { + super.setParent(isParentPackage ? PackageProxy.from(parentFQN) : TypeProxy.from(parentFQN, 0, modifiers)); + return this; + } + + /** + * Sets this class as an inner class and builds a {@link TypeProxy} + * from the given parent. + * @param parentFQN the fully qualified name of the parent + * @param isParentPackage whether this parent should be interpreted as a package or class + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, boolean isParentPackage) { + return this.setParent(parentFQN, 0, isParentPackage); + } + + /** + * Sets the primitive flag to true or false, to signal that the type here specified + * is a primitive. + * @param primitive the new state of the primitive flag + * @return the builder's state after the change + */ + public Builder setPrimitive(boolean primitive) { + this.primitive = primitive; + return this; + } + + /** + * Builds a {@link TypeProxy} of the given kind. + * @return the built {@link TypeProxy} + */ + @Override + public TypeProxy build() { + return new TypeProxy(this.name, this.descriptor, this.modifiers, this.parent, this.primitive); + } + } +} \ No newline at end of file diff --git a/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java b/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java index 479e651..068ade0 100644 --- a/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java +++ b/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java @@ -17,6 +17,6 @@ public class FieldProxyInsnNode extends FieldInsnNode { * @param f a {@link FieldProxy} representing the field to call */ public FieldProxyInsnNode(int opcode, FieldProxy f) { - super(opcode, f.parent.internalName, f.name, f.type.getDescriptor()); + super(opcode, f.parent.internalName, f.name, f.descriptor); } } diff --git a/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java b/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java index 4fb3b89..01549a8 100644 --- a/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java +++ b/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java @@ -18,6 +18,6 @@ public class MethodProxyInsnNode extends MethodInsnNode { * @param m a {@link MethodProxy} representing the method to call */ public MethodProxyInsnNode(int opcode, MethodProxy m) { - super(opcode, m.parent.internalName, m.name, m.type.getDescriptor()); + super(opcode, m.parent.internalName, m.name, m.descriptor); } } diff --git a/src/main/java/ftbsc/lll/tools/nodes/TypeProxyInsnNode.java b/src/main/java/ftbsc/lll/tools/nodes/TypeProxyInsnNode.java new file mode 100644 index 0000000..e5b5f2a --- /dev/null +++ b/src/main/java/ftbsc/lll/tools/nodes/TypeProxyInsnNode.java @@ -0,0 +1,23 @@ +package ftbsc.lll.tools.nodes; + +import ftbsc.lll.proxies.TypeProxy; +import org.objectweb.asm.tree.TypeInsnNode; + +/** + * Overrides the {@link TypeInsnNode} to add a constructor + * taking in a {@link TypeProxy}. + * @since 0.4.0 + */ +public class TypeProxyInsnNode extends TypeInsnNode { + /** + * Constructs a new {@link TypeInsnNode} starting from a + * {@link TypeProxy}. The user should ensure that the TypeInsnNode + * represents a declared type before calling this. + * @param opcode the opcode, must be one of NEW, ANEWARRAY, + * CHECKCAST or INSTANCEOF + * @param t a {@link TypeProxy} representing the type to call + */ + public TypeProxyInsnNode(int opcode, TypeProxy t) { + super(opcode, t.internalName); + } +} -- cgit v1.2.3-56-ga3b1 From 17a0b4d0172c0b3399fb5ed0ef1f89b41a1fc67f Mon Sep 17 00:00:00 2001 From: zaaarf Date: Tue, 21 Mar 2023 18:46:23 +0100 Subject: chore: reorganize, add ProxyType enum --- src/main/java/ftbsc/lll/proxies/AbstractProxy.java | 12 +- src/main/java/ftbsc/lll/proxies/FieldProxy.java | 95 ---------- src/main/java/ftbsc/lll/proxies/MethodProxy.java | 185 ------------------- src/main/java/ftbsc/lll/proxies/PackageProxy.java | 51 ------ src/main/java/ftbsc/lll/proxies/ProxyType.java | 11 ++ .../java/ftbsc/lll/proxies/QualifiableProxy.java | 11 +- src/main/java/ftbsc/lll/proxies/TypeProxy.java | 196 -------------------- .../java/ftbsc/lll/proxies/impl/FieldProxy.java | 98 ++++++++++ .../java/ftbsc/lll/proxies/impl/MethodProxy.java | 188 +++++++++++++++++++ .../java/ftbsc/lll/proxies/impl/PackageProxy.java | 54 ++++++ .../java/ftbsc/lll/proxies/impl/TypeProxy.java | 199 +++++++++++++++++++++ .../ftbsc/lll/tools/nodes/FieldProxyInsnNode.java | 2 +- .../ftbsc/lll/tools/nodes/MethodProxyInsnNode.java | 2 +- .../ftbsc/lll/tools/nodes/TypeProxyInsnNode.java | 2 +- 14 files changed, 566 insertions(+), 540 deletions(-) delete mode 100644 src/main/java/ftbsc/lll/proxies/FieldProxy.java delete mode 100644 src/main/java/ftbsc/lll/proxies/MethodProxy.java delete mode 100644 src/main/java/ftbsc/lll/proxies/PackageProxy.java create mode 100644 src/main/java/ftbsc/lll/proxies/ProxyType.java delete mode 100644 src/main/java/ftbsc/lll/proxies/TypeProxy.java create mode 100644 src/main/java/ftbsc/lll/proxies/impl/FieldProxy.java create mode 100644 src/main/java/ftbsc/lll/proxies/impl/MethodProxy.java create mode 100644 src/main/java/ftbsc/lll/proxies/impl/PackageProxy.java create mode 100644 src/main/java/ftbsc/lll/proxies/impl/TypeProxy.java (limited to 'src/main/java/ftbsc/lll/proxies/AbstractProxy.java') diff --git a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java index d60f3d5..054cef9 100644 --- a/src/main/java/ftbsc/lll/proxies/AbstractProxy.java +++ b/src/main/java/ftbsc/lll/proxies/AbstractProxy.java @@ -3,12 +3,16 @@ package ftbsc.lll.proxies; import org.objectweb.asm.Type; /** - * Abstract proxy class, implementing common aspects - * of {@link MethodProxy} and {@link FieldProxy}. + * Abstract proxy class, implementing common aspects. * @since 0.3.0 */ public abstract class AbstractProxy { + /** + * Which type of proxy this is. + */ + public final ProxyType proxyType; + /** * The name of the corresponding element. */ @@ -37,12 +41,14 @@ public abstract class AbstractProxy { * @param descriptor the descriptor for the element * @param modifiers the modifiers, as a packed int * @param parent the FQN of the parent class + * @param proxyType the {@link ProxyType} being represented here */ - protected AbstractProxy(String name, String descriptor, int modifiers, QualifiableProxy parent) { + protected AbstractProxy(String name, String descriptor, int modifiers, QualifiableProxy parent, ProxyType proxyType) { this.name = name; this.descriptor = descriptor; this.modifiers = modifiers; this.parent = parent; + this.proxyType = proxyType; } /** diff --git a/src/main/java/ftbsc/lll/proxies/FieldProxy.java b/src/main/java/ftbsc/lll/proxies/FieldProxy.java deleted file mode 100644 index 8732997..0000000 --- a/src/main/java/ftbsc/lll/proxies/FieldProxy.java +++ /dev/null @@ -1,95 +0,0 @@ -package ftbsc.lll.proxies; - -import org.objectweb.asm.Type; - -import java.lang.reflect.Field; - -/** - * A container for information about class fields to be used - * in ASM patching. - * @since 0.3.0 - */ -public class FieldProxy extends AbstractProxy { - /** - * A public constructor, builds a proxy from a {@link Field} - * obtained from reflection. - * @param f the {@link Field} object corresponding to this. - */ - public FieldProxy(Field f) { - super(f.getName(), Type.getDescriptor(f.getType()), f.getModifiers(), TypeProxy.from(f.getDeclaringClass())); - } - - /** - * Protected constructor, called only from the builder. - * @param name the name of the field - * @param descriptor the descriptor of the field - * @param modifiers the modifiers of the field - * @param parent the {@link QualifiableProxy} for the parent - */ - protected FieldProxy(String name, String descriptor, int modifiers, QualifiableProxy parent) { - super(name, descriptor, modifiers, parent); - } - - /** - * Returns a new instance of {@link FieldProxy.Builder}. - * @param name the name of the field - * @return the builder object for field proxies - */ - public static Builder builder(String name) { - return new Builder(name); - } - - /** - * Indicates whether the given object is a proxy for the same element as this. - * @param obj the object to perform - * @return true if it's equal - */ - @Override - public boolean equals(Object obj) { - return obj instanceof FieldProxy && super.equals(obj); - } - - /** - * A builder object for {@link FieldProxy}. - */ - public static class Builder extends AbstractProxy.Builder { - /** - * The constructor of the builder, used only internally. - * @param name the name of the field - */ - Builder(String name) { - super(name); - } - - /** - * Sets the parent class of this field to the one described by the - * fully qualified name and with the given modifiers. - * @param parentFQN the fully qualified name of the parent - * @param modifiers the modifiers of the parent - * @return the builder's state after the change - */ - public Builder setParent(String parentFQN, int modifiers) { - super.setParent(TypeProxy.from(parentFQN, 0, modifiers)); - return this; - } - - /** - * Sets the parent class of this field to the one described by the - * fully qualified name. - * @param parentFQN the fully qualified name of the parent - * @return the builder's state after the change - */ - public Builder setParent(String parentFQN) { - return this.setParent(parentFQN, 0); - } - - /** - * Builds a {@link FieldProxy} of the given kind. - * @return the built {@link FieldProxy} - */ - @Override - public FieldProxy build() { - return new FieldProxy(this.name, this.descriptor, this.modifiers, this.parent); - } - } -} diff --git a/src/main/java/ftbsc/lll/proxies/MethodProxy.java b/src/main/java/ftbsc/lll/proxies/MethodProxy.java deleted file mode 100644 index c906ec7..0000000 --- a/src/main/java/ftbsc/lll/proxies/MethodProxy.java +++ /dev/null @@ -1,185 +0,0 @@ -package ftbsc.lll.proxies; - -import org.objectweb.asm.Type; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; - -/** - * A container for information about class methods to be used - * in ASM patching. - * @since 0.3.0 - */ -public class MethodProxy extends AbstractProxy { - - /** - * An array of {@link TypeProxy} each representing the parameters of the method. - */ - public final TypeProxy[] parameters; - - /** - * The {@link TypeProxy} for the return type of the method. - */ - public final TypeProxy returnType; - - /** - * A protected constructor, called only from the builder. - * @param name the name of the method - * @param modifiers the modifiers of the method - * @param parent the {@link QualifiableProxy} for the parent - * @param parameters the parameters of the method - * @param returnType the return type of the method - */ - protected MethodProxy(String name, int modifiers, QualifiableProxy parent, Type[] parameters, Type returnType) { - super(name, Type.getMethodDescriptor(returnType, parameters), modifiers, parent); - this.parameters = Arrays.stream(parameters) - .map(t -> TypeProxy.from(t, 0)) - .toArray(TypeProxy[]::new); - this.returnType = TypeProxy.from(returnType, 0); - } - - /** - * A public constructor, builds a proxy from a {@link Method} - * obtained from reflection. - * @param m the {@link Method} object corresponding to this. - */ - public MethodProxy(Method m) { - this(m.getName(), - m.getModifiers(), - TypeProxy.from(m.getDeclaringClass()), - Type.getArgumentTypes(m), - Type.getReturnType(m) - ); - } - - /** - * Returns a new instance of {@link MethodProxy.Builder}. - * @param name the name of the method - * @return the builder object for method proxies - */ - public static Builder builder(String name) { - return new Builder(name); - } - - /** - * Indicates whether the given object is a proxy for the same element as this. - * @param obj the object to perform - * @return true if it's equal - */ - @Override - public boolean equals(Object obj) { - if(obj instanceof MethodProxy) { - MethodProxy m = (MethodProxy) obj; - return super.equals(obj) && m.returnType.equals(this.returnType) && Arrays.equals(m.parameters, this.parameters); - } else return false; - } - - /** - * A builder object for {@link MethodProxy}. - */ - public static class Builder extends AbstractProxy.Builder { - /** - * The parameters of the method. - */ - private final List parameters; - - /** - * The return type of the method. Defaults to void. - */ - private Type returnType; - - /** - * The constructor of the builder, used only internally. - * @param name the name of the method - */ - Builder(String name) { - super(name); - this.parameters = new ArrayList<>(); - this.returnType = Type.getType(void.class); - } - - /** - * Adds a parameter of a given type. - * @param fqn the fully qualified name of the parameter type - * @param arrayLevel the array level of the parameter type - * @return the builder's state after the change - */ - public Builder addParameter(String fqn, int arrayLevel) { - this.parameters.add(Type.getType(nameToDescriptor(fqn, arrayLevel))); - return this; - } - - /** - * Adds a parameter of a given type. - * @param paramType the {@link Class} object corresponding to - * the parameter type. - * @return the builder's state after the change - */ - public Builder addParameter(Class paramType) { - this.parameters.add(Type.getType(paramType)); - return this; - } - - /** - * Sets the return type to the given type. - * @param fqn the fully qualified name of the return type - * @param arrayLevel the array level of the return type - * @return the builder's state after the change - */ - public Builder setReturnType(String fqn, int arrayLevel) { - this.returnType = Type.getType(nameToDescriptor(fqn, arrayLevel)); - return this; - } - - /** - * Sets the parent class of this method to the one described by the - * fully qualified name and with the given modifiers. - * @param parentFQN the fully qualified name of the parent - * @param modifiers the modifiers of the parent - * @return the builder's state after the change - */ - public Builder setParent(String parentFQN, int modifiers) { - super.setParent(TypeProxy.from(parentFQN, 0, modifiers)); - return this; - } - - /** - * Sets the parent class of this method to the one described by the - * fully qualified name. - * @param parentFQN the fully qualified name of the parent - * @return the builder's state after the change - */ - public Builder setParent(String parentFQN) { - return this.setParent(parentFQN, 0); - } - - /** - * Sets the return type to the given type. - * @param returnType the {@link Class} object corresponding to - * the return type - * @return the builder's state after the change - */ - public Builder setReturnType(Class returnType) { - this.returnType = Type.getType(returnType); - return this; - } - - /** - * Builds a {@link MethodProxy} of the given kind. - * @return the built {@link MethodProxy} - */ - @Override - public MethodProxy build() { - return new MethodProxy( - this.name, - this.modifiers, - this.parent, - this.parameters.toArray(new Type[0]), - this.returnType); - } - } -} diff --git a/src/main/java/ftbsc/lll/proxies/PackageProxy.java b/src/main/java/ftbsc/lll/proxies/PackageProxy.java deleted file mode 100644 index fbfe6c0..0000000 --- a/src/main/java/ftbsc/lll/proxies/PackageProxy.java +++ /dev/null @@ -1,51 +0,0 @@ -package ftbsc.lll.proxies; - -/** - * A container for information about a package. - * @since 0.4.0 - */ -public class PackageProxy extends QualifiableProxy { - - /** - * The {@link PackageProxy} representing the root package. - */ - public static final PackageProxy ROOT = new PackageProxy(null, ""); - - /** - * The protected constructor, called only from {@link PackageProxy#from(String)}. - * @param parent the {@link PackageProxy} representing the parent - * @param fqn the fully-qualified name of this package - */ - protected PackageProxy(PackageProxy parent, String fqn) { - super(null, 0, parent, fqn); - } - - /** - * Builds a {@link PackageProxy} from its fully-qualified name. - * @param fqn the fully-qualified name of the package - * @return the built {@link PackageProxy} - */ - protected static PackageProxy from(String fqn) { - if(fqn == null || fqn.equals("")) return ROOT; - return new PackageProxy(from(extractParentFromFQN(fqn)), fqn); - } - - /** - * Builds a {@link PackageProxy} from a reflective {@link Package} object. - * @param p the {@link Package} object - * @return the built {@link PackageProxy} - */ - protected static PackageProxy from(Package p) { - return from(extractParentFromFQN(p.getName())); - } - - /** - * Indicates whether the given object is a proxy for the same element as this. - * @param obj the object to perform - * @return true if it's equal - */ - @Override - public boolean equals(Object obj) { - return obj instanceof PackageProxy && super.equals(obj); - } -} diff --git a/src/main/java/ftbsc/lll/proxies/ProxyType.java b/src/main/java/ftbsc/lll/proxies/ProxyType.java new file mode 100644 index 0000000..1fd8169 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/ProxyType.java @@ -0,0 +1,11 @@ +package ftbsc.lll.proxies; + +/** + * An enum listing the various proxies. + */ +public enum ProxyType { + FIELD, + METHOD, + TYPE, + PACKAGE +} diff --git a/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java b/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java index 885ddc8..d245124 100644 --- a/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java +++ b/src/main/java/ftbsc/lll/proxies/QualifiableProxy.java @@ -1,11 +1,7 @@ package ftbsc.lll.proxies; -import org.objectweb.asm.Type; - /** - * A container for information about an element which has a fully-qualified name. - * @see TypeProxy - * @see PackageProxy + * A proxy for elements who have a fully-qualified name. * @since 0.4.0 */ public abstract class QualifiableProxy extends AbstractProxy { @@ -26,9 +22,10 @@ public abstract class QualifiableProxy extends AbstractProxy { * @param modifiers the modifiers, as a packed int * @param parent the {@link QualifiableProxy} representing the parent of this element * @param fullyQualifiedName the FQN of the element + * @param proxyType the {@link ProxyType} being represented here */ - protected QualifiableProxy(String descriptor, int modifiers, QualifiableProxy parent, String fullyQualifiedName) { - super(extractSimpleNameFromFQN(fullyQualifiedName), descriptor, modifiers, parent); + protected QualifiableProxy(String descriptor, int modifiers, QualifiableProxy parent, String fullyQualifiedName, ProxyType proxyType) { + super(extractSimpleNameFromFQN(fullyQualifiedName), descriptor, modifiers, parent, proxyType); this.fullyQualifiedName = fullyQualifiedName; this.internalName = this.fullyQualifiedName.replace('.', '/'); } diff --git a/src/main/java/ftbsc/lll/proxies/TypeProxy.java b/src/main/java/ftbsc/lll/proxies/TypeProxy.java deleted file mode 100644 index f828f11..0000000 --- a/src/main/java/ftbsc/lll/proxies/TypeProxy.java +++ /dev/null @@ -1,196 +0,0 @@ -package ftbsc.lll.proxies; - -import org.objectweb.asm.Type; - -import java.lang.reflect.Modifier; - -import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; - -/** - * A container for information about classes to be used - * in ASM patching. - * @since 0.4.0 - */ -public class TypeProxy extends QualifiableProxy { - /** - * Whether this proxy represents a primitive. - */ - public final boolean primitive; - - /** - * Protected constructor, called only from the builder. - * @param name the name of the class - * @param descriptor the descriptor of the class - * @param modifiers the modifiers of the class - * @param parent the package containing this class - * @param primitive whether the proxy is a primitive - */ - protected TypeProxy(String name, String descriptor, int modifiers, String parent, boolean primitive) { - super(descriptor, modifiers, PackageProxy.from(parent), String.format("%s.%s", name, parent)); - this.primitive = primitive; - } - - /** - * Protected constructor, called only from the builder. - * @param name the name of the class - * @param descriptor the descriptor of the element - * @param modifiers the modifiers of the class - * @param primitive whether the proxy is a primitive - * @param containerClass the FQN of the parent class of the class - */ - protected TypeProxy(String name, String descriptor, int modifiers, QualifiableProxy containerClass, boolean primitive) { - super(descriptor, modifiers, containerClass, String.format("%s$%s", name, containerClass.fullyQualifiedName)); - this.primitive = primitive; - } - - /** - * Builds a {@link TypeProxy} from a {@link Type} and modifiers. - * @param type the {@link Type} representing this Class - * @param modifiers the modifiers of the class - * @return the builty {@link TypeProxy} - */ - public static TypeProxy from(Type type, int modifiers) { - while(type.getSort() == Type.ARRAY) - type = type.getElementType(); - String fqn = type.getInternalName().replace('/', '.'); - String simpleName = extractSimpleNameFromFQN(fqn); - String parent = extractParentFromFQN(fqn); - boolean primitive = type.getSort() < Type.ARRAY; - if(fqn.contains("$")) - return new TypeProxy(simpleName, type.getDescriptor(), modifiers, from(type, Modifier.PUBLIC), primitive); - else return new TypeProxy(simpleName, type.getDescriptor(), modifiers, parent, primitive); - } - - /** - * Builds a {@link TypeProxy} given only the fully-qualified name and modifiers. - * If present, parent classes will be assumed to have {@code public} as their - * only modifier. - * @param fqn the fully qualified name of the desired class - * @param arrayLevel the array level for this type - * @param modifiers the access modifiers of the desired class - * @return the built {@link TypeProxy} - */ - protected static TypeProxy from(String fqn, int arrayLevel, int modifiers) { - return from(Type.getObjectType(nameToDescriptor(fqn, arrayLevel)), modifiers); - } - - /** - * Builds a {@link TypeProxy} from a {@link Class} object. - * @param clazz the {@link Class} object representing the target class - * @return the built {@link TypeProxy} - */ - public static TypeProxy from(Class clazz) { - Class parentClass = clazz.getEnclosingClass(); - if(parentClass == null) - return new TypeProxy( - clazz.getSimpleName(), - Type.getDescriptor(clazz), - clazz.getModifiers(), - clazz.getPackage().getName(), - clazz.isPrimitive() - ); - else - return new TypeProxy( - clazz.getSimpleName(), - Type.getDescriptor(clazz), - clazz.getModifiers(), - from(parentClass), - clazz.isPrimitive() - ); - } - - /** - * Returns a new instance of {@link TypeProxy.Builder}. - * @param name the name of the class - * @return the builder object for class proxies - */ - public static Builder builder(String name) { - return new Builder(name); - } - - /** - * Indicates whether the given object is a proxy for the same element as this. - * @param obj the object to perform - * @return true if it's equal - */ - @Override - public boolean equals(Object obj) { - return obj instanceof TypeProxy && super.equals(obj); - } - - /** - * A builder object for {@link TypeProxy}. - */ - public static class Builder extends AbstractProxy.Builder { - - /** - * Whether the proxy represents a primitive. - */ - private boolean primitive; - - /** - * The constructor of the builder, used only internally. - * @param name the "simple name" of the class - */ - Builder(String name) { - super(name); - this.primitive = false; - } - - /** - * Sets this class as an inner class and sets the containing - * class to the given class object. - * @param containerClass the {@link Class} representing the - * container class - * @return the builder's state after the change - */ - public Builder setParent(Class containerClass) { - super.setParent(TypeProxy.from(containerClass)); - return this; - } - - /** - * Sets this class as an inner class and builds a {@link TypeProxy} - * from the given parent and modifiers. - * @param parentFQN the fully qualified name of the parent - * @param modifiers the modifiers of the parent (if it's a class) - * @param isParentPackage whether this parent should be interpreted as a package or class - * @return the builder's state after the change - */ - public Builder setParent(String parentFQN, int modifiers, boolean isParentPackage) { - super.setParent(isParentPackage ? PackageProxy.from(parentFQN) : TypeProxy.from(parentFQN, 0, modifiers)); - return this; - } - - /** - * Sets this class as an inner class and builds a {@link TypeProxy} - * from the given parent. - * @param parentFQN the fully qualified name of the parent - * @param isParentPackage whether this parent should be interpreted as a package or class - * @return the builder's state after the change - */ - public Builder setParent(String parentFQN, boolean isParentPackage) { - return this.setParent(parentFQN, 0, isParentPackage); - } - - /** - * Sets the primitive flag to true or false, to signal that the type here specified - * is a primitive. - * @param primitive the new state of the primitive flag - * @return the builder's state after the change - */ - public Builder setPrimitive(boolean primitive) { - this.primitive = primitive; - return this; - } - - /** - * Builds a {@link TypeProxy} of the given kind. - * @return the built {@link TypeProxy} - */ - @Override - public TypeProxy build() { - return new TypeProxy(this.name, this.descriptor, this.modifiers, this.parent, this.primitive); - } - } -} \ No newline at end of file diff --git a/src/main/java/ftbsc/lll/proxies/impl/FieldProxy.java b/src/main/java/ftbsc/lll/proxies/impl/FieldProxy.java new file mode 100644 index 0000000..ceb8277 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/impl/FieldProxy.java @@ -0,0 +1,98 @@ +package ftbsc.lll.proxies.impl; + +import ftbsc.lll.proxies.AbstractProxy; +import ftbsc.lll.proxies.ProxyType; +import ftbsc.lll.proxies.QualifiableProxy; +import org.objectweb.asm.Type; + +import java.lang.reflect.Field; + +/** + * A container for information about class fields to be used + * in ASM patching. + * @since 0.3.0 + */ +public class FieldProxy extends AbstractProxy { + /** + * Protected constructor, called only from the builder. + * @param name the name of the field + * @param descriptor the descriptor of the field + * @param modifiers the modifiers of the field + * @param parent the {@link QualifiableProxy} for the parent + */ + protected FieldProxy(String name, String descriptor, int modifiers, QualifiableProxy parent) { + super(name, descriptor, modifiers, parent, ProxyType.FIELD); + } + + /** + * A public constructor, builds a proxy from a {@link Field} + * obtained from reflection. + * @param f the {@link Field} object corresponding to this. + */ + public FieldProxy(Field f) { + this(f.getName(), Type.getDescriptor(f.getType()), f.getModifiers(), TypeProxy.from(f.getDeclaringClass())); + } + + /** + * Returns a new instance of {@link FieldProxy.Builder}. + * @param name the name of the field + * @return the builder object for field proxies + */ + public static Builder builder(String name) { + return new Builder(name); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof FieldProxy && super.equals(obj); + } + + /** + * A builder object for {@link FieldProxy}. + */ + public static class Builder extends AbstractProxy.Builder { + /** + * The constructor of the builder, used only internally. + * @param name the name of the field + */ + Builder(String name) { + super(name); + } + + /** + * Sets the parent class of this field to the one described by the + * fully qualified name and with the given modifiers. + * @param parentFQN the fully qualified name of the parent + * @param modifiers the modifiers of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, int modifiers) { + super.setParent(TypeProxy.from(parentFQN, 0, modifiers)); + return this; + } + + /** + * Sets the parent class of this field to the one described by the + * fully qualified name. + * @param parentFQN the fully qualified name of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN) { + return this.setParent(parentFQN, 0); + } + + /** + * Builds a {@link FieldProxy} of the given kind. + * @return the built {@link FieldProxy} + */ + @Override + public FieldProxy build() { + return new FieldProxy(this.name, this.descriptor, this.modifiers, this.parent); + } + } +} diff --git a/src/main/java/ftbsc/lll/proxies/impl/MethodProxy.java b/src/main/java/ftbsc/lll/proxies/impl/MethodProxy.java new file mode 100644 index 0000000..3710d36 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/impl/MethodProxy.java @@ -0,0 +1,188 @@ +package ftbsc.lll.proxies.impl; + +import ftbsc.lll.proxies.AbstractProxy; +import ftbsc.lll.proxies.ProxyType; +import ftbsc.lll.proxies.QualifiableProxy; +import org.objectweb.asm.Type; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; + +/** + * A container for information about class methods to be used + * in ASM patching. + * @since 0.3.0 + */ +public class MethodProxy extends AbstractProxy { + + /** + * An array of {@link TypeProxy} each representing the parameters of the method. + */ + public final TypeProxy[] parameters; + + /** + * The {@link TypeProxy} for the return type of the method. + */ + public final TypeProxy returnType; + + /** + * A protected constructor, called only from the builder. + * @param name the name of the method + * @param modifiers the modifiers of the method + * @param parent the {@link QualifiableProxy} for the parent + * @param parameters the parameters of the method + * @param returnType the return type of the method + */ + protected MethodProxy(String name, int modifiers, QualifiableProxy parent, Type[] parameters, Type returnType) { + super(name, Type.getMethodDescriptor(returnType, parameters), modifiers, parent, ProxyType.METHOD); + this.parameters = Arrays.stream(parameters) + .map(t -> TypeProxy.from(t, 0)) + .toArray(TypeProxy[]::new); + this.returnType = TypeProxy.from(returnType, 0); + } + + /** + * A public constructor, builds a proxy from a {@link Method} + * obtained from reflection. + * @param m the {@link Method} object corresponding to this. + */ + public MethodProxy(Method m) { + this(m.getName(), + m.getModifiers(), + TypeProxy.from(m.getDeclaringClass()), + Type.getArgumentTypes(m), + Type.getReturnType(m) + ); + } + + /** + * Returns a new instance of {@link MethodProxy.Builder}. + * @param name the name of the method + * @return the builder object for method proxies + */ + public static Builder builder(String name) { + return new Builder(name); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + if(obj instanceof MethodProxy) { + MethodProxy m = (MethodProxy) obj; + return super.equals(obj) && m.returnType.equals(this.returnType) && Arrays.equals(m.parameters, this.parameters); + } else return false; + } + + /** + * A builder object for {@link MethodProxy}. + */ + public static class Builder extends AbstractProxy.Builder { + /** + * The parameters of the method. + */ + private final List parameters; + + /** + * The return type of the method. Defaults to void. + */ + private Type returnType; + + /** + * The constructor of the builder, used only internally. + * @param name the name of the method + */ + Builder(String name) { + super(name); + this.parameters = new ArrayList<>(); + this.returnType = Type.getType(void.class); + } + + /** + * Adds a parameter of a given type. + * @param fqn the fully qualified name of the parameter type + * @param arrayLevel the array level of the parameter type + * @return the builder's state after the change + */ + public Builder addParameter(String fqn, int arrayLevel) { + this.parameters.add(Type.getType(nameToDescriptor(fqn, arrayLevel))); + return this; + } + + /** + * Adds a parameter of a given type. + * @param paramType the {@link Class} object corresponding to + * the parameter type. + * @return the builder's state after the change + */ + public Builder addParameter(Class paramType) { + this.parameters.add(Type.getType(paramType)); + return this; + } + + /** + * Sets the return type to the given type. + * @param fqn the fully qualified name of the return type + * @param arrayLevel the array level of the return type + * @return the builder's state after the change + */ + public Builder setReturnType(String fqn, int arrayLevel) { + this.returnType = Type.getType(nameToDescriptor(fqn, arrayLevel)); + return this; + } + + /** + * Sets the parent class of this method to the one described by the + * fully qualified name and with the given modifiers. + * @param parentFQN the fully qualified name of the parent + * @param modifiers the modifiers of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, int modifiers) { + super.setParent(TypeProxy.from(parentFQN, 0, modifiers)); + return this; + } + + /** + * Sets the parent class of this method to the one described by the + * fully qualified name. + * @param parentFQN the fully qualified name of the parent + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN) { + return this.setParent(parentFQN, 0); + } + + /** + * Sets the return type to the given type. + * @param returnType the {@link Class} object corresponding to + * the return type + * @return the builder's state after the change + */ + public Builder setReturnType(Class returnType) { + this.returnType = Type.getType(returnType); + return this; + } + + /** + * Builds a {@link MethodProxy} of the given kind. + * @return the built {@link MethodProxy} + */ + @Override + public MethodProxy build() { + return new MethodProxy( + this.name, + this.modifiers, + this.parent, + this.parameters.toArray(new Type[0]), + this.returnType); + } + } +} diff --git a/src/main/java/ftbsc/lll/proxies/impl/PackageProxy.java b/src/main/java/ftbsc/lll/proxies/impl/PackageProxy.java new file mode 100644 index 0000000..5989da3 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/impl/PackageProxy.java @@ -0,0 +1,54 @@ +package ftbsc.lll.proxies.impl; + +import ftbsc.lll.proxies.ProxyType; +import ftbsc.lll.proxies.QualifiableProxy; + +/** + * A container for information about a package. + * @since 0.4.0 + */ +public class PackageProxy extends QualifiableProxy { + + /** + * The {@link PackageProxy} representing the root package. + */ + public static final PackageProxy ROOT = new PackageProxy(null, ""); + + /** + * The protected constructor, called only from {@link PackageProxy#from(String)}. + * @param parent the {@link PackageProxy} representing the parent + * @param fqn the fully-qualified name of this package + */ + protected PackageProxy(PackageProxy parent, String fqn) { + super(null, 0, parent, fqn, ProxyType.PACKAGE); + } + + /** + * Builds a {@link PackageProxy} from its fully-qualified name. + * @param fqn the fully-qualified name of the package + * @return the built {@link PackageProxy} + */ + protected static PackageProxy from(String fqn) { + if(fqn == null || fqn.equals("")) return ROOT; + return new PackageProxy(from(extractParentFromFQN(fqn)), fqn); + } + + /** + * Builds a {@link PackageProxy} from a reflective {@link Package} object. + * @param p the {@link Package} object + * @return the built {@link PackageProxy} + */ + protected static PackageProxy from(Package p) { + return from(extractParentFromFQN(p.getName())); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof PackageProxy && super.equals(obj); + } +} diff --git a/src/main/java/ftbsc/lll/proxies/impl/TypeProxy.java b/src/main/java/ftbsc/lll/proxies/impl/TypeProxy.java new file mode 100644 index 0000000..9f613b0 --- /dev/null +++ b/src/main/java/ftbsc/lll/proxies/impl/TypeProxy.java @@ -0,0 +1,199 @@ +package ftbsc.lll.proxies.impl; + +import ftbsc.lll.proxies.AbstractProxy; +import ftbsc.lll.proxies.ProxyType; +import ftbsc.lll.proxies.QualifiableProxy; +import org.objectweb.asm.Type; + +import java.lang.reflect.Modifier; + +import static ftbsc.lll.tools.DescriptorBuilder.nameToDescriptor; + +/** + * A container for information about classes to be used + * in ASM patching. + * @since 0.4.0 + */ +public class TypeProxy extends QualifiableProxy { + /** + * Whether this proxy represents a primitive. + */ + public final boolean primitive; + + /** + * Protected constructor, called only from the builder. + * @param name the name of the class + * @param descriptor the descriptor of the class + * @param modifiers the modifiers of the class + * @param parent the package containing this class + * @param primitive whether the proxy is a primitive + */ + protected TypeProxy(String name, String descriptor, int modifiers, String parent, boolean primitive) { + super(descriptor, modifiers, PackageProxy.from(parent), String.format("%s.%s", name, parent), ProxyType.TYPE); + this.primitive = primitive; + } + + /** + * Protected constructor, called only from the builder. + * @param name the name of the class + * @param descriptor the descriptor of the element + * @param modifiers the modifiers of the class + * @param primitive whether the proxy is a primitive + * @param containerClass the FQN of the parent class of the class + */ + protected TypeProxy(String name, String descriptor, int modifiers, QualifiableProxy containerClass, boolean primitive) { + super(descriptor, modifiers, containerClass, String.format("%s$%s", name, containerClass.fullyQualifiedName), ProxyType.TYPE); + this.primitive = primitive; + } + + /** + * Builds a {@link TypeProxy} from a {@link Type} and modifiers. + * @param type the {@link Type} representing this Class + * @param modifiers the modifiers of the class + * @return the builty {@link TypeProxy} + */ + public static TypeProxy from(Type type, int modifiers) { + while(type.getSort() == Type.ARRAY) + type = type.getElementType(); + String fqn = type.getInternalName().replace('/', '.'); + String simpleName = extractSimpleNameFromFQN(fqn); + String parent = extractParentFromFQN(fqn); + boolean primitive = type.getSort() < Type.ARRAY; + if(fqn.contains("$")) + return new TypeProxy(simpleName, type.getDescriptor(), modifiers, from(type, Modifier.PUBLIC), primitive); + else return new TypeProxy(simpleName, type.getDescriptor(), modifiers, parent, primitive); + } + + /** + * Builds a {@link TypeProxy} given only the fully-qualified name and modifiers. + * If present, parent classes will be assumed to have {@code public} as their + * only modifier. + * @param fqn the fully qualified name of the desired class + * @param arrayLevel the array level for this type + * @param modifiers the access modifiers of the desired class + * @return the built {@link TypeProxy} + */ + protected static TypeProxy from(String fqn, int arrayLevel, int modifiers) { + return from(Type.getObjectType(nameToDescriptor(fqn, arrayLevel)), modifiers); + } + + /** + * Builds a {@link TypeProxy} from a {@link Class} object. + * @param clazz the {@link Class} object representing the target class + * @return the built {@link TypeProxy} + */ + public static TypeProxy from(Class clazz) { + Class parentClass = clazz.getEnclosingClass(); + if(parentClass == null) + return new TypeProxy( + clazz.getSimpleName(), + Type.getDescriptor(clazz), + clazz.getModifiers(), + clazz.getPackage().getName(), + clazz.isPrimitive() + ); + else + return new TypeProxy( + clazz.getSimpleName(), + Type.getDescriptor(clazz), + clazz.getModifiers(), + from(parentClass), + clazz.isPrimitive() + ); + } + + /** + * Returns a new instance of {@link TypeProxy.Builder}. + * @param name the name of the class + * @return the builder object for class proxies + */ + public static Builder builder(String name) { + return new Builder(name); + } + + /** + * Indicates whether the given object is a proxy for the same element as this. + * @param obj the object to perform + * @return true if it's equal + */ + @Override + public boolean equals(Object obj) { + return obj instanceof TypeProxy && super.equals(obj); + } + + /** + * A builder object for {@link TypeProxy}. + */ + public static class Builder extends AbstractProxy.Builder { + + /** + * Whether the proxy represents a primitive. + */ + private boolean primitive; + + /** + * The constructor of the builder, used only internally. + * @param name the "simple name" of the class + */ + Builder(String name) { + super(name); + this.primitive = false; + } + + /** + * Sets this class as an inner class and sets the containing + * class to the given class object. + * @param containerClass the {@link Class} representing the + * container class + * @return the builder's state after the change + */ + public Builder setParent(Class containerClass) { + super.setParent(TypeProxy.from(containerClass)); + return this; + } + + /** + * Sets this class as an inner class and builds a {@link TypeProxy} + * from the given parent and modifiers. + * @param parentFQN the fully qualified name of the parent + * @param modifiers the modifiers of the parent (if it's a class) + * @param isParentPackage whether this parent should be interpreted as a package or class + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, int modifiers, boolean isParentPackage) { + super.setParent(isParentPackage ? PackageProxy.from(parentFQN) : TypeProxy.from(parentFQN, 0, modifiers)); + return this; + } + + /** + * Sets this class as an inner class and builds a {@link TypeProxy} + * from the given parent. + * @param parentFQN the fully qualified name of the parent + * @param isParentPackage whether this parent should be interpreted as a package or class + * @return the builder's state after the change + */ + public Builder setParent(String parentFQN, boolean isParentPackage) { + return this.setParent(parentFQN, 0, isParentPackage); + } + + /** + * Sets the primitive flag to true or false, to signal that the type here specified + * is a primitive. + * @param primitive the new state of the primitive flag + * @return the builder's state after the change + */ + public Builder setPrimitive(boolean primitive) { + this.primitive = primitive; + return this; + } + + /** + * Builds a {@link TypeProxy} of the given kind. + * @return the built {@link TypeProxy} + */ + @Override + public TypeProxy build() { + return new TypeProxy(this.name, this.descriptor, this.modifiers, this.parent, this.primitive); + } + } +} \ No newline at end of file diff --git a/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java b/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java index 068ade0..d1ac595 100644 --- a/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java +++ b/src/main/java/ftbsc/lll/tools/nodes/FieldProxyInsnNode.java @@ -1,6 +1,6 @@ package ftbsc.lll.tools.nodes; -import ftbsc.lll.proxies.FieldProxy; +import ftbsc.lll.proxies.impl.FieldProxy; import org.objectweb.asm.tree.FieldInsnNode; /** diff --git a/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java b/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java index 01549a8..73a26d7 100644 --- a/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java +++ b/src/main/java/ftbsc/lll/tools/nodes/MethodProxyInsnNode.java @@ -1,6 +1,6 @@ package ftbsc.lll.tools.nodes; -import ftbsc.lll.proxies.MethodProxy; +import ftbsc.lll.proxies.impl.MethodProxy; import org.objectweb.asm.tree.MethodInsnNode; /** diff --git a/src/main/java/ftbsc/lll/tools/nodes/TypeProxyInsnNode.java b/src/main/java/ftbsc/lll/tools/nodes/TypeProxyInsnNode.java index e5b5f2a..9e78dc9 100644 --- a/src/main/java/ftbsc/lll/tools/nodes/TypeProxyInsnNode.java +++ b/src/main/java/ftbsc/lll/tools/nodes/TypeProxyInsnNode.java @@ -1,6 +1,6 @@ package ftbsc.lll.tools.nodes; -import ftbsc.lll.proxies.TypeProxy; +import ftbsc.lll.proxies.impl.TypeProxy; import org.objectweb.asm.tree.TypeInsnNode; /** -- cgit v1.2.3-56-ga3b1