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

com.llamalad7.mixinextras.sugar.impl.SugarWrapperImpl Maven / Gradle / Ivy

package com.llamalad7.mixinextras.sugar.impl;

import com.llamalad7.mixinextras.sugar.SugarBridge;
import com.llamalad7.mixinextras.sugar.impl.handlers.HandlerInfo;
import com.llamalad7.mixinextras.utils.CompatibilityHelper;
import com.llamalad7.mixinextras.utils.GenericParamParser;
import com.llamalad7.mixinextras.utils.MixinInternals;
import com.llamalad7.mixinextras.wrapper.InjectorWrapperImpl;
import org.apache.commons.lang3.tuple.Pair;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import org.spongepowered.asm.mixin.injection.struct.InjectionInfo;
import org.spongepowered.asm.mixin.injection.struct.InjectionNodes;
import org.spongepowered.asm.mixin.injection.struct.Target;
import org.spongepowered.asm.mixin.injection.throwables.InjectionError;
import org.spongepowered.asm.mixin.injection.throwables.InvalidInjectionException;
import org.spongepowered.asm.mixin.transformer.MixinTargetContext;
import org.spongepowered.asm.util.Annotations;
import org.spongepowered.asm.util.asm.MethodNodeEx;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SugarWrapperImpl extends InjectorWrapperImpl {
    private final InjectionInfo wrapperInfo;
    private final AnnotationNode originalAnnotation;
    private final List sugarAnnotations;
    private final ArrayList generics;
    private final MethodNode handler;
    private final InjectionInfo delegate;
    private final SugarInjector sugarInjector;

    protected SugarWrapperImpl(InjectionInfo wrapper, MixinTargetContext mixin, MethodNode method, AnnotationNode annotation) {
        super(wrapper, mixin, method, annotation, true);
        wrapperInfo = wrapper;
        method.visibleAnnotations.remove(annotation);
        method.visibleAnnotations.add(originalAnnotation = Annotations.getValue(annotation, "original"));
        sugarAnnotations = Annotations.getValue(annotation, "sugars");
        generics = new ArrayList<>(
                GenericParamParser.getParameterGenerics(method.desc, Annotations.getValue(annotation, "signature"))
        );
        handler = prepareHandler(method);
        sugarInjector = new SugarInjector(wrapperInfo, mixin.getMixin(), handler, sugarAnnotations, generics);
        sugarInjector.stripSugar();
        delegate = InjectionInfo.parse(mixin, handler);
        sugarInjector.setTargets(MixinInternals.getTargets(delegate));
        if (!isValid()) {
            // The injector is now dropped by mixin, so we must make sure the handler method is in a valid state.
            sugarInjector.reSugarHandler();
        }
    }

    @Override
    protected InjectionInfo getDelegate() {
        return delegate;
    }

    @Override
    protected MethodNode getHandler() {
        return handler;
    }

    @Override
    protected void prepare() {
        super.prepare();
        sugarInjector.prepareSugar();
    }

    @Override
    protected void granularInject(HandlerCallCallback callback) {
        Map>> handlerCallMap = new HashMap<>();
        super.granularInject(((target, sourceNode, call) -> {
            callback.onFound(target, sourceNode, call);
            handlerCallMap.computeIfAbsent(target, k -> new ArrayList<>()).add(Pair.of(sourceNode, call));
        }));
        sugarInjector.reSugarHandler();
        sugarInjector.transformHandlerCalls(handlerCallMap);
    }

    @Override
    protected void doPostInject(Runnable postInject) {
        try {
            super.doPostInject(postInject);
        } catch (InvalidInjectionException | InjectionError e) {
            for (SugarApplicationException sugarException : sugarInjector.getExceptions()) {
                e.addSuppressed(sugarException);
            }
            throw e;
        }
    }

    private MethodNode prepareHandler(MethodNode original) {
        IMixinInfo mixin = CompatibilityHelper.getMixin(wrapperInfo).getMixin();
        HandlerInfo handlerInfo = SugarInjector.getHandlerInfo(mixin, original, sugarAnnotations, generics);
        if (handlerInfo == null) {
            return original;
        }
        MethodNodeEx newMethod = new MethodNodeEx(
                original.access, MethodNodeEx.getName(original), original.desc, original.signature,
                original.exceptions.toArray(new String[0]), mixin);
        original.accept(newMethod);
        original.visibleAnnotations.remove(originalAnnotation);
        newMethod.name = original.name;
        newMethod.tryCatchBlocks = null;
        newMethod.visitAnnotation(Type.getDescriptor(SugarBridge.class), false);
        handlerInfo.transformHandler(classNode, newMethod);
        handlerInfo.transformGenerics(generics);
        classNode.methods.add(newMethod);
        return newMethod;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy