All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.llamalad7.mixinextras.injector.wrapoperation.WrapOperationInjectionInfo Maven / Gradle / Ivy

package com.llamalad7.mixinextras.injector.wrapoperation;

import com.llamalad7.mixinextras.injector.LateApplyingInjectorInfo;
import com.llamalad7.mixinextras.injector.MixinExtrasInjectionInfo;
import com.llamalad7.mixinextras.utils.*;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import org.spongepowered.asm.mixin.injection.code.Injector;
import org.spongepowered.asm.mixin.injection.points.BeforeConstant;
import org.spongepowered.asm.mixin.injection.struct.InjectionInfo;
import org.spongepowered.asm.mixin.injection.struct.InjectionInfo.HandlerPrefix;
import org.spongepowered.asm.mixin.injection.struct.InjectionNodes;
import org.spongepowered.asm.mixin.injection.struct.Target;
import org.spongepowered.asm.mixin.transformer.MixinTargetContext;
import org.spongepowered.asm.util.Annotations;
import org.spongepowered.asm.util.Bytecode;

import java.util.List;
import java.util.ListIterator;
import java.util.Map;

@InjectionInfo.AnnotationType(WrapOperation.class)
@HandlerPrefix("wrapOperation")
public class WrapOperationInjectionInfo extends MixinExtrasInjectionInfo implements LateApplyingInjectorInfo {
    private static final MixinExtrasLogger LOGGER = MixinExtrasLogger.get("WrapOperation");
    private LateApplyingInjectorInfo injectionInfoToQueue = this;

    public WrapOperationInjectionInfo(MixinTargetContext mixin, MethodNode method, AnnotationNode annotation) {
        super(mixin, method, annotation, determineAtKey(mixin, method, annotation));
    }

    @Override
    protected Injector parseInjector(AnnotationNode injectAnnotation) {
        return new WrapOperationInjector(this);
    }

    @Override
    public void prepare() {
        super.prepare();
        InjectorUtils.checkForDupedNews(this.targetNodes);
        for (Map.Entry> entry : this.targetNodes.entrySet()) {
            Target target = entry.getKey();
            for (ListIterator it = entry.getValue().listIterator(); it.hasNext(); ) {
                InjectionNodes.InjectionNode node = it.next();
                AbstractInsnNode currentTarget = node.getCurrentTarget();
                if (currentTarget.getOpcode() == Opcodes.NEW) {
                    MethodInsnNode initCall = ASMUtils.findInitNodeFor(target, (TypeInsnNode) currentTarget);
                    if (initCall == null) {
                        LOGGER.warn("NEW node {} in {} has no init call?", Bytecode.describeNode(currentTarget), target);
                        it.remove();
                        continue;
                    }
                    node.decorate(Decorations.NEW_ARG_TYPES, Type.getArgumentTypes(initCall.desc));
                }
            }
        }
    }

    @Override
    public void inject() {
        WrapOperationApplicatorExtension.offerInjection(this.mixin.getTarget(), injectionInfoToQueue);
    }

    @Override
    public void postInject() {
    }

    @Override
    public void lateInject() {
        super.inject();
    }

    @Override
    public void latePostInject() {
        super.postInject();
    }

    @Override
    public void wrap(LateApplyingInjectorInfo outer) {
        this.injectionInfoToQueue = outer;
    }

    @Override
    protected void parseInjectionPoints(List ats) {
        if (this.atKey.equals("at")) {
            super.parseInjectionPoints(ats);
            return;
        }
        // If we're wrapping a `constant`, we need to parse the injection points ourselves.
        Type returnType = Type.getReturnType(this.method.desc);

        for (AnnotationNode at : ats) {
            this.injectionPoints.add(new BeforeConstant(CompatibilityHelper.getMixin(this), at, returnType.getDescriptor()));
        }
    }

    private static String determineAtKey(MixinTargetContext mixin, MethodNode method, AnnotationNode annotation) {
        boolean at = Annotations.getValue(annotation, "at") != null;
        boolean constant = Annotations.getValue(annotation, "constant") != null;
        if (at == constant) {
            throw new IllegalStateException(
                    String.format("@WrapOperation injector %s::%s must specify exactly one of `at` and `constant`, got %s.",
                            mixin.getMixin().getClassName(),
                            method.name,
                            at ? "both" : "neither"
                    )
            );
        } else {
            return at ? "at" : "constant";
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy