Allow Overwrite methods to be aliased

This commit is contained in:
Mumfrey committed 2015-04-09 16:58:38 +01:00
1 parent 441c3a7e93
commit eb4e693cde
2 files changed
+63 -25

No files matched your search

@@ -53,5 +53,21 @@ import java.lang.annotation.Target;
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Overwrite {
/**
* Supplies possible aliases for this method. This should <b>only</b>
* be used in the following scenarios:
*
* <ul>
* <li>When shadowing a sythetic method which can have differen names at
* development time because it is regenerated by the compiler.
* </li>
* <li>When another mod or transformer is known to change the name of a
* field</li>
* </ul>
*
* @return Aliases for this member
*/
public String[] aliases() default { };
}
@@ -24,6 +24,7 @@
*/
package org.spongepowered.asm.mixin.transformer;
import java.lang.annotation.Annotation;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
@@ -37,6 +38,7 @@ import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.transformer.ClassInfo.Field;
import org.spongepowered.asm.mixin.transformer.ClassInfo.Method;
@@ -154,33 +156,53 @@ class MixinPreProcessor {
private void attachMethods(MixinTargetContext context) {
for (MethodNode mixinMethod : this.classNode.methods) {
AnnotationNode shadowAnnotation = ASMHelper.getVisibleAnnotation(mixinMethod, Shadow.class);
if (shadowAnnotation == null) {
if (this.processMethod(context, mixinMethod, Shadow.class, true, true)) {
continue;
}
Method method = this.mixin.getClassInfo().findMethod(mixinMethod, true);
MethodNode target = MixinPreProcessor.findMethod(context.getTargetClass(), mixinMethod, shadowAnnotation);
if (target == null) {
throw new InvalidMixinException(this.mixin, "Shadow method " + mixinMethod.name + " was not located in the target class");
}
if (Constants.INIT.equals(target.name)) {
throw new InvalidMixinException(this.mixin, "Nice try! Cannot alias a constructor!");
}
if (!target.name.equals(mixinMethod.name)) {
if ((target.access & Opcodes.ACC_PRIVATE) == 0) {
throw new InvalidMixinException(this.mixin, "Non-private method cannot be aliased. Found " + target.name);
}
mixinMethod.name = target.name;
method.renameTo(target.name);
}
this.processMethod(context, mixinMethod, Overwrite.class, false, false);
}
}
private boolean processMethod(MixinTargetContext context, MethodNode mixinMethod, Class<? extends Annotation> annotationType,
boolean mustExist, boolean mustBePrivate) {
AnnotationNode annotation = ASMHelper.getVisibleAnnotation(mixinMethod, annotationType);
if (annotation == null) {
return false;
}
Method method = this.mixin.getClassInfo().findMethod(mixinMethod, true);
MethodNode target = MixinPreProcessor.findMethod(context.getTargetClass(), mixinMethod, annotation);
if (target == null) {
if (!mustExist) {
return false;
}
throw new InvalidMixinException(this.mixin, annotationType.getSimpleName() + " method " + mixinMethod.name
+ " was not located in the target class");
}
if (Constants.INIT.equals(target.name)) {
throw new InvalidMixinException(this.mixin, "Nice try! Cannot alias a constructor!");
}
if (!target.name.equals(mixinMethod.name)) {
if (mustBePrivate && (target.access & Opcodes.ACC_PRIVATE) == 0) {
throw new InvalidMixinException(this.mixin, "Non-private method cannot be aliased. Found " + target.name);
}
System.err.printf("=================================================================================\n");
System.err.printf("Renaming %s -> %s\n", mixinMethod.name, target.name);
System.err.printf("=================================================================================\n");
mixinMethod.name = target.name;
method.renameTo(target.name);
}
return true;
}
private void attachFields(MixinTargetContext context) {
for (Iterator<FieldNode> iter = this.classNode.fields.iterator(); iter.hasNext();) {
FieldNode mixinField = iter.next();
@@ -273,11 +295,11 @@ class MixinPreProcessor {
}
}
private static MethodNode findMethod(ClassNode classNode, MethodNode method, AnnotationNode shadow) {
private static MethodNode findMethod(ClassNode classNode, MethodNode method, AnnotationNode annotation) {
Deque<String> aliases = new LinkedList<String>();
aliases.add(method.name);
if (shadow != null) {
List<String> aka = ASMHelper.<List<String>>getAnnotationValue(shadow, "aliases");
if (annotation != null) {
List<String> aka = ASMHelper.<List<String>>getAnnotationValue(annotation, "aliases");
if (aka != null) {
aliases.addAll(aka);
}