<commit_before>package net.bytebuddy.implementation.bind.annotation;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.EqualsAndHashCode;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.ParameterDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.scaffold.FieldLocator;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.bind.MethodDelegationBinder;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.implementation.bytecode.constant.*;
import net.bytebuddy.utility.JavaConstant;
import net.bytebuddy.utility.JavaType;

import java.lang.annotation.Annotation;
import java.util.*;

import static net.bytebuddy.matcher.ElementMatchers.isGetter;
import static net.bytebuddy.matcher.ElementMatchers.isSetter;

/**
 * This {@link net.bytebuddy.implementation.bind.MethodDelegationBinder} binds
 * method by analyzing annotations found on the <i>target</i> method that is subject to a method binding.
 */
@EqualsAndHashCode
public class TargetMethodAnnotationDrivenBinder implements MethodDelegationBinder {

    /**
     * The processor for performing an actual method delegation.
     */
    private final DelegationProcessor delegationProcessor;

    /**
     * Creates a new target method annotation-driven binder.
     *
     * @param delegationProcessor The delegation proessor to use.
     */
    protected TargetMethodAnnotationDrivenBinder(DelegationProcessor delegationProcessor) {
        this.delegationProcessor = delegationProcessor;
    }

    /**
     * Creates a new method delegation binder that binds method based on annotations found on the target method.
     *
     * @param parameterBinders A list of parameter binder delegates. Each such delegate is responsible for creating a
     *                         {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.ParameterBinding}
     *                         for a specific annotation.
     * @return An appropriate method delegation binder.
     */
    public static MethodDelegationBinder of(List<? extends ParameterBinder<?>> parameterBinders) {
        return new TargetMethodAnnotationDrivenBinder(DelegationProcessor.of(parameterBinders));
    }

    @Override
    public MethodDelegationBinder.Record compile(MethodDescription candidate) {
        if (IgnoreForBinding.Verifier.check(candidate)) {
            return MethodDelegationBinder.Record.Illegal.INSTANCE;
        }
        List<DelegationProcessor.Handler> handlers = new ArrayList<DelegationProcessor.Handler>(candidate.getParameters().size());
        for (ParameterDescription parameterDescription : candidate.getParameters()) {
            handlers.add(delegationProcessor.prepare(parameterDescription));
        }
        return new Record(candidate, handlers, RuntimeType.Verifier.check(candidate));
    }

    /**
     * A compiled record of a target method annotation-driven binder.
     */
    @EqualsAndHashCode
    protected static class Record implements MethodDelegationBinder.Record {

        /**
         * The candidate method.
         */
        private final MethodDescription candidate;

        /**
         * A list of handlers for each parameter.
         */
        private final List<DelegationProcessor.Handler> handlers;

        /**
         * The typing to apply.
         */
        private final Assigner.Typing typing;

        /**
         * Creates a default compiled method delegation binder.
         *
         * @param candidate The candidate method.
         * @param handlers  A list of handlers for each parameter.
         * @param typing    The typing to apply.
         */
        protected Record(MethodDescription candidate, List<DelegationProcessor.Handler> handlers, Assigner.Typing typing) {
            this.candidate = candidate;
            this.handlers = handlers;
            this.typing = typing;
        }

        @Override
        public MethodBinding bind(Implementation.Target implementationTarget,
                                  MethodDescription source,
                                  MethodDelegationBinder.TerminationHandler terminationHandler,
                                  MethodInvoker methodInvoker,
                                  Assigner assigner) {
            if (!candidate.isAccessibleTo(implementationTarget.getInstrumentedType())) {
                return MethodBinding.Illegal.INSTANCE;
            }
            StackManipulation methodTermination = terminationHandler.resolve(assigner, typing, source, candidate);
            if (!methodTermination.isValid()) {
                return MethodBinding.Illegal.INSTANCE;
            }
            MethodBinding.Builder methodDelegationBindingBuilder = new MethodBinding.Builder(methodInvoker, candidate);
            for (DelegationProcessor.Handler handler : handlers) {
                ParameterBinding<?> parameterBinding = handler.bind(source, implementationTarget, assigner);
                if (!parameterBinding.isValid() || !methodDelegationBindingBuilder.append(parameterBinding)) {
                    return MethodBinding.Illegal.INSTANCE;
                }
            }
            return methodDelegationBindingBuilder.build(methodTermination);
        }
    }

    /**
     * A parameter binder is used as a delegate for binding a parameter according to a particular annotation type found
     * on this parameter.
     *
     * @param <T> The {@link java.lang.annotation.Annotation#annotationType()} handled by this parameter binder.
     */
    @SuppressFBWarnings(value = "IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION", justification = "Safe initialization is implied")
    public interface ParameterBinder<T extends Annotation> {

        /**
         * The default parameter binders to be used.
         */
        List<ParameterBinder<?>> DEFAULTS = Collections.unmodifiableList(Arrays.<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>>asList(
                Argument.Binder.INSTANCE,
                AllArguments.Binder.INSTANCE,
                Origin.Binder.INSTANCE,
                This.Binder.INSTANCE,
                Super.Binder.INSTANCE,
                Default.Binder.INSTANCE,
                SuperCall.Binder.INSTANCE,
                DefaultCall.Binder.INSTANCE,
                SuperMethod.Binder.INSTANCE,
                DefaultMethod.Binder.INSTANCE,
                FieldValue.Binder.INSTANCE,
                StubValue.Binder.INSTANCE,
                Empty.Binder.INSTANCE));<commit_msg>Added toString method for better error messages.<commit_after>package net.bytebuddy.implementation.bind.annotation;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.EqualsAndHashCode;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.ParameterDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.scaffold.FieldLocator;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.bind.MethodDelegationBinder;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.implementation.bytecode.constant.*;
import net.bytebuddy.utility.JavaConstant;
import net.bytebuddy.utility.JavaType;

import java.lang.annotation.Annotation;
import java.util.*;

import static net.bytebuddy.matcher.ElementMatchers.isGetter;
import static net.bytebuddy.matcher.ElementMatchers.isSetter;

/**
 * This {@link net.bytebuddy.implementation.bind.MethodDelegationBinder} binds
 * method by analyzing annotations found on the <i>target</i> method that is subject to a method binding.
 */
@EqualsAndHashCode
public class TargetMethodAnnotationDrivenBinder implements MethodDelegationBinder {

    /**
     * The processor for performing an actual method delegation.
     */
    private final DelegationProcessor delegationProcessor;

    /**
     * Creates a new target method annotation-driven binder.
     *
     * @param delegationProcessor The delegation proessor to use.
     */
    protected TargetMethodAnnotationDrivenBinder(DelegationProcessor delegationProcessor) {
        this.delegationProcessor = delegationProcessor;
    }

    /**
     * Creates a new method delegation binder that binds method based on annotations found on the target method.
     *
     * @param parameterBinders A list of parameter binder delegates. Each such delegate is responsible for creating a
     *                         {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.ParameterBinding}
     *                         for a specific annotation.
     * @return An appropriate method delegation binder.
     */
    public static MethodDelegationBinder of(List<? extends ParameterBinder<?>> parameterBinders) {
        return new TargetMethodAnnotationDrivenBinder(DelegationProcessor.of(parameterBinders));
    }

    @Override
    public MethodDelegationBinder.Record compile(MethodDescription candidate) {
        if (IgnoreForBinding.Verifier.check(candidate)) {
            return MethodDelegationBinder.Record.Illegal.INSTANCE;
        }
        List<DelegationProcessor.Handler> handlers = new ArrayList<DelegationProcessor.Handler>(candidate.getParameters().size());
        for (ParameterDescription parameterDescription : candidate.getParameters()) {
            handlers.add(delegationProcessor.prepare(parameterDescription));
        }
        return new Record(candidate, handlers, RuntimeType.Verifier.check(candidate));
    }

    /**
     * A compiled record of a target method annotation-driven binder.
     */
    @EqualsAndHashCode
    protected static class Record implements MethodDelegationBinder.Record {

        /**
         * The candidate method.
         */
        private final MethodDescription candidate;

        /**
         * A list of handlers for each parameter.
         */
        private final List<DelegationProcessor.Handler> handlers;

        /**
         * The typing to apply.
         */
        private final Assigner.Typing typing;

        /**
         * Creates a default compiled method delegation binder.
         *
         * @param candidate The candidate method.
         * @param handlers  A list of handlers for each parameter.
         * @param typing    The typing to apply.
         */
        protected Record(MethodDescription candidate, List<DelegationProcessor.Handler> handlers, Assigner.Typing typing) {
            this.candidate = candidate;
            this.handlers = handlers;
            this.typing = typing;
        }

        @Override
        public MethodBinding bind(Implementation.Target implementationTarget,
                                  MethodDescription source,
                                  MethodDelegationBinder.TerminationHandler terminationHandler,
                                  MethodInvoker methodInvoker,
                                  Assigner assigner) {
            if (!candidate.isAccessibleTo(implementationTarget.getInstrumentedType())) {
                return MethodBinding.Illegal.INSTANCE;
            }
            StackManipulation methodTermination = terminationHandler.resolve(assigner, typing, source, candidate);
            if (!methodTermination.isValid()) {
                return MethodBinding.Illegal.INSTANCE;
            }
            MethodBinding.Builder methodDelegationBindingBuilder = new MethodBinding.Builder(methodInvoker, candidate);
            for (DelegationProcessor.Handler handler : handlers) {
                ParameterBinding<?> parameterBinding = handler.bind(source, implementationTarget, assigner);
                if (!parameterBinding.isValid() || !methodDelegationBindingBuilder.append(parameterBinding)) {
                    return MethodBinding.Illegal.INSTANCE;
                }
            }
            return methodDelegationBindingBuilder.build(methodTermination);
        }

        @Override
        public String toString() {
            return candidate.toString();
        }
    }

    /**
     * A parameter binder is used as a delegate for binding a parameter according to a particular annotation type found
     * on this parameter.
     *
     * @param <T> The {@link java.lang.annotation.Annotation#annotationType()} handled by this parameter binder.
     */
    @SuppressFBWarnings(value = "IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION", justification = "Safe initialization is implied")
    public interface ParameterBinder<T extends Annotation> {

        /**
         * The default parameter binders to be used.
         */
        List<ParameterBinder<?>> DEFAULTS = Collections.unmodifiableList(Arrays.<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>>asList(
                Argument.Binder.INSTANCE,
                AllArguments.Binder.INSTANCE,
                Origin.Binder.INSTANCE,
                This.Binder.INSTANCE,
                Super.Binder.INSTANCE,
                Default.Binder.INSTANCE,
                SuperCall.Binder.INSTANCE,
                DefaultCall.Binder.INSTANCE,
                SuperMethod.Binder.INSTANCE,
                DefaultMethod.Binder.INSTANCE,
                FieldValue.Binder.INSTANCE,
                StubValue.Binder.INSTANCE,
                Empty.Binder.INSTANCE));
{'fraction_non_alphanumeric': 0.07506546406750073, 'fraction_numerical': 0.0, 'mean_word_length': 2.7199675324675323, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1925182', 'n_tokens_mistral': 3393, 'n_tokens_neox': 3279, 'n_words': 759}