• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

raphw / byte-buddy / #801

27 Oct 2025 09:37AM UTC coverage: 84.715% (-0.4%) from 85.118%
#801

push

raphw
Fix imports.

29586 of 34924 relevant lines covered (84.72%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.86
/byte-buddy-dep/src/main/java/net/bytebuddy/asm/MemberSubstitution.java
1
/*
2
 * Copyright 2014 - Present Rafael Winterhalter
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package net.bytebuddy.asm;
17

18
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.ClassFileVersion;
20
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
21
import net.bytebuddy.build.SafeVarargsPlugin;
22
import net.bytebuddy.description.ByteCodeElement;
23
import net.bytebuddy.description.annotation.AnnotationDescription;
24
import net.bytebuddy.description.annotation.AnnotationValue;
25
import net.bytebuddy.description.enumeration.EnumerationDescription;
26
import net.bytebuddy.description.field.FieldDescription;
27
import net.bytebuddy.description.field.FieldList;
28
import net.bytebuddy.description.method.MethodDescription;
29
import net.bytebuddy.description.method.MethodList;
30
import net.bytebuddy.description.method.ParameterDescription;
31
import net.bytebuddy.description.type.TypeDefinition;
32
import net.bytebuddy.description.type.TypeDescription;
33
import net.bytebuddy.description.type.TypeList;
34
import net.bytebuddy.description.type.TypeVariableToken;
35
import net.bytebuddy.dynamic.ClassFileLocator;
36
import net.bytebuddy.dynamic.TargetType;
37
import net.bytebuddy.dynamic.scaffold.FieldLocator;
38
import net.bytebuddy.dynamic.scaffold.MethodGraph;
39
import net.bytebuddy.implementation.Implementation;
40
import net.bytebuddy.implementation.bytecode.Duplication;
41
import net.bytebuddy.implementation.bytecode.Removal;
42
import net.bytebuddy.implementation.bytecode.StackManipulation;
43
import net.bytebuddy.implementation.bytecode.StackSize;
44
import net.bytebuddy.implementation.bytecode.TypeCreation;
45
import net.bytebuddy.implementation.bytecode.assign.Assigner;
46
import net.bytebuddy.implementation.bytecode.collection.ArrayFactory;
47
import net.bytebuddy.implementation.bytecode.constant.ClassConstant;
48
import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
49
import net.bytebuddy.implementation.bytecode.constant.FieldConstant;
50
import net.bytebuddy.implementation.bytecode.constant.IntegerConstant;
51
import net.bytebuddy.implementation.bytecode.constant.JavaConstantValue;
52
import net.bytebuddy.implementation.bytecode.constant.MethodConstant;
53
import net.bytebuddy.implementation.bytecode.constant.NullConstant;
54
import net.bytebuddy.implementation.bytecode.constant.SerializedConstant;
55
import net.bytebuddy.implementation.bytecode.constant.TextConstant;
56
import net.bytebuddy.implementation.bytecode.member.FieldAccess;
57
import net.bytebuddy.implementation.bytecode.member.Invokedynamic;
58
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
59
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
60
import net.bytebuddy.matcher.ElementMatcher;
61
import net.bytebuddy.matcher.ElementMatchers;
62
import net.bytebuddy.pool.TypePool;
63
import net.bytebuddy.utility.CompoundList;
64
import net.bytebuddy.utility.ConstantValue;
65
import net.bytebuddy.utility.JavaConstant;
66
import net.bytebuddy.utility.JavaType;
67
import net.bytebuddy.utility.OpenedClassReader;
68
import net.bytebuddy.utility.nullability.MaybeNull;
69
import net.bytebuddy.utility.visitor.LocalVariableAwareMethodVisitor;
70
import org.objectweb.asm.MethodVisitor;
71
import org.objectweb.asm.Opcodes;
72

73
import java.io.Serializable;
74
import java.lang.annotation.Annotation;
75
import java.lang.annotation.Documented;
76
import java.lang.annotation.ElementType;
77
import java.lang.annotation.Retention;
78
import java.lang.annotation.RetentionPolicy;
79
import java.lang.reflect.Constructor;
80
import java.lang.reflect.Field;
81
import java.lang.reflect.Method;
82
import java.lang.reflect.Type;
83
import java.util.ArrayList;
84
import java.util.Arrays;
85
import java.util.Collections;
86
import java.util.HashMap;
87
import java.util.Iterator;
88
import java.util.LinkedHashMap;
89
import java.util.List;
90
import java.util.Map;
91

92
import static net.bytebuddy.matcher.ElementMatchers.hasDescriptor;
93
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
94
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
95
import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
96
import static net.bytebuddy.matcher.ElementMatchers.isStatic;
97
import static net.bytebuddy.matcher.ElementMatchers.isVirtual;
98
import static net.bytebuddy.matcher.ElementMatchers.isVisibleTo;
99
import static net.bytebuddy.matcher.ElementMatchers.named;
100
import static net.bytebuddy.matcher.ElementMatchers.none;
101
import static net.bytebuddy.matcher.ElementMatchers.not;
102

103
/**
104
 * <p>
105
 * Substitutes field access, method invocations or constructor calls within a method's body.
106
 * </p>
107
 * <p>
108
 * <b>Note</b>: This substitution must not be used to match constructor calls to an instrumented class's super constructor invocation from
109
 * within a constructor. Matching such constructors will result in an invalid stack and a verification error.
110
 * </p>
111
 * <p>
112
 * <b>Note</b>: This visitor will compute the required stack size on a best effort basis. For allocating an optimal stack size, ASM needs
113
 * to be configured to compute the stack size.
114
 * </p>
115
 * <p>
116
 * <b>Important</b>: This component relies on using a {@link TypePool} for locating types within method bodies. Within a redefinition
117
 * or a rebasement, this type pool normally resolved correctly by Byte Buddy. When subclassing a type, the type pool must be set
118
 * explicitly, using {@link net.bytebuddy.dynamic.DynamicType.Builder#make(TypePool)} or any similar method. It is however not normally
119
 * necessary to use this component when subclassing a type where methods are only defined explicitly.
120
 * </p>
121
 */
122
@HashCodeAndEqualsPlugin.Enhance
123
public class MemberSubstitution implements AsmVisitorWrapper.ForDeclaredMethods.MethodVisitorWrapper {
124

125
    /**
126
     * The index of the this reference within a non-static method.
127
     */
128
    protected static final int THIS_REFERENCE = 0;
129

130
    /**
131
     * The method graph compiler to use.
132
     */
133
    private final MethodGraph.Compiler methodGraphCompiler;
134

135
    /**
136
     * The type pool resolver to use.
137
     */
138
    private final TypePoolResolver typePoolResolver;
139

140
    /**
141
     * {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
142
     */
143
    private final boolean strict;
144

145
    /**
146
     * {@code true} if the instrumentation should fail if applied to a method without match.
147
     */
148
    private final boolean failIfNoMatch;
149

150
    /**
151
     * The replacement factory to use.
152
     */
153
    private final Replacement.Factory replacementFactory;
154

155
    /**
156
     * Creates a default member substitution.
157
     *
158
     * @param strict {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
159
     */
160
    protected MemberSubstitution(boolean strict) {
161
        this(MethodGraph.Compiler.DEFAULT, TypePoolResolver.OfImplicitPool.INSTANCE, strict, false, Replacement.NoOp.INSTANCE);
1✔
162
    }
1✔
163

164
    /**
165
     * Creates a new member substitution.
166
     *
167
     * @param methodGraphCompiler The method graph compiler to use.
168
     * @param typePoolResolver    The type pool resolver to use.
169
     * @param strict              {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
170
     * @param failIfNoMatch       {@code true} if the instrumentation should fail if applied to a method without match.
171
     * @param replacementFactory  The replacement factory to use.
172
     */
173
    protected MemberSubstitution(MethodGraph.Compiler methodGraphCompiler,
174
                                 TypePoolResolver typePoolResolver,
175
                                 boolean strict,
176
                                 boolean failIfNoMatch,
177
                                 Replacement.Factory replacementFactory) {
1✔
178
        this.methodGraphCompiler = methodGraphCompiler;
1✔
179
        this.typePoolResolver = typePoolResolver;
1✔
180
        this.failIfNoMatch = failIfNoMatch;
1✔
181
        this.strict = strict;
1✔
182
        this.replacementFactory = replacementFactory;
1✔
183
    }
1✔
184

185
    /**
186
     * Creates a member substitution that requires the resolution of all fields and methods that are referenced within a method body. Doing so,
187
     * this component raises an exception if any member cannot be resolved what makes this component unusable when facing optional types.
188
     *
189
     * @return A strict member substitution.
190
     */
191
    public static MemberSubstitution strict() {
192
        return new MemberSubstitution(true);
1✔
193
    }
194

195
    /**
196
     * Creates a member substitution that skips any unresolvable fields or methods that are referenced within a method body. Using a relaxed
197
     * member substitution, methods containing optional types are supported. In the process, it is however possible that misconfigurations
198
     * of this component remain undiscovered.
199
     *
200
     * @return A relaxed member substitution.
201
     */
202
    public static MemberSubstitution relaxed() {
203
        return new MemberSubstitution(false);
1✔
204
    }
205

206
    /**
207
     * Substitutes any interaction with a field or method that matches the given matcher.
208
     *
209
     * @param matcher The matcher to determine what access to byte code elements to substitute.
210
     * @return A specification that allows to determine how to substitute any interaction with byte code elements that match the supplied matcher.
211
     */
212
    public WithoutSpecification<Target.ForMember> element(ElementMatcher<? super ByteCodeElement.Member> matcher) {
213
        return new WithoutSpecification.ForMatchedByteCodeElement(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory, matcher);
×
214
    }
215

216
    /**
217
     * Substitutes any field access that matches the given matcher.
218
     *
219
     * @param matcher The matcher to determine what fields to substitute.
220
     * @return A specification that allows to determine how to substitute any field access that match the supplied matcher.
221
     */
222
    public WithoutSpecification.ForMatchedField field(ElementMatcher<? super FieldDescription> matcher) {
223
        return new WithoutSpecification.ForMatchedField(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory, matcher);
1✔
224
    }
225

226
    /**
227
     * Substitutes any method invocation that matches the given matcher.
228
     *
229
     * @param matcher The matcher to determine what methods to substitute.
230
     * @return A specification that allows to determine how to substitute any method invocations that match the supplied matcher.
231
     */
232
    public WithoutSpecification.ForMatchedMethod method(ElementMatcher<? super MethodDescription> matcher) {
233
        return new WithoutSpecification.ForMatchedMethod(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory, matcher);
1✔
234
    }
235

236
    /**
237
     * Substitutes any constructor invocation that matches the given matcher.
238
     *
239
     * @param matcher The matcher to determine what constructors to substitute.
240
     * @return A specification that allows to determine how to substitute any constructor invocations that match the supplied matcher.
241
     */
242
    public WithoutSpecification<Target.ForMember> constructor(ElementMatcher<? super MethodDescription> matcher) {
243
        return invokable(isConstructor().and(matcher));
1✔
244
    }
245

246
    /**
247
     * Substitutes any method or constructor invocation that matches the given matcher.
248
     *
249
     * @param matcher The matcher to determine what method or constructors to substitute.
250
     * @return A specification that allows to determine how to substitute any constructor invocations that match the supplied matcher.
251
     */
252
    public WithoutSpecification<Target.ForMember> invokable(ElementMatcher<? super MethodDescription> matcher) {
253
        return new WithoutSpecification.ForMatchedMethod(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory, matcher);
1✔
254
    }
255

256
    /**
257
     * Matches invokedynamic instructions which represents Java lambda expressions.
258
     *
259
     * @return A member substitution for Java lambda expressions.
260
     */
261
    public WithoutSpecification.ForMatchedDynamicInvocation lambdaExpression() {
262
        return dynamic(new LambdaMetaFactoryMatcher());
1✔
263
    }
264

265
    /**
266
     * Matches invokedynamic instructions that are dispatched for the supplied method handle.
267
     *
268
     * @param matcher A matcher for the invokedynamic's bootstrap method.
269
     * @return A member substitution for invokedynamic instructions that are dispatched by any matched bootstrap method.
270
     */
271
    public WithoutSpecification.ForMatchedDynamicInvocation dynamic(ElementMatcher<? super JavaConstant.MethodHandle> matcher) {
272
        return new WithoutSpecification.ForMatchedDynamicInvocation(methodGraphCompiler,
1✔
273
                typePoolResolver,
274
                strict,
275
                failIfNoMatch,
276
                replacementFactory,
277
                matcher,
278
                ElementMatchers.<String>any(),
1✔
279
                ElementMatchers.<JavaConstant.MethodType>any(),
1✔
280
                ElementMatchers.<List<? extends JavaConstant>>any());
1✔
281
    }
282

283
    /**
284
     * Specifies the use of a specific method graph compiler for the resolution of virtual methods.
285
     *
286
     * @param methodGraphCompiler The method graph compiler to use.
287
     * @return A new member substitution that is equal to this but uses the specified method graph compiler.
288
     */
289
    public MemberSubstitution with(MethodGraph.Compiler methodGraphCompiler) {
290
        return new MemberSubstitution(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory);
×
291
    }
292

293
    /**
294
     * Specifies a type pool resolver to be used for locating members.
295
     *
296
     * @param typePoolResolver The type pool resolver to use.
297
     * @return A new instance of this member substitution that uses the supplied type pool resolver.
298
     */
299
    public MemberSubstitution with(TypePoolResolver typePoolResolver) {
300
        return new MemberSubstitution(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory);
×
301
    }
302

303
    /**
304
     * Specifies if this substitution should fail if applied on a method without a match.
305
     *
306
     * @param failIfNoMatch {@code true} if the instrumentation should fail if applied to a method without match.
307
     * @return A new instance of this member substitution that fails if applied on a method without a match.
308
     */
309
    public MemberSubstitution failIfNoMatch(boolean failIfNoMatch) {
310
        return new MemberSubstitution(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory);
1✔
311
    }
312

313
    /**
314
     * Applies this member substitution to any method that matches the supplied matcher.
315
     *
316
     * @param matcher The matcher to determine this substitutions application.
317
     * @return An ASM visitor wrapper that applies all specified substitutions for any matched method.
318
     */
319
    public AsmVisitorWrapper.ForDeclaredMethods on(ElementMatcher<? super MethodDescription> matcher) {
320
        return new AsmVisitorWrapper.ForDeclaredMethods().invokable(matcher, this);
1✔
321
    }
322

323
    /**
324
     * {@inheritDoc}
325
     */
326
    public MethodVisitor wrap(TypeDescription instrumentedType,
327
                              MethodDescription instrumentedMethod,
328
                              MethodVisitor methodVisitor,
329
                              Implementation.Context implementationContext,
330
                              TypePool typePool,
331
                              int writerFlags,
332
                              int readerFlags) {
333
        typePool = typePoolResolver.resolve(instrumentedType, instrumentedMethod, typePool);
1✔
334
        return new SubstitutingMethodVisitor(methodVisitor,
1✔
335
                instrumentedType,
336
                instrumentedMethod,
337
                methodGraphCompiler,
338
                strict,
339
                failIfNoMatch,
340
                replacementFactory.make(instrumentedType, instrumentedMethod, typePool),
1✔
341
                implementationContext,
342
                typePool,
343
                implementationContext.getClassFileVersion().isAtLeast(ClassFileVersion.JAVA_V11));
1✔
344
    }
345

346
    /**
347
     * A member substitution that lacks a specification for how to substitute the matched members references within a method body.
348
     *
349
     * @param <T> The type of the matched target.
350
     */
351
    @HashCodeAndEqualsPlugin.Enhance
352
    public abstract static class WithoutSpecification<T extends Target> {
353

354
        /**
355
         * The method graph compiler to use.
356
         */
357
        protected final MethodGraph.Compiler methodGraphCompiler;
358

359
        /**
360
         * The type pool resolver to use.
361
         */
362
        protected final TypePoolResolver typePoolResolver;
363

364
        /**
365
         * {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
366
         */
367
        protected final boolean strict;
368

369
        /**
370
         * {@code true} if the instrumentation should fail if applied to a method without match.
371
         */
372
        protected final boolean failIfNoMatch;
373

374
        /**
375
         * The replacement factory to use for creating substitutions.
376
         */
377
        protected final Replacement.Factory replacementFactory;
378

379
        /**
380
         * Creates a new member substitution that requires a specification for how to perform a substitution.
381
         *
382
         * @param methodGraphCompiler The method graph compiler to use.
383
         * @param typePoolResolver    The type pool resolver to use.
384
         * @param strict              {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
385
         * @param failIfNoMatch       {@code true} if the instrumentation should fail if applied to a method without match.
386
         * @param replacementFactory  The replacement factory to use for creating substitutions.
387
         */
388
        protected WithoutSpecification(MethodGraph.Compiler methodGraphCompiler,
389
                                       TypePoolResolver typePoolResolver,
390
                                       boolean strict,
391
                                       boolean failIfNoMatch,
392
                                       Replacement.Factory replacementFactory) {
1✔
393
            this.methodGraphCompiler = methodGraphCompiler;
1✔
394
            this.typePoolResolver = typePoolResolver;
1✔
395
            this.strict = strict;
1✔
396
            this.failIfNoMatch = failIfNoMatch;
1✔
397
            this.replacementFactory = replacementFactory;
1✔
398
        }
1✔
399

400
        /**
401
         * Subs any interaction with a matched byte code element. Any value read from the element will be replaced with the stubbed
402
         * value's default, i.e. {@code null} for reference types and the specific {@code 0} value for primitive types. Any written
403
         * value will simply be discarded.
404
         *
405
         * @return A member substitution that stubs any interaction with a matched byte code element.
406
         */
407
        public MemberSubstitution stub() {
408
            return replaceWith(Substitution.Stubbing.INSTANCE);
1✔
409
        }
410

411
        /**
412
         * Replaces any interaction with a matched byte code element with the provided compile-time constant.
413
         *
414
         * @param value The compile-time constant to set.
415
         * @return A member substitution that replaces any interaction with the supplied compile-time constant.
416
         */
417
        public MemberSubstitution replaceWithConstant(Object value) {
418
            ConstantValue constant = ConstantValue.Simple.wrap(value);
1✔
419
            return replaceWith(new Substitution.ForValue(constant.toStackManipulation(), constant.getTypeDescription().asGenericType()));
1✔
420
        }
421

422
        /**
423
         * <p>
424
         * Replaces any interaction with a matched byte code element by an interaction with the specified field. If a field
425
         * is replacing a method or constructor invocation, it is treated as if it was a field getter or setter respectively.
426
         * </p>
427
         * <p>
428
         * A replacement can only be applied if the field is compatible to the original byte code element, i.e. consumes an
429
         * instance of the declaring type if it is not {@code static} as an argument and consumes or produces an instance of
430
         * the field's type.
431
         * </p>
432
         *
433
         * @param field The field to access instead of interacting with any of the matched byte code elements.
434
         * @return A member substitution that replaces any matched byte code element with an access of the specified field.
435
         */
436
        public MemberSubstitution replaceWith(Field field) {
437
            return replaceWith(new FieldDescription.ForLoadedField(field));
1✔
438
        }
439

440
        /**
441
         * <p>
442
         * Replaces any interaction with a matched byte code element by an interaction with the specified field. If a field
443
         * is replacing a method or constructor invocation, it is treated as if it was a field getter or setter respectively.
444
         * </p>
445
         * <p>
446
         * A replacement can only be applied if the field is compatible to the original byte code element, i.e. consumes an
447
         * instance of the declaring type if it is not {@code static} as an argument and consumes or produces an instance of
448
         * the field's type.
449
         * </p>
450
         *
451
         * @param fieldDescription The field to access instead of interacting with any of the matched byte code elements.
452
         * @return A member substitution that replaces any matched byte code element with an access of the specified field.
453
         */
454
        public MemberSubstitution replaceWith(FieldDescription fieldDescription) {
455
            return replaceWith(new Substitution.ForFieldAccess.OfGivenField(fieldDescription));
1✔
456
        }
457

458
        /**
459
         * Replaces any interaction with a matched byte code element with a non-static field access on the first
460
         * parameter of the matched element. When matching a non-static field access or method invocation, the
461
         * substituted field is located on the same receiver type as the original access. For static access, the
462
         * first argument is used as a receiver.
463
         *
464
         * @param matcher A matcher for locating a field on the original interaction's receiver type.
465
         * @return A member substitution that replaces any matched byte code element with an access of the matched field.
466
         */
467
        public MemberSubstitution replaceWithField(ElementMatcher<? super FieldDescription> matcher) {
468
            return replaceWith(new Substitution.ForFieldAccess.OfMatchedField(matcher));
1✔
469
        }
470

471
        /**
472
         * <p>
473
         * Replaces any interaction with a matched byte code element by an invocation of the specified method. If a method
474
         * is replacing a field access, it is treated as if it was replacing an invocation of the field's getter or setter respectively.
475
         * </p>
476
         * <p>
477
         * A replacement can only be applied if the method is compatible to the original byte code element, i.e. consumes compatible
478
         * arguments and returns a compatible value. If the method is not {@code static}, it is treated as if {@code this} was an implicit
479
         * first argument.
480
         * </p>
481
         *
482
         * @param method The method to invoke instead of interacting with any of the matched byte code elements.
483
         * @return A member substitution that replaces any matched byte code element with an invocation of the specified method.
484
         */
485
        public MemberSubstitution replaceWith(Method method) {
486
            return replaceWith(new MethodDescription.ForLoadedMethod(method));
1✔
487
        }
488

489
        /**
490
         * <p>
491
         * Replaces any interaction with a matched byte code element by an invocation of the specified method. If a method
492
         * is replacing a field access, it is treated as if it was replacing an invocation of the field's getter or setter respectively.
493
         * </p>
494
         * <p>
495
         * A replacement can only be applied if the method is compatible to the original byte code element, i.e. consumes compatible
496
         * arguments and returns a compatible value. If the method is not {@code static}, it is treated as if {@code this} was an implicit
497
         * first argument.
498
         * </p>
499
         * <p>
500
         * <b>Important</b>: It is not allowed to specify a constructor or the static type initializer as a replacement.
501
         * </p>
502
         *
503
         * @param methodDescription The method to invoke instead of interacting with any of the matched byte code elements.
504
         * @return A member substitution that replaces any matched byte code element with an invocation of the specified method.
505
         */
506
        public MemberSubstitution replaceWith(MethodDescription methodDescription) {
507
            if (!methodDescription.isMethod()) {
1✔
508
                throw new IllegalArgumentException("Cannot use " + methodDescription + " as a replacement");
1✔
509
            }
510
            return replaceWith(new Substitution.ForMethodInvocation.OfGivenMethod(methodDescription));
1✔
511
        }
512

513
        /**
514
         * Replaces any interaction with a matched byte code element with a non-static method access on the first
515
         * parameter of the matched element. When matching a non-static field access or method invocation, the
516
         * substituted method is located on the same receiver type as the original access. For static access, the
517
         * first argument is used as a receiver.
518
         *
519
         * @param matcher A matcher for locating a method on the original interaction's receiver type.
520
         * @return A member substitution that replaces any matched byte code element with an access of the matched method.
521
         */
522
        public MemberSubstitution replaceWithMethod(ElementMatcher<? super MethodDescription> matcher) {
523
            return replaceWithMethod(matcher, methodGraphCompiler);
1✔
524
        }
525

526
        /**
527
         * Replaces any interaction with a matched byte code element with a non-static method access on the first
528
         * parameter of the matched element. When matching a non-static field access or method invocation, the
529
         * substituted method is located on the same receiver type as the original access. For static access, the
530
         * first argument is used as a receiver.
531
         *
532
         * @param matcher             A matcher for locating a method on the original interaction's receiver type.
533
         * @param methodGraphCompiler The method graph compiler to use for locating a method.
534
         * @return A member substitution that replaces any matched byte code element with an access of the matched method.
535
         */
536
        public MemberSubstitution replaceWithMethod(ElementMatcher<? super MethodDescription> matcher, MethodGraph.Compiler methodGraphCompiler) {
537
            return replaceWith(new Substitution.ForMethodInvocation.OfMatchedMethod(matcher, methodGraphCompiler));
1✔
538
        }
539

540
        /**
541
         * Replaces any interaction with a matched byte code element with an invocation of the instrumented
542
         * method. This can cause an infinite recursive call if the arguments to the method are not altered.
543
         *
544
         * @return A member substitution that replaces any matched byte code element with an invocation of the
545
         * instrumented method.
546
         */
547
        public MemberSubstitution replaceWithInstrumentedMethod() {
548
            return replaceWith(Substitution.ForMethodInvocation.OfInstrumentedMethod.INSTANCE);
1✔
549
        }
550

551
        /**
552
         * Replaces the matched byte code elements with a chain of substitutions that can operate on the same values as the substituted element. This is a
553
         * shortcut for creating a substitution chain with a default assigner.
554
         *
555
         * @param step The steps to apply for a substitution.
556
         * @return A member substitution that replaces any matched byte code element with the provided substitution chain.
557
         */
558
        @SafeVarargsPlugin.Enhance
559
        @SuppressWarnings("unchecked") // In absence of @SafeVarargs
560
        public final MemberSubstitution replaceWithChain(Substitution.Chain.Step.Factory<? super T>... step) {
561
            return replaceWithChain(Arrays.asList(step));
1✔
562
        }
563

564
        /**
565
         * Replaces the matched byte code elements with a chain of substitutions that can operate on the same values as the substituted element. This is a
566
         * shortcut for creating a substitution chain with a default assigner.
567
         *
568
         * @param steps The steps to apply for a substitution.
569
         * @return A member substitution that replaces any matched byte code element with the provided substitution chain.
570
         */
571
        public MemberSubstitution replaceWithChain(List<? extends Substitution.Chain.Step.Factory<? super T>> steps) {
572
            return replaceWith(Substitution.Chain.<T>withDefaultAssigner().executing(steps));
1✔
573
        }
574

575
        /**
576
         * Replaces any interaction with the supplied substitution.
577
         *
578
         * @param factory The substitution factory to use for creating the applied substitution.
579
         * @return A member substitution that replaces any matched byte code element with the supplied substitution.
580
         */
581
        public abstract MemberSubstitution replaceWith(Substitution.Factory<? super T> factory);
582

583
        /**
584
         * A member substitution for an invokedynamic instruction.
585
         */
586
        @HashCodeAndEqualsPlugin.Enhance
587
        public static class ForMatchedDynamicInvocation extends WithoutSpecification<Target.ForDynamicInvocation> {
588

589
            /**
590
             * A matcher for an invokedynamic bootstrap method.
591
             */
592
            private final ElementMatcher<? super JavaConstant.MethodHandle> handleMatcher;
593

594
            /**
595
             * A matcher for an invokedynamic instruction's name.
596
             */
597
            private final ElementMatcher.Junction<? super String> nameMatcher;
598

599
            /**
600
             * A matcher for an invokedynamic instruction's result type.
601
             */
602
            private final ElementMatcher.Junction<? super JavaConstant.MethodType> typeMatcher;
603

604
            /**
605
             * A matcher for an invokedynamic instruction's constant arguments.
606
             */
607
            private final ElementMatcher.Junction<? super List<? extends JavaConstant>> argumentsMatcher;
608

609
            /**
610
             * Creates a member substitution for an invokedynamic instruction.
611
             *
612
             * @param methodGraphCompiler The method graph compiler to use.
613
             * @param typePoolResolver    The type pool resolver to use.
614
             * @param strict              {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
615
             * @param failIfNoMatch       {@code true} if the instrumentation should fail if applied to a method without match.
616
             * @param replacementFactory  The replacement factory to use for creating substitutions.
617
             * @param handleMatcher       A matcher for an invokedynamic bootstrap method.
618
             * @param nameMatcher         A matcher for an invokedynamic instruction's name.
619
             * @param typeMatcher         A matcher for an invokedynamic instruction's result type.
620
             * @param argumentsMatcher    A matcher for an invokedynamic instruction's constant arguments.
621
             */
622
            protected ForMatchedDynamicInvocation(MethodGraph.Compiler methodGraphCompiler,
623
                                                  TypePoolResolver typePoolResolver,
624
                                                  boolean strict,
625
                                                  boolean failIfNoMatch,
626
                                                  Replacement.Factory replacementFactory,
627
                                                  ElementMatcher<? super JavaConstant.MethodHandle> handleMatcher,
628
                                                  ElementMatcher.Junction<? super String> nameMatcher,
629
                                                  ElementMatcher.Junction<? super JavaConstant.MethodType> typeMatcher,
630
                                                  ElementMatcher.Junction<? super List<? extends JavaConstant>> argumentsMatcher) {
631
                super(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory);
1✔
632
                this.handleMatcher = handleMatcher;
1✔
633
                this.nameMatcher = nameMatcher;
1✔
634
                this.typeMatcher = typeMatcher;
1✔
635
                this.argumentsMatcher = argumentsMatcher;
1✔
636
            }
1✔
637

638
            /**
639
             * Reduces matched invokedynamic instructions to such instructions that declare a name which is matched by the supplied matcher.
640
             *
641
             * @param nameMatcher A matcher for an invokedynamic instruction's name.
642
             * @return A member substitution for an invokedynamic instruction with a name that is matched by the given matcher.
643
             */
644
            public ForMatchedDynamicInvocation withName(ElementMatcher<? super String> nameMatcher) {
645
                return new ForMatchedDynamicInvocation(methodGraphCompiler,
1✔
646
                        typePoolResolver,
647
                        strict,
648
                        failIfNoMatch,
649
                        replacementFactory,
650
                        handleMatcher,
651
                        this.nameMatcher.<String>and(nameMatcher),
1✔
652
                        typeMatcher,
653
                        argumentsMatcher);
654
            }
655

656
            /**
657
             * Reduces matched invokedynamic instructions to such instructions that require a type which is matched by the supplied matcher.
658
             *
659
             * @param typeMatcher A matcher for an invokedynamic instruction's required type.
660
             * @return A member substitution for an invokedynamic instruction with a required type that is matched by the given matcher.
661
             */
662
            public ForMatchedDynamicInvocation withType(ElementMatcher<? super JavaConstant.MethodType> typeMatcher) {
663
                return new ForMatchedDynamicInvocation(methodGraphCompiler,
1✔
664
                        typePoolResolver,
665
                        strict,
666
                        failIfNoMatch,
667
                        replacementFactory,
668
                        handleMatcher,
669
                        nameMatcher,
670
                        this.typeMatcher.<JavaConstant.MethodType>and(typeMatcher),
1✔
671
                        argumentsMatcher);
672
            }
673

674
            /**
675
             * Reduces matched invokedynamic instructions to such instructions that is provided with constant arguments which are matched by the supplied matcher.
676
             *
677
             * @param argumentsMatcher A matcher for an invokedynamic instruction's constant arguments.
678
             * @return A member substitution for an invokedynamic instruction with constant arguments that are matched by the given matcher.
679
             */
680
            public ForMatchedDynamicInvocation withArguments(ElementMatcher<? super List<? extends JavaConstant>> argumentsMatcher) {
681
                return new ForMatchedDynamicInvocation(methodGraphCompiler,
1✔
682
                        typePoolResolver,
683
                        strict,
684
                        failIfNoMatch,
685
                        replacementFactory,
686
                        handleMatcher,
687
                        nameMatcher,
688
                        typeMatcher,
689
                        this.argumentsMatcher.<List<? extends JavaConstant>>and(argumentsMatcher));
1✔
690
            }
691

692
            @Override
693
            public MemberSubstitution replaceWith(Substitution.Factory<? super Target.ForDynamicInvocation> substitutionFactory) {
694
                return new MemberSubstitution(methodGraphCompiler,
1✔
695
                        typePoolResolver,
696
                        strict,
697
                        failIfNoMatch,
698
                        new Replacement.Factory.Compound(this.replacementFactory, new Replacement.ForDynamicInvocation.Factory(handleMatcher,
699
                                nameMatcher,
700
                                typeMatcher,
701
                                argumentsMatcher,
702
                                substitutionFactory)));
703
            }
704
        }
705

706
        /**
707
         * Describes a member substitution that requires a specification for how to replace a byte code element.
708
         */
709
        @HashCodeAndEqualsPlugin.Enhance
710
        protected static class ForMatchedByteCodeElement extends WithoutSpecification<Target.ForMember> {
711

712
            /**
713
             * A matcher for any byte code elements that should be substituted.
714
             */
715
            private final ElementMatcher<? super ByteCodeElement.Member> matcher;
716

717
            /**
718
             * Creates a new member substitution for a matched byte code element that requires a specification for how to perform a substitution.
719
             *
720
             * @param methodGraphCompiler The method graph compiler to use.
721
             * @param typePoolResolver    The type pool resolver to use.
722
             * @param strict              {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
723
             * @param failIfNoMatch       {@code true} if the instrumentation should fail if applied to a method without match.
724
             * @param replacementFactory  The replacement factory to use.
725
             * @param matcher             A matcher for any byte code elements that should be substituted.
726
             */
727
            protected ForMatchedByteCodeElement(MethodGraph.Compiler methodGraphCompiler,
728
                                                TypePoolResolver typePoolResolver,
729
                                                boolean strict,
730
                                                boolean failIfNoMatch,
731
                                                Replacement.Factory replacementFactory,
732
                                                ElementMatcher<? super ByteCodeElement.Member> matcher) {
733
                super(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory);
×
734
                this.matcher = matcher;
×
735
            }
×
736

737
            /**
738
             * {@inheritDoc}
739
             */
740
            public MemberSubstitution replaceWith(Substitution.Factory<? super Target.ForMember> substitutionFactory) {
741
                return new MemberSubstitution(methodGraphCompiler,
×
742
                        typePoolResolver,
743
                        strict,
744
                        failIfNoMatch,
745
                        new Replacement.Factory.Compound(this.replacementFactory, Replacement.ForElementMatchers.Factory.of(matcher, substitutionFactory)));
×
746
            }
747
        }
748

749
        /**
750
         * Describes a member substitution that requires a specification for how to replace a field.
751
         */
752
        @HashCodeAndEqualsPlugin.Enhance
753
        public static class ForMatchedField extends WithoutSpecification<Target.ForMember> {
754

755
            /**
756
             * A matcher for any field that should be substituted.
757
             */
758
            private final ElementMatcher<? super FieldDescription> matcher;
759

760
            /**
761
             * {@code true} if read access to a field should be substituted.
762
             */
763
            private final boolean matchRead;
764

765
            /**
766
             * {@code true} if write access to a field should be substituted.
767
             */
768
            private final boolean matchWrite;
769

770
            /**
771
             * Creates a new member substitution for a matched field that requires a specification for how to perform a substitution.
772
             *
773
             * @param methodGraphCompiler The method graph compiler to use.
774
             * @param typePoolResolver    The type pool resolver to use.
775
             * @param strict              {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
776
             * @param failIfNoMatch       {@code true} if the instrumentation should fail if applied to a method without match.
777
             * @param replacementFactory  The replacement factory to use.
778
             * @param matcher             A matcher for any field that should be substituted.
779
             */
780
            protected ForMatchedField(MethodGraph.Compiler methodGraphCompiler,
781
                                      TypePoolResolver typePoolResolver,
782
                                      boolean strict,
783
                                      boolean failIfNoMatch,
784
                                      Replacement.Factory replacementFactory,
785
                                      ElementMatcher<? super FieldDescription> matcher) {
786
                this(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory, matcher, true, true);
1✔
787
            }
1✔
788

789
            /**
790
             * Creates a new member substitution for a matched field that requires a specification for how to perform a substitution.
791
             *
792
             * @param methodGraphCompiler The method graph compiler to use.
793
             * @param typePoolResolver    The type pool resolver to use.
794
             * @param strict              {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
795
             * @param failIfNoMatch       {@code true} if the instrumentation should fail if applied to a method without match.
796
             * @param replacementFactory  The replacement factory to use.
797
             * @param matcher             A matcher for any field that should be substituted.
798
             * @param matchRead           {@code true} if read access to a field should be substituted.
799
             * @param matchWrite          {@code true} if write access to a field should be substituted.
800
             */
801
            protected ForMatchedField(MethodGraph.Compiler methodGraphCompiler,
802
                                      TypePoolResolver typePoolResolver,
803
                                      boolean strict,
804
                                      boolean failIfNoMatch,
805
                                      Replacement.Factory replacementFactory,
806
                                      ElementMatcher<? super FieldDescription> matcher,
807
                                      boolean matchRead,
808
                                      boolean matchWrite) {
809
                super(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory);
1✔
810
                this.matcher = matcher;
1✔
811
                this.matchRead = matchRead;
1✔
812
                this.matchWrite = matchWrite;
1✔
813
            }
1✔
814

815
            /**
816
             * When invoked, only read access of the previously matched field is substituted.
817
             *
818
             * @return This instance with the limitation that only read access to the matched field is substituted.
819
             */
820
            public WithoutSpecification<Target.ForMember> onRead() {
821
                return new ForMatchedField(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory, matcher, true, false);
1✔
822
            }
823

824
            /**
825
             * When invoked, only write access of the previously matched field is substituted.
826
             *
827
             * @return This instance with the limitation that only write access to the matched field is substituted.
828
             */
829
            public WithoutSpecification<Target.ForMember> onWrite() {
830
                return new ForMatchedField(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory, matcher, false, true);
1✔
831
            }
832

833
            /**
834
             * {@inheritDoc}
835
             */
836
            public MemberSubstitution replaceWith(Substitution.Factory<? super Target.ForMember> substitutionFactory) {
837
                return new MemberSubstitution(methodGraphCompiler,
1✔
838
                        typePoolResolver,
839
                        strict,
840
                        failIfNoMatch,
841
                        new Replacement.Factory.Compound(this.replacementFactory, Replacement.ForElementMatchers.Factory.ofField(matcher, matchRead, matchWrite, substitutionFactory)));
1✔
842
            }
843
        }
844

845
        /**
846
         * Describes a member substitution that requires a specification for how to replace a method or constructor.
847
         */
848
        @HashCodeAndEqualsPlugin.Enhance
849
        public static class ForMatchedMethod extends WithoutSpecification<Target.ForMember> {
850

851
            /**
852
             * A matcher for any method or constructor that should be substituted.
853
             */
854
            private final ElementMatcher<? super MethodDescription> matcher;
855

856
            /**
857
             * {@code true} if this specification includes virtual invocations.
858
             */
859
            private final boolean includeVirtualCalls;
860

861
            /**
862
             * {@code true} if this specification includes {@code super} invocations.
863
             */
864
            private final boolean includeSuperCalls;
865

866
            /**
867
             * Creates a new member substitution for a matched method that requires a specification for how to perform a substitution.
868
             *
869
             * @param methodGraphCompiler The method graph compiler to use.
870
             * @param typePoolResolver    The type pool resolver to use.
871
             * @param strict              {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
872
             * @param failIfNoMatch       {@code true} if the instrumentation should fail if applied to a method without match.
873
             * @param replacementFactory  The replacement factory to use.
874
             * @param matcher             A matcher for any method or constructor that should be substituted.
875
             */
876
            protected ForMatchedMethod(MethodGraph.Compiler methodGraphCompiler,
877
                                       TypePoolResolver typePoolResolver,
878
                                       boolean strict,
879
                                       boolean failIfNoMatch,
880
                                       Replacement.Factory replacementFactory,
881
                                       ElementMatcher<? super MethodDescription> matcher) {
882
                this(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory, matcher, true, true);
1✔
883
            }
1✔
884

885
            /**
886
             * Creates a new member substitution for a matched method that requires a specification for how to perform a substitution.
887
             *
888
             * @param methodGraphCompiler The method graph compiler to use.
889
             * @param typePoolResolver    The type pool resolver to use.
890
             * @param strict              {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
891
             * @param failIfNoMatch       {@code true} if the instrumentation should fail if applied to a method without match.
892
             * @param replacementFactory  The replacement factory to use.
893
             * @param matcher             A matcher for any method or constructor that should be substituted.
894
             * @param includeVirtualCalls {@code true} if this specification includes virtual invocations.
895
             * @param includeSuperCalls   {@code true} if this specification includes {@code super} invocations.
896
             */
897
            protected ForMatchedMethod(MethodGraph.Compiler methodGraphCompiler,
898
                                       TypePoolResolver typePoolResolver,
899
                                       boolean strict,
900
                                       boolean failIfNoMatch,
901
                                       Replacement.Factory replacementFactory,
902
                                       ElementMatcher<? super MethodDescription> matcher,
903
                                       boolean includeVirtualCalls,
904
                                       boolean includeSuperCalls) {
905
                super(methodGraphCompiler, typePoolResolver, strict, failIfNoMatch, replacementFactory);
1✔
906
                this.matcher = matcher;
1✔
907
                this.includeVirtualCalls = includeVirtualCalls;
1✔
908
                this.includeSuperCalls = includeSuperCalls;
1✔
909
            }
1✔
910

911
            /**
912
             * Limits the substituted method calls to method calls that invoke a method virtually (as opposed to a {@code super} invocation).
913
             *
914
             * @return This specification where only virtual methods are matched if they are not invoked as a virtual call.
915
             */
916
            public WithoutSpecification<Target.ForMember> onVirtualCall() {
917
                return new ForMatchedMethod(methodGraphCompiler,
1✔
918
                        typePoolResolver,
919
                        strict,
920
                        failIfNoMatch,
921
                        replacementFactory,
922
                        isVirtual().and(matcher),
1✔
923
                        true,
924
                        false);
925
            }
926

927
            /**
928
             * Limits the substituted method calls to method calls that invoke a method as a {@code super} call.
929
             *
930
             * @return This specification where only virtual methods are matched if they are not invoked as a super call.
931
             */
932
            public WithoutSpecification<Target.ForMember> onSuperCall() {
933
                return new ForMatchedMethod(methodGraphCompiler,
1✔
934
                        typePoolResolver,
935
                        strict,
936
                        failIfNoMatch,
937
                        replacementFactory,
938
                        isVirtual().and(matcher),
1✔
939
                        false,
940
                        true);
941
            }
942

943
            /**
944
             * {@inheritDoc}
945
             */
946
            public MemberSubstitution replaceWith(Substitution.Factory<? super Target.ForMember> substitutionFactory) {
947
                return new MemberSubstitution(methodGraphCompiler,
1✔
948
                        typePoolResolver,
949
                        strict,
950
                        failIfNoMatch,
951
                        new Replacement.Factory.Compound(this.replacementFactory, Replacement.ForElementMatchers.Factory.ofMethod(matcher, includeVirtualCalls, includeSuperCalls, substitutionFactory)));
1✔
952
            }
953
        }
954
    }
955

956
    /**
957
     * A type pool resolver is responsible for resolving a {@link TypePool} for locating substituted members.
958
     */
959
    public interface TypePoolResolver {
960

961
        /**
962
         * Resolves a type pool to use for locating substituted members.
963
         *
964
         * @param instrumentedType   The instrumented type.
965
         * @param instrumentedMethod The instrumented method.
966
         * @param typePool           The type pool implicit to the instrumentation.
967
         * @return The type pool to use.
968
         */
969
        TypePool resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool);
970

971
        /**
972
         * Returns the implicit type pool.
973
         */
974
        enum OfImplicitPool implements TypePoolResolver {
1✔
975

976
            /**
977
             * The singleton instance.
978
             */
979
            INSTANCE;
1✔
980

981
            /**
982
             * {@inheritDoc}
983
             */
984
            public TypePool resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
985
                return typePool;
1✔
986
            }
987
        }
988

989
        /**
990
         * A type pool resolver that returns a specific type pool.
991
         */
992
        @HashCodeAndEqualsPlugin.Enhance
993
        class ForExplicitPool implements TypePoolResolver {
994

995
            /**
996
             * The type pool to return.
997
             */
998
            private final TypePool typePool;
999

1000
            /**
1001
             * Creates a resolver for an explicit type pool.
1002
             *
1003
             * @param typePool The type pool to return.
1004
             */
1005
            public ForExplicitPool(TypePool typePool) {
×
1006
                this.typePool = typePool;
×
1007
            }
×
1008

1009
            /**
1010
             * {@inheritDoc}
1011
             */
1012
            public TypePool resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
1013
                return this.typePool;
×
1014
            }
1015
        }
1016

1017
        /**
1018
         * A type pool resolver that resolves the implicit pool but additionally checks another class file locator.
1019
         */
1020
        @HashCodeAndEqualsPlugin.Enhance
1021
        class ForClassFileLocator implements TypePoolResolver {
1022

1023
            /**
1024
             * The class file locator to use.
1025
             */
1026
            private final ClassFileLocator classFileLocator;
1027

1028
            /**
1029
             * The reader mode to apply.
1030
             */
1031
            private final TypePool.Default.ReaderMode readerMode;
1032

1033
            /**
1034
             * Creates a new type pool resolver for a class file locator as a supplement of the implicit type pool.
1035
             *
1036
             * @param classFileLocator The class file locator to use.
1037
             */
1038
            public ForClassFileLocator(ClassFileLocator classFileLocator) {
1039
                this(classFileLocator, TypePool.Default.ReaderMode.FAST);
×
1040
            }
×
1041

1042
            /**
1043
             * Creates a new type pool resolver for a class file locator as a supplement of the implicit type pool.
1044
             *
1045
             * @param classFileLocator The class file locator to use.
1046
             * @param readerMode       The reader mode to apply.
1047
             */
1048
            public ForClassFileLocator(ClassFileLocator classFileLocator, TypePool.Default.ReaderMode readerMode) {
×
1049
                this.classFileLocator = classFileLocator;
×
1050
                this.readerMode = readerMode;
×
1051
            }
×
1052

1053
            /**
1054
             * Creates a new type pool resolver that supplements the supplied class loader to the implicit type pool.
1055
             *
1056
             * @param classLoader The class loader to use as a supplement which can be {@code null} to represent the bootstrap loader.
1057
             * @return An appropriate type pool resolver.
1058
             */
1059
            public static TypePoolResolver of(@MaybeNull ClassLoader classLoader) {
1060
                return new ForClassFileLocator(ClassFileLocator.ForClassLoader.of(classLoader));
×
1061
            }
1062

1063
            /**
1064
             * {@inheritDoc}
1065
             */
1066
            public TypePool resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
1067
                return new TypePool.Default(new TypePool.CacheProvider.Simple(), classFileLocator, readerMode, typePool);
×
1068
            }
1069
        }
1070
    }
1071

1072
    /**
1073
     * Representation of a substitution target within a method body.
1074
     */
1075
    public interface Target {
1076

1077
        /**
1078
         * Returns the (internal) name of the target.
1079
         *
1080
         * @return The name of the target.
1081
         */
1082
        String getName();
1083

1084
        /**
1085
         * Determines if the target is dispatched statically.
1086
         *
1087
         * @return {@code true} if the target is dispatched statically.
1088
         */
1089
        boolean isStaticDispatch();
1090

1091
        /**
1092
         * Represents a member that is the target of a substitution.
1093
         */
1094
        class ForMember implements Target {
1095

1096
            /**
1097
             * The actual (sub-)type on which the member is accessed.
1098
             */
1099
            private final TypeDescription receiverType;
1100

1101
            /**
1102
             * The member that is being accessed.
1103
             */
1104
            private final ByteCodeElement.Member member;
1105

1106
            /**
1107
             * Creates a new target for a member that is being accessed.
1108
             *
1109
             * @param receiverType The actual (sub-)type on which the member is accessed.
1110
             * @param member       The member that is being accessed.
1111
             */
1112
            protected ForMember(TypeDescription receiverType, ByteCodeElement.Member member) {
1✔
1113
                this.receiverType = receiverType;
1✔
1114
                this.member = member;
1✔
1115
            }
1✔
1116

1117
            /**
1118
             * {@inheritDoc}
1119
             */
1120
            public String getName() {
1121
                return member.getInternalName();
×
1122
            }
1123

1124
            /**
1125
             * {@inheritDoc}
1126
             */
1127
            public boolean isStaticDispatch() {
1128
                return member.isStatic()
1✔
1129
                        || member instanceof MethodDescription
1130
                        && ((MethodDescription) member).isConstructor();
1✔
1131
            }
1132

1133
            /**
1134
             * Returns the actual (sub-)type on which the member is accessed.
1135
             *
1136
             * @return The actual (sub-)type on which the member is accessed.
1137
             */
1138
            public TypeDescription getReceiverType() {
1139
                return receiverType;
×
1140
            }
1141

1142
            /**
1143
             * Returns the member that is being accessed.
1144
             *
1145
             * @return The member that is being accessed.
1146
             */
1147
            public ByteCodeElement.Member getMember() {
1148
                return member;
1✔
1149
            }
1150
        }
1151

1152
        /**
1153
         * Represents an invokedynamic instruction that is the target of a substitution.
1154
         */
1155
        class ForDynamicInvocation implements Target {
1156

1157
            /**
1158
             * The requested type of the target for the invokedynamic instruction.
1159
             */
1160
            private final JavaConstant.MethodType methodType;
1161

1162
            /**
1163
             * The name that is expected for the bound target.
1164
             */
1165
            private final String name;
1166

1167
            /**
1168
             * The constant arguments that are provided to the invokedynamic instruction.
1169
             */
1170
            private final List<? extends JavaConstant> arguments;
1171

1172
            /**
1173
             * Creates a new target for an invokedynamic instruction.
1174
             *
1175
             * @param methodType The requested type of the target for the invokedynamic instruction.
1176
             * @param name       The name that is expected for the bound target.
1177
             * @param arguments  The constant arguments that are provided to the invokedynamic instruction.
1178
             */
1179
            protected ForDynamicInvocation(JavaConstant.MethodType methodType, String name, List<? extends JavaConstant> arguments) {
1✔
1180
                this.methodType = methodType;
1✔
1181
                this.name = name;
1✔
1182
                this.arguments = arguments;
1✔
1183
            }
1✔
1184

1185
            /**
1186
             * {@inheritDoc}
1187
             */
1188
            public boolean isStaticDispatch() {
1189
                return true;
×
1190
            }
1191

1192
            /**
1193
             * Returns the requested type of the target for the invokedynamic instruction.
1194
             *
1195
             * @return The requested type of the target for the invokedynamic instruction.
1196
             */
1197
            public JavaConstant.MethodType getMethodType() {
1198
                return methodType;
1✔
1199
            }
1200

1201
            /**
1202
             * {@inheritDoc}
1203
             */
1204
            public String getName() {
1205
                return name;
×
1206
            }
1207

1208
            /**
1209
             * Returns the constant arguments that are provided to the invokedynamic instruction.
1210
             *
1211
             * @return The constant arguments that are provided to the invokedynamic instruction.
1212
             */
1213
            public List<? extends JavaConstant> getArguments() {
1214
                return arguments;
×
1215
            }
1216
        }
1217
    }
1218

1219
    /**
1220
     * A substitution replaces or enhances an interaction with a field or method within an instrumented method.
1221
     *
1222
     * @param <T> The type of the matched target.
1223
     */
1224
    public interface Substitution<T extends Target> {
1225

1226
        /**
1227
         * Resolves this substitution into a stack manipulation.
1228
         *
1229
         * @param target            The targeted member that is substituted.
1230
         * @param parameters        All parameters that serve as input to this access.
1231
         * @param result            The result that is expected from the interaction or {@code void} if no result is expected.
1232
         * @param methodHandle      A method handle describing the substituted expression.
1233
         * @param stackManipulation The original byte code expression that is being executed.
1234
         * @param freeOffset        The first free offset of the local variable array that can be used for storing values.
1235
         * @return A stack manipulation that represents the access.
1236
         */
1237
        StackManipulation resolve(T target,
1238
                                  TypeList.Generic parameters,
1239
                                  TypeDescription.Generic result,
1240
                                  JavaConstant.MethodHandle methodHandle,
1241
                                  StackManipulation stackManipulation,
1242
                                  int freeOffset);
1243

1244
        /**
1245
         * A factory for creating a substitution for an instrumented method.
1246
         *
1247
         * @param <S> The type of the matched target.
1248
         */
1249
        interface Factory<S extends Target> {
1250

1251
            /**
1252
             * Creates a substitution for an instrumented method.
1253
             *
1254
             * @param instrumentedType   The instrumented type.
1255
             * @param instrumentedMethod The instrumented method.
1256
             * @param typePool           The type pool being used.
1257
             * @return The substitution to apply within the instrumented method.
1258
             */
1259
            Substitution<? super S> make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool);
1260
        }
1261

1262
        /**
1263
         * A substitution that drops any field or method access and returns the expected return
1264
         * type's default value, i.e {@code null} or zero for primitive types.
1265
         */
1266
        enum Stubbing implements Substitution<Target>, Factory<Target> {
1✔
1267

1268
            /**
1269
             * The singleton instance.
1270
             */
1271
            INSTANCE;
1✔
1272

1273
            /**
1274
             * {@inheritDoc}
1275
             */
1276
            public Substitution<Target> make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
1277
                return this;
1✔
1278
            }
1279

1280
            /**
1281
             * {@inheritDoc}
1282
             */
1283
            public StackManipulation resolve(Target target,
1284
                                             TypeList.Generic parameters,
1285
                                             TypeDescription.Generic result,
1286
                                             JavaConstant.MethodHandle methodHandle,
1287
                                             StackManipulation stackManipulation,
1288
                                             int freeOffset) {
1289
                List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(parameters.size());
1✔
1290
                for (int index = parameters.size() - 1; index >= 0; index--) {
1✔
1291
                    stackManipulations.add(Removal.of(parameters.get(index)));
1✔
1292
                }
1293
                return new StackManipulation.Compound(CompoundList.of(stackManipulations, DefaultValue.of(result.asErasure())));
1✔
1294
            }
1295
        }
1296

1297
        /**
1298
         * A substitution that loads a fixed value.
1299
         */
1300
        @HashCodeAndEqualsPlugin.Enhance
1301
        class ForValue implements Substitution<Target>, Factory<Target> {
1302

1303
            /**
1304
             * The stack manipulation to load the value that represents the substitution.
1305
             */
1306
            private final StackManipulation stackManipulation;
1307

1308
            /**
1309
             * The type of the represented stack manipulation.
1310
             */
1311
            private final TypeDescription.Generic typeDescription;
1312

1313
            /**
1314
             * Creates a new substitution for loading a constant value.
1315
             *
1316
             * @param stackManipulation The stack manipulation to load the value that represents the substitution.
1317
             * @param typeDescription   The type of the represented stack manipulation.
1318
             */
1319
            public ForValue(StackManipulation stackManipulation, TypeDescription.Generic typeDescription) {
1✔
1320
                this.stackManipulation = stackManipulation;
1✔
1321
                this.typeDescription = typeDescription;
1✔
1322
            }
1✔
1323

1324
            /**
1325
             * {@inheritDoc}
1326
             */
1327
            public Substitution<Target> make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
1328
                return this;
1✔
1329
            }
1330

1331
            /**
1332
             * {@inheritDoc}
1333
             */
1334
            public StackManipulation resolve(Target target,
1335
                                             TypeList.Generic parameters,
1336
                                             TypeDescription.Generic result,
1337
                                             JavaConstant.MethodHandle methodHandle,
1338
                                             StackManipulation stackManipulation,
1339
                                             int freeOffset) {
1340
                List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(parameters.size());
1✔
1341
                for (int index = parameters.size() - 1; index >= 0; index--) {
1✔
1342
                    stackManipulations.add(Removal.of(parameters.get(index)));
1✔
1343
                }
1344
                if (!typeDescription.asErasure().isAssignableTo(result.asErasure())) {
1✔
1345
                    throw new IllegalStateException("Cannot assign " + typeDescription + " to " + result);
×
1346
                }
1347
                return new StackManipulation.Compound(CompoundList.of(stackManipulations, this.stackManipulation));
1✔
1348
            }
1349
        }
1350

1351
        /**
1352
         * A substitution with a field access.
1353
         */
1354
        @HashCodeAndEqualsPlugin.Enhance
1355
        class ForFieldAccess implements Substitution<Target> {
1356

1357
            /**
1358
             * The instrumented type.
1359
             */
1360
            private final TypeDescription instrumentedType;
1361

1362
            /**
1363
             * A resolver to locate the field to access.
1364
             */
1365
            private final FieldResolver fieldResolver;
1366

1367
            /**
1368
             * Creates a new substitution with a field access.
1369
             *
1370
             * @param instrumentedType The instrumented type.
1371
             * @param fieldResolver    A resolver to locate the field to access.
1372
             */
1373
            public ForFieldAccess(TypeDescription instrumentedType, FieldResolver fieldResolver) {
1✔
1374
                this.instrumentedType = instrumentedType;
1✔
1375
                this.fieldResolver = fieldResolver;
1✔
1376
            }
1✔
1377

1378
            /**
1379
             * {@inheritDoc}
1380
             */
1381
            @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
1382
            public StackManipulation resolve(Target target,
1383
                                             TypeList.Generic parameters,
1384
                                             TypeDescription.Generic result,
1385
                                             JavaConstant.MethodHandle methodHandle,
1386
                                             StackManipulation stackManipulation,
1387
                                             int freeOffset) {
1388
                FieldDescription fieldDescription = fieldResolver.resolve(target, parameters, result);
1✔
1389
                if (!fieldDescription.isAccessibleTo(instrumentedType)) {
1✔
1390
                    throw new IllegalStateException(instrumentedType + " cannot access " + fieldDescription);
1✔
1391
                } else if (result.represents(void.class)) {
1✔
1392
                    if (parameters.size() != (fieldDescription.isStatic() ? 1 : 2)) {
1✔
1393
                        throw new IllegalStateException("Cannot set " + fieldDescription + " with " + parameters);
1✔
1394
                    } else if (!fieldDescription.isStatic() && !parameters.get(0).asErasure().isAssignableTo(fieldDescription.getDeclaringType().asErasure())) {
1✔
1395
                        throw new IllegalStateException("Cannot set " + fieldDescription + " on " + parameters.get(0));
×
1396
                    } else if (!parameters.get(fieldDescription.isStatic() ? 0 : 1).asErasure().isAssignableTo(fieldDescription.getType().asErasure())) {
1✔
1397
                        throw new IllegalStateException("Cannot set " + fieldDescription + " to " + parameters.get(fieldDescription.isStatic() ? 0 : 1));
1✔
1398
                    }
1399
                    return FieldAccess.forField(fieldDescription).write();
1✔
1400
                } else {
1401
                    if (parameters.size() != (fieldDescription.isStatic() ? 0 : 1)) {
1✔
1402
                        throw new IllegalStateException("Cannot set " + fieldDescription + " with " + parameters);
1✔
1403
                    } else if (!fieldDescription.isStatic() && !parameters.get(0).asErasure().isAssignableTo(fieldDescription.getDeclaringType().asErasure())) {
1✔
1404
                        throw new IllegalStateException("Cannot get " + fieldDescription + " on " + parameters.get(0));
×
1405
                    } else if (!fieldDescription.getType().asErasure().isAssignableTo(result.asErasure())) {
1✔
1406
                        throw new IllegalStateException("Cannot get " + fieldDescription + " as " + result);
1✔
1407
                    }
1408
                    return FieldAccess.forField(fieldDescription).read();
1✔
1409
                }
1410
            }
1411

1412
            /**
1413
             * A method resolver for locating a field for a substitute.
1414
             */
1415
            public interface FieldResolver {
1416

1417
                /**
1418
                 * Resolves the field to substitute with.
1419
                 *
1420
                 * @param target     The target member of invokedynamic invocation.
1421
                 * @param parameters All parameters that serve as input to this access.
1422
                 * @param result     The result that is expected from the interaction or {@code void} if no result is expected.
1423
                 * @return The field to substitute with.
1424
                 */
1425
                FieldDescription resolve(Target target, TypeList.Generic parameters, TypeDescription.Generic result);
1426

1427
                /**
1428
                 * A simple field resolver that returns a specific field.
1429
                 */
1430
                @HashCodeAndEqualsPlugin.Enhance
1431
                class Simple implements FieldResolver {
1432

1433
                    /**
1434
                     * The field to access.
1435
                     */
1436
                    private final FieldDescription fieldDescription;
1437

1438
                    /**
1439
                     * Creates a simple field resolver.
1440
                     *
1441
                     * @param fieldDescription The field to access.
1442
                     */
1443
                    public Simple(FieldDescription fieldDescription) {
1✔
1444
                        this.fieldDescription = fieldDescription;
1✔
1445
                    }
1✔
1446

1447
                    /**
1448
                     * {@inheritDoc}
1449
                     */
1450
                    public FieldDescription resolve(Target target, TypeList.Generic parameters, TypeDescription.Generic result) {
1451
                        return fieldDescription;
1✔
1452
                    }
1453
                }
1454

1455
                /**
1456
                 * A field matcher that resolves a non-static field on the first parameter type of the substituted member usage.
1457
                 */
1458
                @HashCodeAndEqualsPlugin.Enhance
1459
                class ForElementMatcher implements FieldResolver {
1460

1461
                    /**
1462
                     * The instrumented type.
1463
                     */
1464
                    private final TypeDescription instrumentedType;
1465

1466
                    /**
1467
                     * The matcher to use for locating the field to substitute with.
1468
                     */
1469
                    private final ElementMatcher<? super FieldDescription> matcher;
1470

1471
                    /**
1472
                     * Creates a new field resolver that locates a field on the receiver type using a matcher.
1473
                     *
1474
                     * @param instrumentedType The instrumented type.
1475
                     * @param matcher          The matcher to use for locating the field to substitute with.
1476
                     */
1477
                    protected ForElementMatcher(TypeDescription instrumentedType, ElementMatcher<? super FieldDescription> matcher) {
1✔
1478
                        this.instrumentedType = instrumentedType;
1✔
1479
                        this.matcher = matcher;
1✔
1480
                    }
1✔
1481

1482
                    /**
1483
                     * {@inheritDoc}
1484
                     */
1485
                    public FieldDescription resolve(Target target, TypeList.Generic parameters, TypeDescription.Generic result) {
1486
                        if (parameters.isEmpty()) {
1✔
1487
                            throw new IllegalStateException("Cannot substitute parameterless instruction with " + parameters);
1✔
1488
                        } else if (parameters.get(0).isPrimitive() || parameters.get(0).isArray()) {
1✔
1489
                            throw new IllegalStateException("Cannot access field on primitive or array type for " + parameters.get(0));
1✔
1490
                        }
1491
                        TypeDefinition current = parameters.get(0).accept(new TypeDescription.Generic.Visitor.Substitutor.ForReplacement(instrumentedType));
1✔
1492
                        do {
1493
                            FieldList<?> fields = current.getDeclaredFields().filter(not(isStatic()).<FieldDescription>and(isVisibleTo(instrumentedType)).and(matcher));
1✔
1494
                            if (fields.size() == 1) {
1✔
1495
                                return fields.getOnly();
1✔
1496
                            } else if (fields.size() > 1) {
1✔
1497
                                throw new IllegalStateException("Ambiguous field location of " + fields);
×
1498
                            }
1499
                            current = current.getSuperClass();
1✔
1500
                        } while (current != null);
1✔
1501
                        throw new IllegalStateException("Cannot locate field matching " + matcher + " on " + target);
1✔
1502
                    }
1503
                }
1504
            }
1505

1506
            /**
1507
             * A factory for a substitution that substitutes with a given field.
1508
             */
1509
            @HashCodeAndEqualsPlugin.Enhance
1510
            public static class OfGivenField implements Factory<Target> {
1511

1512
                /**
1513
                 * The field to substitute with.
1514
                 */
1515
                private final FieldDescription fieldDescription;
1516

1517
                /**
1518
                 * Creates a new factory that substitues with a given field.
1519
                 *
1520
                 * @param fieldDescription The field to substitute with.
1521
                 */
1522
                public OfGivenField(FieldDescription fieldDescription) {
1✔
1523
                    this.fieldDescription = fieldDescription;
1✔
1524
                }
1✔
1525

1526
                /**
1527
                 * {@inheritDoc}
1528
                 */
1529
                public Substitution<Target> make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
1530
                    return new ForFieldAccess(instrumentedType, new FieldResolver.Simple(fieldDescription));
1✔
1531
                }
1532
            }
1533

1534
            /**
1535
             * A factory for a substitution that locates a field on the receiver type using a matcher.
1536
             */
1537
            @HashCodeAndEqualsPlugin.Enhance
1538
            public static class OfMatchedField implements Factory<Target> {
1539

1540
                /**
1541
                 * The matcher to apply.
1542
                 */
1543
                private final ElementMatcher<? super FieldDescription> matcher;
1544

1545
                /**
1546
                 * Creates a new substitution factory that locates a field by applying a matcher on the receiver type.
1547
                 *
1548
                 * @param matcher The matcher to apply.
1549
                 */
1550
                public OfMatchedField(ElementMatcher<? super FieldDescription> matcher) {
1✔
1551
                    this.matcher = matcher;
1✔
1552
                }
1✔
1553

1554
                /**
1555
                 * {@inheritDoc}
1556
                 */
1557
                public Substitution<Target> make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
1558
                    return new ForFieldAccess(instrumentedType, new FieldResolver.ForElementMatcher(instrumentedType, matcher));
1✔
1559
                }
1560
            }
1561
        }
1562

1563
        /**
1564
         * A substitution with a method invocation.
1565
         */
1566
        @HashCodeAndEqualsPlugin.Enhance
1567
        class ForMethodInvocation implements Substitution<Target> {
1568

1569
            /**
1570
             * The instrumented type.
1571
             */
1572
            private final TypeDescription instrumentedType;
1573

1574
            /**
1575
             * The method resolver to use.
1576
             */
1577
            private final MethodResolver methodResolver;
1578

1579
            /**
1580
             * Creates a new method-resolving substitution.
1581
             *
1582
             * @param instrumentedType The instrumented type.
1583
             * @param methodResolver   The method resolver to use.
1584
             */
1585
            public ForMethodInvocation(TypeDescription instrumentedType, MethodResolver methodResolver) {
1✔
1586
                this.instrumentedType = instrumentedType;
1✔
1587
                this.methodResolver = methodResolver;
1✔
1588
            }
1✔
1589

1590
            /**
1591
             * {@inheritDoc}
1592
             */
1593
            public StackManipulation resolve(Target target,
1594
                                             TypeList.Generic parameters,
1595
                                             TypeDescription.Generic result,
1596
                                             JavaConstant.MethodHandle methodHandle,
1597
                                             StackManipulation stackManipulation,
1598
                                             int freeOffset) {
1599
                MethodDescription methodDescription = methodResolver.resolve(target, parameters, result);
1✔
1600
                if (!methodDescription.isAccessibleTo(instrumentedType)) {
1✔
1601
                    throw new IllegalStateException(instrumentedType + " cannot access " + methodDescription);
1✔
1602
                }
1603
                TypeList.Generic mapped = methodDescription.isStatic()
1✔
1604
                        ? methodDescription.getParameters().asTypeList()
1✔
1605
                        : new TypeList.Generic.Explicit(CompoundList.of(methodDescription.getDeclaringType(), methodDescription.getParameters().asTypeList()));
1✔
1606
                if (!methodDescription.getReturnType().asErasure().isAssignableTo(result.asErasure())) {
1✔
1607
                    throw new IllegalStateException("Cannot assign return value of " + methodDescription + " to " + result);
1✔
1608
                } else if (mapped.size() != parameters.size()) {
1✔
1609
                    throw new IllegalStateException("Cannot invoke " + methodDescription + " on " + parameters.size() + " parameters");
1✔
1610
                }
1611
                for (int index = 0; index < mapped.size(); index++) {
1✔
1612
                    if (!parameters.get(index).asErasure().isAssignableTo(mapped.get(index).asErasure())) {
1✔
1613
                        throw new IllegalStateException("Cannot invoke " + methodDescription + " on parameter " + index + " of type " + parameters.get(index));
1✔
1614
                    }
1615
                }
1616
                return methodDescription.isVirtual() ? MethodInvocation.invoke(methodDescription).virtual(mapped.get(THIS_REFERENCE).asErasure()) : MethodInvocation.invoke(methodDescription);
1✔
1617
            }
1618

1619
            /**
1620
             * A method resolver for locating a method for a substitute.
1621
             */
1622
            public interface MethodResolver {
1623

1624
                /**
1625
                 * Resolves the method to substitute with.
1626
                 *
1627
                 * @param target     The target member of invokedynamic invocation.
1628
                 * @param parameters All parameters that serve as input to this access.
1629
                 * @param result     The result that is expected from the interaction or {@code void} if no result is expected.
1630
                 * @return The field to substitute with.
1631
                 */
1632
                MethodDescription resolve(Target target, TypeList.Generic parameters, TypeDescription.Generic result);
1633

1634
                /**
1635
                 * A simple method resolver that returns a given method.
1636
                 */
1637
                @HashCodeAndEqualsPlugin.Enhance
1638
                class Simple implements MethodResolver {
1639

1640
                    /**
1641
                     * The method to substitute with.
1642
                     */
1643
                    private final MethodDescription methodDescription;
1644

1645
                    /**
1646
                     * Creates a new simple method resolver.
1647
                     *
1648
                     * @param methodDescription The method to substitute with.
1649
                     */
1650
                    public Simple(MethodDescription methodDescription) {
1✔
1651
                        this.methodDescription = methodDescription;
1✔
1652
                    }
1✔
1653

1654
                    /**
1655
                     * {@inheritDoc}
1656
                     */
1657
                    public MethodDescription resolve(Target target, TypeList.Generic parameters, TypeDescription.Generic result) {
1658
                        return methodDescription;
1✔
1659
                    }
1660
                }
1661

1662
                /**
1663
                 * A method resolver that locates a non-static method by locating it from the receiver type.
1664
                 */
1665
                @HashCodeAndEqualsPlugin.Enhance
1666
                class Matching implements MethodResolver {
1667

1668
                    /**
1669
                     * The instrumented type.
1670
                     */
1671
                    private final TypeDescription instrumentedType;
1672

1673
                    /**
1674
                     * The method graph compiler to use.
1675
                     */
1676
                    private final MethodGraph.Compiler methodGraphCompiler;
1677

1678
                    /**
1679
                     * The matcher to use for locating the method to substitute with.
1680
                     */
1681
                    private final ElementMatcher<? super MethodDescription> matcher;
1682

1683
                    /**
1684
                     * Creates a new matching method resolver.
1685
                     *
1686
                     * @param instrumentedType    The instrumented type.
1687
                     * @param methodGraphCompiler The method graph compiler to use.
1688
                     * @param matcher             The matcher to use for locating the method to substitute with.
1689
                     */
1690
                    public Matching(TypeDescription instrumentedType, MethodGraph.Compiler methodGraphCompiler, ElementMatcher<? super MethodDescription> matcher) {
1✔
1691
                        this.instrumentedType = instrumentedType;
1✔
1692
                        this.methodGraphCompiler = methodGraphCompiler;
1✔
1693
                        this.matcher = matcher;
1✔
1694
                    }
1✔
1695

1696
                    /**
1697
                     * {@inheritDoc}
1698
                     */
1699
                    public MethodDescription resolve(Target target, TypeList.Generic parameters, TypeDescription.Generic result) {
1700
                        if (parameters.isEmpty()) {
1✔
1701
                            throw new IllegalStateException("Cannot substitute parameterless instruction with " + parameters);
1✔
1702
                        } else if (parameters.get(0).isPrimitive() || parameters.get(0).isArray()) {
1✔
1703
                            throw new IllegalStateException("Cannot invoke method on primitive or array type for " + parameters.get(0));
1✔
1704
                        }
1705
                        TypeDefinition typeDefinition = parameters.get(0).accept(new TypeDescription.Generic.Visitor.Substitutor.ForReplacement(instrumentedType));
1✔
1706
                        List<MethodDescription> candidates = CompoundList.<MethodDescription>of(methodGraphCompiler.compile(typeDefinition, instrumentedType).listNodes()
1✔
1707
                                .asMethodList()
1✔
1708
                                .filter(matcher), typeDefinition.getDeclaredMethods().filter(isPrivate().<MethodDescription>and(isVisibleTo(instrumentedType)).and(matcher)));
1✔
1709
                        if (candidates.size() == 1) {
1✔
1710
                            return candidates.get(0);
1✔
1711
                        } else {
1712
                            throw new IllegalStateException("Not exactly one method that matches " + matcher + ": " + candidates);
1✔
1713
                        }
1714
                    }
1715
                }
1716
            }
1717

1718
            /**
1719
             * A factory for a substitution that invokes the instrumented method.
1720
             */
1721
            enum OfInstrumentedMethod implements Factory<Target> {
1✔
1722

1723
                /**
1724
                 * The singleton instance.
1725
                 */
1726
                INSTANCE;
1✔
1727

1728
                /**
1729
                 * {@inheritDoc}
1730
                 */
1731
                public Substitution<Target> make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
1732
                    return new ForMethodInvocation(instrumentedType, new MethodResolver.Simple(instrumentedMethod));
1✔
1733
                }
1734
            }
1735

1736
            /**
1737
             * A factory for a substitution that invokes a given method.
1738
             */
1739
            @HashCodeAndEqualsPlugin.Enhance
1740
            public static class OfGivenMethod implements Factory<Target> {
1741

1742
                /**
1743
                 * The method to invoke.
1744
                 */
1745
                private final MethodDescription methodDescription;
1746

1747
                /**
1748
                 * Creates a new factory for a substitution that invokes a given method.
1749
                 *
1750
                 * @param methodDescription The method to invoke.
1751
                 */
1752
                public OfGivenMethod(MethodDescription methodDescription) {
1✔
1753
                    this.methodDescription = methodDescription;
1✔
1754
                }
1✔
1755

1756
                /**
1757
                 * {@inheritDoc}
1758
                 */
1759
                public Substitution<Target> make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
1760
                    return new ForMethodInvocation(instrumentedType, new MethodResolver.Simple(methodDescription));
1✔
1761
                }
1762
            }
1763

1764
            /**
1765
             * A factory for a substitution that locates a method on the receiver type using a matcher.
1766
             */
1767
            @HashCodeAndEqualsPlugin.Enhance
1768
            public static class OfMatchedMethod implements Factory<Target> {
1769

1770
                /**
1771
                 * The matcher for locating the method to substitute with.
1772
                 */
1773
                private final ElementMatcher<? super MethodDescription> matcher;
1774

1775
                /**
1776
                 * The method graph compiler to use.
1777
                 */
1778
                private final MethodGraph.Compiler methodGraphCompiler;
1779

1780
                /**
1781
                 * Creates a factory for a substitution that locates a method on the receiver type.
1782
                 *
1783
                 * @param matcher             The matcher for locating the method to substitute with.
1784
                 * @param methodGraphCompiler The method graph compiler to use.
1785
                 */
1786
                public OfMatchedMethod(ElementMatcher<? super MethodDescription> matcher, MethodGraph.Compiler methodGraphCompiler) {
1✔
1787
                    this.matcher = matcher;
1✔
1788
                    this.methodGraphCompiler = methodGraphCompiler;
1✔
1789
                }
1✔
1790

1791
                /**
1792
                 * {@inheritDoc}
1793
                 */
1794
                public Substitution<Target> make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
1795
                    return new ForMethodInvocation(instrumentedType, new MethodResolver.Matching(instrumentedType, methodGraphCompiler, matcher));
1✔
1796
                }
1797
            }
1798
        }
1799

1800
        /**
1801
         * A substitution chain allows for chaining multiple substitution steps for a byte code element being replaced.
1802
         *
1803
         * @param <S> The type of the matched target.
1804
         */
1805
        @HashCodeAndEqualsPlugin.Enhance
1806
        class Chain<S extends Target> implements Substitution<S> {
1807

1808
            /**
1809
             * The assigner to use.
1810
             */
1811
            private final Assigner assigner;
1812

1813
            /**
1814
             * The typing of the assignment to use.
1815
             */
1816
            private final Assigner.Typing typing;
1817

1818
            /**
1819
             * The substitution steps to apply.
1820
             */
1821
            private final List<Step<? super S>> steps;
1822

1823
            /**
1824
             * Creates a new substitution chain.
1825
             *
1826
             * @param assigner The assigner to use.
1827
             * @param typing   The typing of the assignment to use.
1828
             * @param steps    The substitution steps to apply.
1829
             */
1830
            protected Chain(Assigner assigner, Assigner.Typing typing, List<Step<? super S>> steps) {
1✔
1831
                this.assigner = assigner;
1✔
1832
                this.typing = typing;
1✔
1833
                this.steps = steps;
1✔
1834
            }
1✔
1835

1836
            /**
1837
             * Creates a new substitution chain that uses a default assigner and static typing.
1838
             *
1839
             * @param <U> The type of the matched target.
1840
             * @return A new substitution chain.
1841
             */
1842
            public static <U extends Target> Chain.Factory<U> withDefaultAssigner() {
1843
                return with(Assigner.DEFAULT, Assigner.Typing.STATIC);
1✔
1844
            }
1845

1846
            /**
1847
             * Creates a new substitution chain.
1848
             *
1849
             * @param assigner The assigner to use.
1850
             * @param typing   The typing of the assignment to use.
1851
             * @param <U>      The type of the matched target.
1852
             * @return A new substitution chain.
1853
             */
1854
            public static <U extends Target> Chain.Factory<U> with(Assigner assigner, Assigner.Typing typing) {
1855
                return new Chain.Factory<U>(assigner, typing, Collections.<Step.Factory<? super U>>emptyList());
1✔
1856
            }
1857

1858
            /**
1859
             * {@inheritDoc}
1860
             */
1861
            public StackManipulation resolve(S target,
1862
                                             TypeList.Generic parameters,
1863
                                             TypeDescription.Generic result,
1864
                                             JavaConstant.MethodHandle methodHandle,
1865
                                             StackManipulation stackManipulation,
1866
                                             int freeOffset) {
1867
                List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(1
1✔
1868
                        + parameters.size() + steps.size() * 2
1✔
1869
                        + (result.represents(void.class) ? 0 : 2));
1✔
1870
                Map<Integer, Integer> offsets = new HashMap<Integer, Integer>();
1✔
1871
                for (int index = parameters.size() - 1; index >= 0; index--) {
1✔
1872
                    stackManipulations.add(MethodVariableAccess.of(parameters.get(index)).storeAt(freeOffset));
1✔
1873
                    offsets.put(index, freeOffset);
1✔
1874
                    freeOffset += parameters.get(index).getStackSize().getSize();
1✔
1875
                }
1876
                stackManipulations.add(DefaultValue.of(result));
1✔
1877
                TypeDescription.Generic current = result;
1✔
1878
                for (Step<? super S> step : steps) {
1✔
1879
                    Step.Resolution resolution = step.resolve(target,
1✔
1880
                            parameters,
1881
                            result,
1882
                            methodHandle,
1883
                            stackManipulation,
1884
                            current,
1885
                            offsets,
1886
                            freeOffset);
1887
                    stackManipulations.add(resolution.getStackManipulation());
1✔
1888
                    current = resolution.getResultType();
1✔
1889
                }
1✔
1890
                StackManipulation assignment = assigner.assign(current, result, typing);
1✔
1891
                if (!assignment.isValid()) {
1✔
1892
                    throw new IllegalStateException("Failed to assign " + current + " to " + result);
×
1893
                }
1894
                stackManipulations.add(assignment);
1✔
1895
                return new StackManipulation.Compound(stackManipulations);
1✔
1896
            }
1897

1898
            /**
1899
             * Represents a step of a substitution chain.
1900
             *
1901
             * @param <U> The type of the matched target.
1902
             */
1903
            public interface Step<U extends Target> {
1904

1905
                /**
1906
                 * Resolves this step of a substitution chain.
1907
                 *
1908
                 * @param target            The target member of invokedynamic invocation.
1909
                 * @param parameters        The parameters of the substituted element.
1910
                 * @param result            The resulting type of the substituted element.
1911
                 * @param methodHandle      A method handle of the stackManipulation invocation that is being substituted.
1912
                 * @param stackManipulation The byte code instruction that is being substituted.
1913
                 * @param current           The current type of the applied substitution that is the top element on the operand stack.
1914
                 * @param offsets           The arguments of the substituted byte code element mapped to their local variable offsets.
1915
                 * @param freeOffset        The first free offset in the local variable array.
1916
                 * @return A resolved substitution step for the supplied inputs.
1917
                 */
1918
                Resolution resolve(U target,
1919
                                   TypeList.Generic parameters,
1920
                                   TypeDescription.Generic result,
1921
                                   JavaConstant.MethodHandle methodHandle,
1922
                                   StackManipulation stackManipulation,
1923
                                   TypeDescription.Generic current,
1924
                                   Map<Integer, Integer> offsets,
1925
                                   int freeOffset);
1926

1927
                /**
1928
                 * A resolved substitution step.
1929
                 */
1930
                interface Resolution {
1931

1932
                    /**
1933
                     * Returns the stack manipulation to apply the substitution.
1934
                     *
1935
                     * @return The stack manipulation to apply the substitution.
1936
                     */
1937
                    StackManipulation getStackManipulation();
1938

1939
                    /**
1940
                     * Returns the resulting type of the substitution or {@code void} if no resulting value is applied.
1941
                     *
1942
                     * @return The resulting type of the substitution or {@code void} if no resulting value is applied.
1943
                     */
1944
                    TypeDescription.Generic getResultType();
1945
                }
1946

1947
                /**
1948
                 * Resolves a substitution for an instrumented method.
1949
                 *
1950
                 * @param <V> The type of the matched target.
1951
                 */
1952
                interface Factory<V extends Target> {
1953

1954
                    /**
1955
                     * Creates a substitution step for an instrumented method.
1956
                     *
1957
                     * @param assigner           The assigner to use.
1958
                     * @param typing             The typing to use.
1959
                     * @param instrumentedType   The instrumented type.
1960
                     * @param instrumentedMethod The instrumented method.
1961
                     * @return The substitution step to apply.
1962
                     */
1963
                    Step<V> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod);
1964
                }
1965

1966
                /**
1967
                 * A step that executes the original method invocation or field access.
1968
                 */
1969
                enum OfOriginalExpression implements Step<Target>, Factory<Target> {
1✔
1970

1971
                    /**
1972
                     * The singleton instance.
1973
                     */
1974
                    INSTANCE;
1✔
1975

1976
                    /**
1977
                     * {@inheritDoc}
1978
                     */
1979
                    public Resolution resolve(Target target,
1980
                                              TypeList.Generic parameters,
1981
                                              TypeDescription.Generic result,
1982
                                              JavaConstant.MethodHandle methodHandle,
1983
                                              StackManipulation stackManipulation,
1984
                                              TypeDescription.Generic current,
1985
                                              Map<Integer, Integer> offsets,
1986
                                              int freeOffset) {
1987
                        List<StackManipulation> stackManipulations;
1988
                        if (target instanceof Target.ForMember) {
1✔
1989
                            ByteCodeElement.Member member = ((Target.ForMember) target).getMember();
1✔
1990
                            if (member instanceof MethodDescription && ((MethodDescription) member).isConstructor()) {
1✔
1991
                                stackManipulations = new ArrayList<StackManipulation>(parameters.size() + 4);
1✔
1992
                                stackManipulations.add(Removal.of(current));
1✔
1993
                                stackManipulations.add(TypeCreation.of(member.getDeclaringType().asErasure()));
1✔
1994
                                stackManipulations.add(Duplication.SINGLE);
1✔
1995
                            } else {
1996
                                stackManipulations = new ArrayList<StackManipulation>(parameters.size() + 4);
1✔
1997
                                stackManipulations.add(Removal.of(current));
1✔
1998
                            }
1999
                            for (int index = 0; index < parameters.size(); index++) {
1✔
2000
                                stackManipulations.add(MethodVariableAccess.of(parameters.get(index)).loadFrom(offsets.get(index)));
1✔
2001
                            }
2002
                            if (member instanceof MethodDescription) {
1✔
2003
                                stackManipulations.add(stackManipulation);
1✔
2004
                                return new Simple(new StackManipulation.Compound(stackManipulations), ((MethodDescription) member).isConstructor()
1✔
2005
                                        ? member.getDeclaringType().asGenericType()
1✔
2006
                                        : ((MethodDescription) member).getReturnType());
1✔
2007
                            } else if (member instanceof FieldDescription) {
1✔
2008
                                if (member.isStatic()) {
1✔
2009
                                    if (parameters.isEmpty()) {
1✔
2010
                                        stackManipulations.add(stackManipulation);
1✔
2011
                                        return new Simple(new StackManipulation.Compound(stackManipulations), ((FieldDescription) member).getType());
1✔
2012
                                    } else /* if (parameters.size() == 1) */ {
2013
                                        stackManipulations.add(stackManipulation);
1✔
2014
                                        return new Simple(new StackManipulation.Compound(stackManipulations), TypeDefinition.Sort.describe(void.class));
1✔
2015
                                    }
2016
                                } else {
2017
                                    if (parameters.size() == 1) {
1✔
2018
                                        stackManipulations.add(FieldAccess.forField((FieldDescription) member).read());
1✔
2019
                                        return new Simple(new StackManipulation.Compound(stackManipulations), ((FieldDescription) member).getType());
1✔
2020
                                    } else /* if (parameters.size() == 2) */ {
2021
                                        stackManipulations.add(FieldAccess.forField((FieldDescription) member).write());
1✔
2022
                                        return new Simple(new StackManipulation.Compound(stackManipulations), TypeDefinition.Sort.describe(void.class));
1✔
2023
                                    }
2024
                                }
2025
                            } else {
2026
                                throw new IllegalStateException("Unexpected member: " + member);
×
2027
                            }
2028
                        } else if (target instanceof Target.ForDynamicInvocation) {
1✔
2029
                            stackManipulations = new ArrayList<StackManipulation>(parameters.size() + 4);
1✔
2030
                            stackManipulations.add(Removal.of(current));
1✔
2031
                            for (int index = 0; index < parameters.size(); index++) {
1✔
2032
                                stackManipulations.add(MethodVariableAccess.of(parameters.get(index)).loadFrom(offsets.get(index)));
×
2033
                            }
2034
                            stackManipulations.add(stackManipulation);
1✔
2035
                            return new Simple(new StackManipulation.Compound(stackManipulations), ((Target.ForDynamicInvocation) target).getMethodType().getReturnType().asGenericType());
1✔
2036
                        } else {
2037
                            throw new IllegalStateException("Unexpected target: " + target);
×
2038
                        }
2039
                    }
2040

2041
                    /**
2042
                     * {@inheritDoc}
2043
                     */
2044
                    public Step<Target> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
2045
                        return this;
1✔
2046
                    }
2047
                }
2048

2049
                /**
2050
                 * A simple substitution step within a substitution chain.
2051
                 */
2052
                @HashCodeAndEqualsPlugin.Enhance
2053
                class Simple implements Step<Target>, Factory<Target>, Resolution {
2054

2055
                    /**
2056
                     * The stack manipulation to apply.
2057
                     */
2058
                    private final StackManipulation stackManipulation;
2059

2060
                    /**
2061
                     * The resulting type of applying the stack manipulation.
2062
                     */
2063
                    private final TypeDescription.Generic resultType;
2064

2065
                    /**
2066
                     * Creates a new simple substitution step.
2067
                     *
2068
                     * @param stackManipulation The stack manipulation to apply.
2069
                     * @param resultType        The resulting type of applying the stack manipulation.
2070
                     */
2071
                    public Simple(StackManipulation stackManipulation, Type resultType) {
2072
                        this(stackManipulation, TypeDefinition.Sort.describe(resultType));
1✔
2073
                    }
1✔
2074

2075
                    /**
2076
                     * Creates a new simple substitution step.
2077
                     *
2078
                     * @param stackManipulation The stack manipulation to apply.
2079
                     * @param resultType        The resulting type of applying the stack manipulation.
2080
                     */
2081
                    public Simple(StackManipulation stackManipulation, TypeDescription.Generic resultType) {
1✔
2082
                        this.stackManipulation = stackManipulation;
1✔
2083
                        this.resultType = resultType;
1✔
2084
                    }
1✔
2085

2086
                    /**
2087
                     * Resolves a compile-time constant as the next step value.
2088
                     *
2089
                     * @param value The compile-time constant to resolve.
2090
                     * @return An appropriate step factory.
2091
                     */
2092
                    public static Step.Factory<Target> of(Object value) {
2093
                        ConstantValue constant = ConstantValue.Simple.wrap(value);
1✔
2094
                        return new Simple(constant.toStackManipulation(), constant.getTypeDescription().asGenericType());
1✔
2095
                    }
2096

2097
                    /**
2098
                     * {@inheritDoc}
2099
                     */
2100
                    public Step<Target> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
2101
                        return this;
1✔
2102
                    }
2103

2104
                    /**
2105
                     * {@inheritDoc}
2106
                     */
2107
                    public Resolution resolve(Target target,
2108
                                              TypeList.Generic parameters,
2109
                                              TypeDescription.Generic result,
2110
                                              JavaConstant.MethodHandle methodHandle,
2111
                                              StackManipulation stackManipulation,
2112
                                              TypeDescription.Generic current,
2113
                                              Map<Integer, Integer> offsets,
2114
                                              int freeOffset) {
2115
                        return current.represents(void.class)
1✔
2116
                                ? this
2117
                                : new Simple(new StackManipulation.Compound(Removal.of(current), this.stackManipulation), resultType);
1✔
2118
                    }
2119

2120
                    /**
2121
                     * {@inheritDoc}
2122
                     */
2123
                    public StackManipulation getStackManipulation() {
2124
                        return stackManipulation;
1✔
2125
                    }
2126

2127
                    /**
2128
                     * {@inheritDoc}
2129
                     */
2130
                    public TypeDescription.Generic getResultType() {
2131
                        return resultType;
1✔
2132
                    }
2133
                }
2134

2135
                /**
2136
                 * A step within a substitution chain that converts the current type to another type by casting.
2137
                 */
2138
                @HashCodeAndEqualsPlugin.Enhance
2139
                class ForAssignment implements Step<Target> {
2140

2141
                    /**
2142
                     * The result type or {@code null} if the type of the substitution result should be targeted.
2143
                     */
2144
                    @MaybeNull
2145
                    @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
2146
                    private final TypeDescription.Generic result;
2147

2148
                    /**
2149
                     * The assigner to use.
2150
                     */
2151
                    private final Assigner assigner;
2152

2153
                    /**
2154
                     * Creates a step for a type assignment.
2155
                     *
2156
                     * @param result   The result type or {@code null} if the type of the substitution result should be targeted.
2157
                     * @param assigner The assigner to use.
2158
                     */
2159
                    protected ForAssignment(@MaybeNull TypeDescription.Generic result, Assigner assigner) {
1✔
2160
                        this.result = result;
1✔
2161
                        this.assigner = assigner;
1✔
2162
                    }
1✔
2163

2164
                    /**
2165
                     * Creates a step factory that casts the current stack top value to the specified type.
2166
                     *
2167
                     * @param type The type that should be cast to.
2168
                     * @return An appropriate step factory.
2169
                     */
2170
                    public static Step.Factory<Target> castTo(Type type) {
2171
                        return new Factory(TypeDefinition.Sort.describe(type));
1✔
2172
                    }
2173

2174
                    /**
2175
                     * Creates a step factory that casts the current stack top value to the specified type.
2176
                     *
2177
                     * @param typeDescription The description of the type that should be cast to.
2178
                     * @return An appropriate step factory.
2179
                     */
2180
                    public static Step.Factory<Target> castTo(TypeDescription.Generic typeDescription) {
2181
                        return new Factory(typeDescription);
×
2182
                    }
2183

2184
                    /**
2185
                     * Creates a step factory that casts the current stack top value to the expected return value.
2186
                     *
2187
                     * @return An appropriate step factory.
2188
                     */
2189
                    public static Step.Factory<Target> castToSubstitutionResult() {
2190
                        return new Factory(null);
1✔
2191
                    }
2192

2193
                    /**
2194
                     * {@inheritDoc}
2195
                     */
2196
                    public Resolution resolve(Target target,
2197
                                              TypeList.Generic parameters,
2198
                                              TypeDescription.Generic result,
2199
                                              JavaConstant.MethodHandle methodHandle,
2200
                                              StackManipulation stackManipulation,
2201
                                              TypeDescription.Generic current,
2202
                                              Map<Integer, Integer> offsets,
2203
                                              int freeOffset) {
2204
                        StackManipulation assignment = assigner.assign(current, this.result == null ? result : this.result, Assigner.Typing.DYNAMIC);
1✔
2205
                        if (!assignment.isValid()) {
1✔
2206
                            throw new IllegalStateException("Failed to assign " + current + " to " + (this.result == null ? result : this.result));
×
2207
                        }
2208
                        return new Simple(assignment, this.result == null ? result : this.result);
1✔
2209
                    }
2210

2211
                    /**
2212
                     * A factory for creating a step for a dynamic type assignment.
2213
                     */
2214
                    @HashCodeAndEqualsPlugin.Enhance
2215
                    protected static class Factory implements Step.Factory<Target> {
2216

2217
                        /**
2218
                         * The result type or {@code null} if the type of the substitution result should be targeted.
2219
                         */
2220
                        @MaybeNull
2221
                        @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
2222
                        private final TypeDescription.Generic result;
2223

2224
                        /**
2225
                         * Creates a new factory for a step that applies a type assignment.
2226
                         *
2227
                         * @param result The result type or {@code null} if the type of the substitution result should be targeted.
2228
                         */
2229
                        protected Factory(@MaybeNull TypeDescription.Generic result) {
1✔
2230
                            this.result = result;
1✔
2231
                        }
1✔
2232

2233
                        /**
2234
                         * {@inheritDoc}
2235
                         */
2236
                        public Step<Target> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
2237
                            return new ForAssignment(result, assigner);
1✔
2238
                        }
2239
                    }
2240
                }
2241

2242
                /**
2243
                 * A step that substitutes an argument of a given index with a compatible type.
2244
                 */
2245
                @HashCodeAndEqualsPlugin.Enhance
2246
                class ForArgumentSubstitution implements Step<Target> {
2247

2248
                    /**
2249
                     * The stack manipulation that loads the substituted argument.
2250
                     */
2251
                    private final StackManipulation substitution;
2252

2253
                    /**
2254
                     * The type of the substituted argument.
2255
                     */
2256
                    private final TypeDescription.Generic typeDescription;
2257

2258
                    /**
2259
                     * The index of the argument to substitute.
2260
                     */
2261
                    private final int index;
2262

2263
                    /**
2264
                     * The assigner to use for assigning the argument.
2265
                     */
2266
                    private final Assigner assigner;
2267

2268
                    /**
2269
                     * The typing to use for the argument assignment.
2270
                     */
2271
                    private final Assigner.Typing typing;
2272

2273
                    /**
2274
                     * Creates an argument substitution step.
2275
                     *
2276
                     * @param substitution    The stack manipulation that loads the substituted argument.
2277
                     * @param typeDescription The type of the substituted argument.
2278
                     * @param index           The index of the argument to substitute.
2279
                     * @param assigner        The assigner to use for assigning the argument.
2280
                     * @param typing          The typing to use for the argument assignment.
2281
                     */
2282
                    protected ForArgumentSubstitution(StackManipulation substitution, TypeDescription.Generic typeDescription, int index, Assigner assigner, Assigner.Typing typing) {
1✔
2283
                        this.substitution = substitution;
1✔
2284
                        this.typeDescription = typeDescription;
1✔
2285
                        this.index = index;
1✔
2286
                        this.assigner = assigner;
1✔
2287
                        this.typing = typing;
1✔
2288
                    }
1✔
2289

2290
                    /**
2291
                     * Resolves a step substitution factory for a compile-time constant to replace an argument value at a given index.
2292
                     *
2293
                     * @param value The compile-time constant to replace.
2294
                     * @param index The index of the substituted argument.
2295
                     * @return An appropriate step factory.
2296
                     */
2297
                    public static Step.Factory<Target> of(Object value, int index) {
2298
                        if (index < 0) {
1✔
2299
                            throw new IllegalArgumentException("Index cannot be negative: " + index);
1✔
2300
                        }
2301
                        ConstantValue constant = ConstantValue.Simple.wrap(value);
1✔
2302
                        return new Factory(constant.toStackManipulation(), constant.getTypeDescription().asGenericType(), index);
1✔
2303
                    }
2304

2305
                    /**
2306
                     * {@inheritDoc}
2307
                     */
2308
                    public Resolution resolve(Target target,
2309
                                              TypeList.Generic parameters,
2310
                                              TypeDescription.Generic result,
2311
                                              JavaConstant.MethodHandle methodHandle,
2312
                                              StackManipulation stackManipulation,
2313
                                              TypeDescription.Generic current,
2314
                                              Map<Integer, Integer> offsets,
2315
                                              int freeOffset) {
2316
                        if (index >= parameters.size()) {
1✔
2317
                            throw new IllegalStateException(target + " has not " + index + " arguments");
×
2318
                        }
2319
                        StackManipulation assignment = assigner.assign(typeDescription, parameters.get(index), typing);
1✔
2320
                        if (!assignment.isValid()) {
1✔
2321
                            throw new IllegalStateException("Cannot assign " + typeDescription + " to " + parameters.get(index));
×
2322
                        }
2323
                        return new Simple(new StackManipulation.Compound(substitution, assignment, MethodVariableAccess.of(parameters.get(index)).storeAt(offsets.get(index))), current);
1✔
2324
                    }
2325

2326
                    /**
2327
                     * A factory to create an argument substitution step.
2328
                     */
2329
                    @HashCodeAndEqualsPlugin.Enhance
2330
                    public static class Factory implements Step.Factory<Target> {
2331

2332
                        /**
2333
                         * The stack manipulation that loads the substituted argument.
2334
                         */
2335
                        private final StackManipulation stackManipulation;
2336

2337
                        /**
2338
                         * The type of the substituted argument.
2339
                         */
2340
                        private final TypeDescription.Generic typeDescription;
2341

2342
                        /**
2343
                         * The index of the argument to substitute.
2344
                         */
2345
                        private final int index;
2346

2347
                        /**
2348
                         * Creates a factory for an argument substitution step.
2349
                         *
2350
                         * @param stackManipulation The stack manipulation that loads the substituted argument.
2351
                         * @param type              The type of the substituted argument.
2352
                         * @param index             The index of the argument to substitute.
2353
                         */
2354
                        public Factory(StackManipulation stackManipulation, Type type, int index) {
2355
                            this(stackManipulation, TypeDefinition.Sort.describe(type), index);
×
2356
                        }
×
2357

2358
                        /**
2359
                         * Creates a factory for an argument substitution step.
2360
                         *
2361
                         * @param stackManipulation The stack manipulation that loads the substituted argument.
2362
                         * @param typeDescription   The type of the substituted argument.
2363
                         * @param index             The index of the argument to substitute.
2364
                         */
2365
                        public Factory(StackManipulation stackManipulation, TypeDescription.Generic typeDescription, int index) {
1✔
2366
                            this.stackManipulation = stackManipulation;
1✔
2367
                            this.typeDescription = typeDescription;
1✔
2368
                            this.index = index;
1✔
2369
                        }
1✔
2370

2371
                        /**
2372
                         * {@inheritDoc}
2373
                         */
2374
                        public Step<Target> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
2375
                            return new ForArgumentSubstitution(stackManipulation, typeDescription, index, assigner, typing);
1✔
2376
                        }
2377
                    }
2378
                }
2379

2380
                /**
2381
                 * A step that loads an argument to a method as the current chain value.
2382
                 */
2383
                @HashCodeAndEqualsPlugin.Enhance
2384
                class ForArgumentLoading implements Step<Target>, Factory<Target> {
2385

2386
                    /**
2387
                     * The index of the argument to substitute.
2388
                     */
2389
                    private final int index;
2390

2391
                    /**
2392
                     * Creates an argument loading step.
2393
                     *
2394
                     * @param index The index of the argument to load.
2395
                     */
2396
                    protected ForArgumentLoading(int index) {
1✔
2397
                        this.index = index;
1✔
2398
                    }
1✔
2399

2400
                    /**
2401
                     * Creates a factory that loads the argument for the targeted value's parameter of the specified index.
2402
                     *
2403
                     * @param index The index to load.
2404
                     * @return An appropriate factory.
2405
                     */
2406
                    public static Factory<Target> ofTarget(int index) {
2407
                        if (index < 0) {
1✔
2408
                            throw new IllegalArgumentException("Argument index cannot be negative: " + index);
1✔
2409
                        }
2410
                        return new ForArgumentLoading(index);
1✔
2411
                    }
2412

2413
                    /**
2414
                     * Creates a factory that loads the argument for the instrumented method's parameter of the specified index.
2415
                     *
2416
                     * @param index The index to load.
2417
                     * @return An appropriate factory.
2418
                     */
2419
                    public static Factory<Target> ofInstrumentedMethod(int index) {
2420
                        if (index < 0) {
1✔
2421
                            throw new IllegalArgumentException("Argument index cannot be negative: " + index);
1✔
2422
                        }
2423
                        return new OfInstrumentedMethod(index);
1✔
2424
                    }
2425

2426
                    /**
2427
                     * Creates a factory that loads the {@code this} reference of the instrumented method.
2428
                     *
2429
                     * @return An appropriate factory.
2430
                     */
2431
                    public static Factory<Target> ofThis() {
2432
                        return OfInstrumentedMethodThis.INSTANCE;
1✔
2433
                    }
2434

2435
                    /**
2436
                     * {@inheritDoc}
2437
                     */
2438
                    public Step<Target> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
2439
                        return this;
1✔
2440
                    }
2441

2442
                    /**
2443
                     * {@inheritDoc}
2444
                     */
2445
                    public Resolution resolve(Target target,
2446
                                              TypeList.Generic parameters,
2447
                                              TypeDescription.Generic result,
2448
                                              JavaConstant.MethodHandle methodHandle,
2449
                                              StackManipulation stackManipulation,
2450
                                              TypeDescription.Generic current,
2451
                                              Map<Integer, Integer> offsets,
2452
                                              int freeOffset) {
2453
                        if (index >= parameters.size()) {
1✔
2454
                            throw new IllegalStateException(target + " has not " + index + " arguments");
×
2455
                        }
2456
                        return new Simple(new StackManipulation.Compound(Removal.of(current), MethodVariableAccess.of(parameters.get(index)).loadFrom(offsets.get(index))), parameters.get(index));
1✔
2457
                    }
2458

2459
                    /**
2460
                     * A factory that resolves the {@code this} reference of the instrumented method.
2461
                     */
2462
                    protected enum OfInstrumentedMethodThis implements Factory<Target> {
1✔
2463

2464
                        /**
2465
                         * The singleton instance.
2466
                         */
2467
                        INSTANCE;
1✔
2468

2469
                        /**
2470
                         * {@inheritDoc}
2471
                         */
2472
                        public Step<Target> make(Assigner assigner,
2473
                                                 Assigner.Typing typing,
2474
                                                 TypeDescription instrumentedType,
2475
                                                 MethodDescription instrumentedMethod) {
2476
                            if (instrumentedMethod.isStatic()) {
1✔
2477
                                throw new IllegalStateException(instrumentedMethod + " is static and does not define a this reference");
×
2478
                            }
2479
                            return new Simple(MethodVariableAccess.loadThis(), instrumentedType.asGenericType());
1✔
2480
                        }
2481
                    }
2482

2483
                    /**
2484
                     * A factory that resolves a given argument of the instrumented method.
2485
                     */
2486
                    @HashCodeAndEqualsPlugin.Enhance
2487
                    protected static class OfInstrumentedMethod implements Factory<Target> {
2488

2489
                        /**
2490
                         * The index of the argument to load.
2491
                         */
2492
                        private final int index;
2493

2494
                        /**
2495
                         * Creates a new factory for resolving an argument of the instrumented method.
2496
                         *
2497
                         * @param index The index of the argument to load.
2498
                         */
2499
                        protected OfInstrumentedMethod(int index) {
1✔
2500
                            this.index = index;
1✔
2501
                        }
1✔
2502

2503
                        /**
2504
                         * {@inheritDoc}
2505
                         */
2506
                        public Step<Target> make(Assigner assigner,
2507
                                                 Assigner.Typing typing,
2508
                                                 TypeDescription instrumentedType,
2509
                                                 MethodDescription instrumentedMethod) {
2510
                            if (instrumentedMethod.getParameters().size() < index) {
1✔
2511
                                throw new IllegalStateException(instrumentedMethod + " does not declare " + index + " parameters");
×
2512
                            }
2513
                            ParameterDescription parameterDescription = instrumentedMethod.getParameters().get(index);
1✔
2514
                            return new Simple(MethodVariableAccess.load(parameterDescription), parameterDescription.getType());
1✔
2515
                        }
2516
                    }
2517
                }
2518

2519
                /**
2520
                 * Creates a step for a field access.
2521
                 */
2522
                @HashCodeAndEqualsPlugin.Enhance
2523
                abstract class ForField implements Step<Target> {
2524

2525
                    /**
2526
                     * The field description accessed in this step.
2527
                     */
2528
                    protected final FieldDescription fieldDescription;
2529

2530
                    /**
2531
                     * The assigner to use.
2532
                     */
2533
                    protected final Assigner assigner;
2534

2535
                    /**
2536
                     * The typing to use when assigning.
2537
                     */
2538
                    protected final Assigner.Typing typing;
2539

2540
                    /**
2541
                     * Creates a new step for a field access.
2542
                     *
2543
                     * @param fieldDescription The field description accessed in this step.
2544
                     * @param assigner         The assigner to use.
2545
                     * @param typing           The typing to use when assigning.
2546
                     */
2547
                    protected ForField(FieldDescription fieldDescription, Assigner assigner, Assigner.Typing typing) {
1✔
2548
                        this.fieldDescription = fieldDescription;
1✔
2549
                        this.assigner = assigner;
1✔
2550
                        this.typing = typing;
1✔
2551
                    }
1✔
2552

2553
                    /**
2554
                     * {@inheritDoc}
2555
                     */
2556
                    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Field description always has declaring type.")
2557
                    public Resolution resolve(Target target,
2558
                                              TypeList.Generic parameters,
2559
                                              TypeDescription.Generic result,
2560
                                              JavaConstant.MethodHandle methodHandle,
2561
                                              StackManipulation stackManipulation,
2562
                                              TypeDescription.Generic current,
2563
                                              Map<Integer, Integer> offsets,
2564
                                              int freeOffset) {
2565
                        List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(2);
1✔
2566
                        if (fieldDescription.isStatic()) {
1✔
2567
                            stackManipulations.add(Removal.of(current));
1✔
2568
                        } else {
2569
                            StackManipulation assignment = assigner.assign(current, fieldDescription.getDeclaringType().asGenericType(), typing);
1✔
2570
                            if (!assignment.isValid()) {
1✔
2571
                                throw new IllegalStateException("Cannot assign " + current + " to " + fieldDescription.getDeclaringType());
×
2572
                            }
2573
                            stackManipulations.add(assignment);
1✔
2574
                        }
2575
                        return doResolve(target, parameters, offsets, new StackManipulation.Compound(stackManipulations));
1✔
2576
                    }
2577

2578
                    /**
2579
                     * Completes the resolution.
2580
                     *
2581
                     * @param target            The target member of invokedynamic invocation.
2582
                     * @param parameters        The parameters of the substituted element.
2583
                     * @param offsets           The arguments of the substituted byte code element mapped to their local variable offsets.
2584
                     * @param stackManipulation A stack manipulation to prepare the field access.
2585
                     * @return A resolved substitution step for the supplied inputs.
2586
                     */
2587
                    protected abstract Resolution doResolve(Target target,
2588
                                                            TypeList.Generic parameters,
2589
                                                            Map<Integer, Integer> offsets,
2590
                                                            StackManipulation stackManipulation);
2591

2592
                    /**
2593
                     * A step for reading a field.
2594
                     */
2595
                    @HashCodeAndEqualsPlugin.Enhance
2596
                    public static class Read extends ForField {
2597

2598
                        /**
2599
                         * Creates a step for reading a field.
2600
                         *
2601
                         * @param fieldDescription A description of the field being read.
2602
                         * @param assigner         The assigner to use.
2603
                         * @param typing           The typing to use when assigning.
2604
                         */
2605
                        protected Read(FieldDescription fieldDescription, Assigner assigner, Assigner.Typing typing) {
2606
                            super(fieldDescription, assigner, typing);
1✔
2607
                        }
1✔
2608

2609
                        /**
2610
                         * {@inheritDoc}
2611
                         */
2612
                        protected Resolution doResolve(Target target,
2613
                                                       TypeList.Generic parameters,
2614
                                                       Map<Integer, Integer> offsets,
2615
                                                       StackManipulation stackManipulation) {
2616
                            return new Simple(new StackManipulation.Compound(stackManipulation, FieldAccess.forField(fieldDescription).read()), fieldDescription.getType());
1✔
2617
                        }
2618

2619
                        /**
2620
                         * A factory for creating a field read step in a chain.
2621
                         */
2622
                        @HashCodeAndEqualsPlugin.Enhance
2623
                        public static class Factory implements Step.Factory<Target> {
2624

2625
                            /**
2626
                             * A description of the field being read.
2627
                             */
2628
                            private final FieldDescription fieldDescription;
2629

2630
                            /**
2631
                             * Creates a factory for a step reading a field.
2632
                             *
2633
                             * @param field The field being read.
2634
                             */
2635
                            public Factory(Field field) {
2636
                                this(new FieldDescription.ForLoadedField(field));
1✔
2637
                            }
1✔
2638

2639
                            /**
2640
                             * Creates a factory for a step reading a field.
2641
                             *
2642
                             * @param fieldDescription A description of the field being read.
2643
                             */
2644
                            public Factory(FieldDescription fieldDescription) {
1✔
2645
                                this.fieldDescription = fieldDescription;
1✔
2646
                            }
1✔
2647

2648
                            /**
2649
                             * {@inheritDoc}
2650
                             */
2651
                            public Step<Target> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
2652
                                return new Read(fieldDescription, assigner, typing);
1✔
2653
                            }
2654
                        }
2655
                    }
2656

2657
                    /**
2658
                     * A step for writing to a field.
2659
                     */
2660
                    @HashCodeAndEqualsPlugin.Enhance
2661
                    public static class Write extends ForField {
2662

2663
                        /**
2664
                         * The index of the parameter being accessed. If the targeted element is a non-static method, is increased by one.
2665
                         */
2666
                        private final int index;
2667

2668
                        /**
2669
                         * Creates a step for writing to a field.
2670
                         *
2671
                         * @param fieldDescription A description of the field to write to.
2672
                         * @param assigner         The assigner to use.
2673
                         * @param typing           The typing to use when assigning.
2674
                         * @param index            The index of the parameter being accessed. If the targeted element is a non-static method, is increased by one.
2675
                         */
2676
                        protected Write(FieldDescription fieldDescription, Assigner assigner, Assigner.Typing typing, int index) {
2677
                            super(fieldDescription, assigner, typing);
1✔
2678
                            this.index = index;
1✔
2679
                        }
1✔
2680

2681
                        /**
2682
                         * {@inheritDoc}
2683
                         */
2684
                        protected Resolution doResolve(Target target,
2685
                                                       TypeList.Generic parameters,
2686
                                                       Map<Integer, Integer> offsets,
2687
                                                       StackManipulation stackManipulation) {
2688
                            int index = target.isStaticDispatch() ? this.index : this.index + 1;
1✔
2689
                            if (index >= parameters.size()) {
1✔
2690
                                throw new IllegalStateException("Target does not define an argument with index " + index);
×
2691
                            }
2692
                            StackManipulation assignment = assigner.assign(parameters.get(index), fieldDescription.getType(), typing);
1✔
2693
                            if (!assignment.isValid()) {
1✔
2694
                                throw new IllegalStateException("Cannot write " + parameters.get(index) + " to " + fieldDescription);
×
2695
                            }
2696
                            return new Simple(new StackManipulation.Compound(stackManipulation,
1✔
2697
                                    MethodVariableAccess.of(parameters.get(index)).loadFrom(offsets.get(index)),
1✔
2698
                                    assignment,
2699
                                    FieldAccess.forField(fieldDescription).write()), TypeDefinition.Sort.describe(void.class));
1✔
2700
                        }
2701

2702
                        /**
2703
                         * A factory for creating a step to write to a field.
2704
                         */
2705
                        @HashCodeAndEqualsPlugin.Enhance
2706
                        public static class Factory implements Step.Factory<Target> {
2707

2708
                            /**
2709
                             * A description of the field to write to.
2710
                             */
2711
                            private final FieldDescription fieldDescription;
2712

2713
                            /**
2714
                             * The index of the parameter being accessed. If the targeted element is a non-static method, is increased by one.
2715
                             */
2716
                            private final int index;
2717

2718
                            /**
2719
                             * Creates a factory for writing to a field.
2720
                             *
2721
                             * @param field The field to write to.
2722
                             * @param index The index of the parameter being accessed. If the targeted element is a non-static method, is increased by one.
2723
                             */
2724
                            public Factory(Field field, int index) {
2725
                                this(new FieldDescription.ForLoadedField(field), index);
1✔
2726
                            }
1✔
2727

2728
                            /**
2729
                             * Creates a factory for writing to a field.
2730
                             *
2731
                             * @param fieldDescription A description of the field to write to.
2732
                             * @param index            The index of the parameter being accessed. If the targeted element is a non-static method, is increased by one.
2733
                             */
2734
                            public Factory(FieldDescription fieldDescription, int index) {
1✔
2735
                                this.fieldDescription = fieldDescription;
1✔
2736
                                this.index = index;
1✔
2737
                            }
1✔
2738

2739
                            /**
2740
                             * {@inheritDoc}
2741
                             */
2742
                            public Step<Target> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
2743
                                return new Write(fieldDescription, assigner, typing, index);
1✔
2744
                            }
2745
                        }
2746
                    }
2747
                }
2748

2749
                /**
2750
                 * A step for invoking a method or constructor. If non-static, a method is invoked upon a the current stack argument of the chain.
2751
                 * Arguments are loaded from the intercepted byte code element with a possibility of substitution.
2752
                 */
2753
                @HashCodeAndEqualsPlugin.Enhance
2754
                class ForInvocation implements Step<Target> {
2755

2756
                    /**
2757
                     * The invoked method or constructor.
2758
                     */
2759
                    private final MethodDescription methodDescription;
2760

2761
                    /**
2762
                     * A mapping of substituted parameter indices. For targets that are non-static methods, the targeted index is increased by one.
2763
                     */
2764
                    private final Map<Integer, Integer> substitutions;
2765

2766
                    /**
2767
                     * The assigner to use.
2768
                     */
2769
                    private final Assigner assigner;
2770

2771
                    /**
2772
                     * The typing to use when assigning.
2773
                     */
2774
                    private final Assigner.Typing typing;
2775

2776
                    /**
2777
                     * Creates a new step of an invocation.
2778
                     *
2779
                     * @param methodDescription The invoked method or constructor.
2780
                     * @param substitutions     A mapping of substituted parameter indices. For targets that are non-static methods, the targeted index is increased by one.
2781
                     * @param assigner          The assigner to use.
2782
                     * @param typing            The typing to use when assigning.
2783
                     */
2784
                    protected ForInvocation(MethodDescription methodDescription, Map<Integer, Integer> substitutions, Assigner assigner, Assigner.Typing typing) {
1✔
2785
                        this.methodDescription = methodDescription;
1✔
2786
                        this.substitutions = substitutions;
1✔
2787
                        this.assigner = assigner;
1✔
2788
                        this.typing = typing;
1✔
2789
                    }
1✔
2790

2791
                    /**
2792
                     * {@inheritDoc}
2793
                     */
2794
                    public Resolution resolve(Target target,
2795
                                              TypeList.Generic parameters,
2796
                                              TypeDescription.Generic result,
2797
                                              JavaConstant.MethodHandle methodHandle,
2798
                                              StackManipulation stackManipulation,
2799
                                              TypeDescription.Generic current,
2800
                                              Map<Integer, Integer> offsets,
2801
                                              int freeOffset) {
2802
                        List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(3 + parameters.size() * 2);
1✔
2803
                        if (methodDescription.isStatic()) {
1✔
2804
                            stackManipulations.add(Removal.of(current));
1✔
2805
                        } else if (methodDescription.isConstructor()) {
1✔
2806
                            stackManipulations.add(Removal.of(current));
×
2807
                            stackManipulations.add(TypeCreation.of(methodDescription.getDeclaringType().asErasure()));
×
2808
                        } else {
2809
                            StackManipulation assignment = assigner.assign(current, methodDescription.getDeclaringType().asGenericType(), typing);
1✔
2810
                            if (!assignment.isValid()) {
1✔
2811
                                throw new IllegalStateException("Cannot assign " + current + " to " + methodDescription.getDeclaringType());
×
2812
                            }
2813
                            stackManipulations.add(assignment);
1✔
2814
                        }
2815
                        boolean shift = !target.isStaticDispatch();
1✔
2816
                        for (int index = 0; index < methodDescription.getParameters().size(); index++) {
1✔
2817
                            int substitution = substitutions.containsKey(index + (shift ? 1 : 0)) ? substitutions.get(index + (shift ? 1 : 0)) : index + (shift ? 1 : 0);
1✔
2818
                            if (substitution >= parameters.size()) {
1✔
2819
                                throw new IllegalStateException(target + " does not support an index " + substitution);
×
2820
                            }
2821
                            stackManipulations.add(MethodVariableAccess.of(parameters.get(substitution)).loadFrom(offsets.get(substitution)));
1✔
2822
                            StackManipulation assignment = assigner.assign(parameters.get(substitution), methodDescription.getParameters().get(index).getType(), typing);
1✔
2823
                            if (!assignment.isValid()) {
1✔
2824
                                throw new IllegalStateException("Cannot assign parameter with " + index + " of type " + parameters.get(substitution) + " to " + methodDescription);
×
2825
                            }
2826
                            stackManipulations.add(assignment);
1✔
2827
                        }
2828
                        stackManipulations.add(MethodInvocation.invoke(methodDescription));
1✔
2829
                        return new Simple(new StackManipulation.Compound(stackManipulations), methodDescription.getReturnType());
1✔
2830
                    }
2831

2832
                    /**
2833
                     * A factory to create a step for a method invocation.
2834
                     */
2835
                    @HashCodeAndEqualsPlugin.Enhance
2836
                    public static class Factory implements Step.Factory<Target> {
2837

2838
                        /**
2839
                         * The invoked method or constructor.
2840
                         */
2841
                        private final MethodDescription methodDescription;
2842

2843
                        /**
2844
                         * A mapping of substituted parameter indices. For targets that are non-static methods, the targeted index is increased by one.
2845
                         */
2846
                        private final Map<Integer, Integer> substitutions;
2847

2848
                        /**
2849
                         * Creates a factory for a method invocation without parameter substitutions.
2850
                         *
2851
                         * @param method The invoked method.
2852
                         */
2853
                        public Factory(Method method) {
2854
                            this(new MethodDescription.ForLoadedMethod(method));
1✔
2855
                        }
1✔
2856

2857
                        /**
2858
                         * Creates a factory for a method invocation without parameter substitutions.
2859
                         *
2860
                         * @param method        The invoked method.
2861
                         * @param substitutions A mapping of substituted parameter indices. For targets that are non-static methods,
2862
                         *                      the targeted index is increased by one.
2863
                         */
2864
                        public Factory(Method method, Map<Integer, Integer> substitutions) {
2865
                            this(new MethodDescription.ForLoadedMethod(method), substitutions);
×
2866
                        }
×
2867

2868
                        /**
2869
                         * Creates a factory for a method invocation without parameter substitutions.
2870
                         *
2871
                         * @param constructor The constructor.
2872
                         */
2873
                        public Factory(Constructor<?> constructor) {
2874
                            this(new MethodDescription.ForLoadedConstructor(constructor));
×
2875
                        }
×
2876

2877
                        /**
2878
                         * Creates a factory for a method invocation without parameter substitutions.
2879
                         *
2880
                         * @param constructor   The constructor.
2881
                         * @param substitutions A mapping of substituted parameter indices. For targets that are non-static methods,
2882
                         *                      the targeted index is increased by one.
2883
                         */
2884
                        public Factory(Constructor<?> constructor, Map<Integer, Integer> substitutions) {
2885
                            this(new MethodDescription.ForLoadedConstructor(constructor), substitutions);
×
2886
                        }
×
2887

2888
                        /**
2889
                         * Creates a factory for a method invocation without parameter substitutions.
2890
                         *
2891
                         * @param methodDescription The invoked method or constructor.
2892
                         */
2893
                        public Factory(MethodDescription methodDescription) {
2894
                            this(methodDescription, Collections.<Integer, Integer>emptyMap());
1✔
2895
                        }
1✔
2896

2897
                        /**
2898
                         * Creates a factory for a method invocation.
2899
                         *
2900
                         * @param methodDescription The invoked method or constructor.
2901
                         * @param substitutions     A mapping of substituted parameter indices. For targets that are non-static methods,
2902
                         *                          the targeted index is increased by one.
2903
                         */
2904
                        public Factory(MethodDescription methodDescription, Map<Integer, Integer> substitutions) {
1✔
2905
                            this.methodDescription = methodDescription;
1✔
2906
                            this.substitutions = substitutions;
1✔
2907
                        }
1✔
2908

2909
                        /**
2910
                         * {@inheritDoc}
2911
                         */
2912
                        public Step<Target> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
2913
                            return new ForInvocation(methodDescription, substitutions, assigner, typing);
1✔
2914
                        }
2915
                    }
2916
                }
2917

2918
                /**
2919
                 * A step that invokes a delegation method based on annotations on the parameters of the targeted method.
2920
                 */
2921
                @HashCodeAndEqualsPlugin.Enhance
2922
                class ForDelegation implements Step<Target> {
2923

2924
                    /**
2925
                     * The type on top of the stack after the delegation is complete.
2926
                     */
2927
                    private final TypeDescription.Generic returned;
2928

2929
                    /**
2930
                     * The dispatcher to use.
2931
                     */
2932
                    private final Dispatcher.Resolved dispatcher;
2933

2934
                    /**
2935
                     * A list of offset mappings to execute prior to delegation.
2936
                     */
2937
                    private final List<OffsetMapping.Resolved> offsetMappings;
2938

2939
                    /**
2940
                     * @param returned       The type on top of the stack after the delegation is complete.
2941
                     * @param dispatcher     The dispatcher to use.
2942
                     * @param offsetMappings A list of offset mappings to execute prior to delegation.
2943
                     */
2944
                    protected ForDelegation(TypeDescription.Generic returned, Dispatcher.Resolved dispatcher, List<OffsetMapping.Resolved> offsetMappings) {
1✔
2945
                        this.returned = returned;
1✔
2946
                        this.dispatcher = dispatcher;
1✔
2947
                        this.offsetMappings = offsetMappings;
1✔
2948
                    }
1✔
2949

2950
                    /**
2951
                     * Returns a delegating step factory for the supplied method.
2952
                     *
2953
                     * @param method The method to delegate to.
2954
                     * @return An appropriate step factory.
2955
                     */
2956
                    public static Step.Factory<Target> to(Method method) {
2957
                        return to(new MethodDescription.ForLoadedMethod(method));
1✔
2958
                    }
2959

2960
                    /**
2961
                     * Returns a delegating step factory for the supplied constructor.
2962
                     *
2963
                     * @param constructor The constructor to delegate to.
2964
                     * @return An appropriate step factory.
2965
                     */
2966
                    public static Step.Factory<Target> to(Constructor<?> constructor) {
2967
                        return to(new MethodDescription.ForLoadedConstructor(constructor));
×
2968
                    }
2969

2970
                    /**
2971
                     * Returns a delegating step factory for the supplied method description..
2972
                     *
2973
                     * @param methodDescription A description of the method or constructor to delegate to.
2974
                     * @return An appropriate step factory.
2975
                     */
2976
                    public static Step.Factory<Target> to(MethodDescription.InDefinedShape methodDescription) {
2977
                        if (methodDescription.isTypeInitializer()) {
1✔
2978
                            throw new IllegalArgumentException("Cannot delegate to a type initializer: " + methodDescription);
×
2979
                        }
2980
                        return to(methodDescription, Dispatcher.ForRegularInvocation.Factory.INSTANCE, Collections.<OffsetMapping.Factory<?>>emptyList());
1✔
2981
                    }
2982

2983
                    /**
2984
                     * Creates an appropriate step factory for the given delegate method, dispatcher factory and user factories.
2985
                     *
2986
                     * @param delegate          A description of the method or constructor to delegate to.
2987
                     * @param dispatcherFactory The dispatcher factory to use.
2988
                     * @param userFactories     Factories for custom annotation bindings.
2989
                     * @return An appropriate step factory.
2990
                     */
2991
                    private static Step.Factory<Target> to(MethodDescription.InDefinedShape delegate, Dispatcher.Factory dispatcherFactory, List<? extends OffsetMapping.Factory<?>> userFactories) {
2992
                        if (delegate.isTypeInitializer()) {
1✔
2993
                            throw new IllegalArgumentException("Cannot delegate to type initializer: " + delegate);
×
2994
                        }
2995
                        return new Factory(delegate, dispatcherFactory.make(delegate), CompoundList.of(Arrays.<OffsetMapping.Factory<?>>asList(
1✔
2996
                                OffsetMapping.ForArgument.Factory.INSTANCE,
2997
                                OffsetMapping.ForThisReference.Factory.INSTANCE,
2998
                                OffsetMapping.ForAllArguments.Factory.INSTANCE,
2999
                                OffsetMapping.ForSelfCallHandle.Factory.INSTANCE,
3000
                                OffsetMapping.ForHandle.Factory.INSTANCE,
3001
                                OffsetMapping.ForDynamicConstant.Factory.INSTANCE,
3002
                                OffsetMapping.ForField.Unresolved.Factory.INSTANCE,
3003
                                OffsetMapping.ForFieldHandle.Unresolved.GetterFactory.INSTANCE,
3004
                                OffsetMapping.ForFieldHandle.Unresolved.SetterFactory.INSTANCE,
3005
                                OffsetMapping.ForOrigin.Factory.INSTANCE,
3006
                                OffsetMapping.ForStubValue.Factory.INSTANCE,
3007
                                new OffsetMapping.ForStackManipulation.OfDefaultValue<Unused>(Unused.class),
3008
                                OffsetMapping.ForCurrent.Factory.INSTANCE), userFactories));
3009
                    }
3010

3011
                    /**
3012
                     * Returns a builder for creating a {@link ForDelegation} with custom configuration.
3013
                     *
3014
                     * @return A bulder for creating a custom delegator.
3015
                     */
3016
                    public static WithCustomMapping withCustomMapping() {
3017
                        return new WithCustomMapping(Dispatcher.ForRegularInvocation.Factory.INSTANCE, Collections.<Class<? extends Annotation>, OffsetMapping.Factory<?>>emptyMap());
1✔
3018
                    }
3019

3020
                    /**
3021
                     * {@inheritDoc}
3022
                     */
3023
                    public Resolution resolve(Target target,
3024
                                              TypeList.Generic parameters,
3025
                                              TypeDescription.Generic result,
3026
                                              JavaConstant.MethodHandle methodHandle,
3027
                                              StackManipulation stackManipulation,
3028
                                              TypeDescription.Generic current,
3029
                                              Map<Integer, Integer> offsets,
3030
                                              int freeOffset) {
3031
                        List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(offsetMappings.size() + 3);
1✔
3032
                        stackManipulations.add(current.represents(void.class)
1✔
3033
                                ? StackManipulation.Trivial.INSTANCE
3034
                                : MethodVariableAccess.of(current).storeAt(freeOffset));
1✔
3035
                        stackManipulations.add(dispatcher.initialize());
1✔
3036
                        for (OffsetMapping.Resolved offsetMapping : offsetMappings) {
1✔
3037
                            stackManipulations.add(offsetMapping.apply(target,
1✔
3038
                                    parameters,
3039
                                    result,
3040
                                    current,
3041
                                    methodHandle,
3042
                                    offsets,
3043
                                    freeOffset));
3044
                        }
1✔
3045
                        stackManipulations.add(dispatcher.apply(target, methodHandle));
1✔
3046
                        return new Simple(new StackManipulation.Compound(stackManipulations), returned);
1✔
3047
                    }
3048

3049
                    /**
3050
                     * A factory for creating a delegating step during a member substitution.
3051
                     */
3052
                    @HashCodeAndEqualsPlugin.Enhance
3053
                    protected static class Factory implements Step.Factory<Target> {
3054

3055
                        /**
3056
                         * A description of the method or constructor to delegate to.
3057
                         */
3058
                        private final MethodDescription.InDefinedShape delegate;
3059

3060
                        /**
3061
                         * The dispatcher to use for invoking the delegate.
3062
                         */
3063
                        private final Dispatcher dispatcher;
3064

3065
                        /**
3066
                         * The offset mappings to use.
3067
                         */
3068
                        private final List<OffsetMapping> offsetMappings;
3069

3070
                        /**
3071
                         * Creates a new factory for a delegating step.
3072
                         *
3073
                         * @param delegate   A description of the method or constructor to delegate to.
3074
                         * @param dispatcher The dispatcher to use for invoking the delegate.
3075
                         * @param factories  The dispatcher to use for invoking the delegate.
3076
                         */
3077
                        protected Factory(MethodDescription.InDefinedShape delegate, Dispatcher dispatcher, List<? extends OffsetMapping.Factory<?>> factories) {
1✔
3078
                            Map<TypeDescription, OffsetMapping.Factory<?>> offsetMappings = new HashMap<TypeDescription, OffsetMapping.Factory<?>>();
1✔
3079
                            for (OffsetMapping.Factory<?> factory : factories) {
1✔
3080
                                offsetMappings.put(net.bytebuddy.description.type.TypeDescription.ForLoadedType.of(factory.getAnnotationType()), factory);
1✔
3081
                            }
1✔
3082
                            this.offsetMappings = new ArrayList<OffsetMapping>(factories.size());
1✔
3083
                            if (delegate.isMethod() && !delegate.isStatic()) {
1✔
3084
                                OffsetMapping offsetMapping = null;
1✔
3085
                                for (AnnotationDescription annotationDescription : delegate.getDeclaredAnnotations()) {
1✔
3086
                                    OffsetMapping.Factory<?> factory = offsetMappings.get(annotationDescription.getAnnotationType());
×
3087
                                    if (factory != null) {
×
3088
                                        @SuppressWarnings("unchecked") OffsetMapping current = factory.make(delegate, (AnnotationDescription.Loadable) annotationDescription.prepare(factory.getAnnotationType()));
×
3089
                                        if (offsetMapping == null) {
×
3090
                                            offsetMapping = current;
×
3091
                                        } else {
3092
                                            throw new IllegalStateException(delegate + " is bound to both " + current + " and " + offsetMapping);
×
3093
                                        }
3094
                                    }
3095
                                }
×
3096
                                this.offsetMappings.add(offsetMapping == null
1✔
3097
                                        ? new OffsetMapping.ForThisReference(delegate.getDeclaringType().asGenericType(), null, Source.SUBSTITUTED_ELEMENT, false)
1✔
3098
                                        : offsetMapping);
3099
                            }
3100
                            for (int index = 0; index < delegate.getParameters().size(); index++) {
1✔
3101
                                ParameterDescription.InDefinedShape parameterDescription = delegate.getParameters().get(index);
1✔
3102
                                OffsetMapping offsetMapping = null;
1✔
3103
                                for (AnnotationDescription annotationDescription : parameterDescription.getDeclaredAnnotations()) {
1✔
3104
                                    OffsetMapping.Factory<?> factory = offsetMappings.get(annotationDescription.getAnnotationType());
1✔
3105
                                    if (factory != null) {
1✔
3106
                                        @SuppressWarnings("unchecked") OffsetMapping current = factory.make(parameterDescription, (AnnotationDescription.Loadable) annotationDescription.prepare(factory.getAnnotationType()));
1✔
3107
                                        if (offsetMapping == null) {
1✔
3108
                                            offsetMapping = current;
1✔
3109
                                        } else {
3110
                                            throw new IllegalStateException(parameterDescription + " is bound to both " + current + " and " + offsetMapping);
×
3111
                                        }
3112
                                    }
3113
                                }
1✔
3114
                                this.offsetMappings.add(offsetMapping == null
1✔
3115
                                        ? new OffsetMapping.ForArgument(parameterDescription.getType(), index, null, Source.SUBSTITUTED_ELEMENT, false)
1✔
3116
                                        : offsetMapping);
3117
                            }
3118
                            this.delegate = delegate;
1✔
3119
                            this.dispatcher = dispatcher;
1✔
3120
                        }
1✔
3121

3122
                        /**
3123
                         * {@inheritDoc}
3124
                         */
3125
                        public Step<Target> make(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
3126
                            List<OffsetMapping.Resolved> targets = new ArrayList<OffsetMapping.Resolved>(offsetMappings.size());
1✔
3127
                            for (OffsetMapping offsetMapping : offsetMappings) {
1✔
3128
                                targets.add(offsetMapping.resolve(assigner, typing, instrumentedType, instrumentedMethod));
1✔
3129
                            }
1✔
3130
                            return new ForDelegation(delegate.getReturnType(), dispatcher.resolve(instrumentedType, instrumentedMethod), targets);
1✔
3131
                        }
3132
                    }
3133

3134
                    /**
3135
                     * An offset mapping for binding a parameter or dispatch target for the method or constructor that is delegated to.
3136
                     */
3137
                    public interface OffsetMapping {
3138

3139
                        /**
3140
                         * Resolves an offset mapping for a given instrumented method.
3141
                         *
3142
                         * @param assigner           The assigner to use.
3143
                         * @param typing             The typing to use if no explicit typing is specified.
3144
                         * @param instrumentedType   The instrumented type.
3145
                         * @param instrumentedMethod The instrumented method.
3146
                         * @return A resolved version of this offset mapping.
3147
                         */
3148
                        OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod);
3149

3150
                        /**
3151
                         * An offset mapping that was resolved for a given instrumented type and method.
3152
                         */
3153
                        interface Resolved {
3154

3155
                            /**
3156
                             * Applies this offset mapping.
3157
                             *
3158
                             * @param target       The target member of invokedynamic invocation.
3159
                             * @param parameters   The parameters that are supplied to the substituted expression.
3160
                             * @param result       The resulting type of the substituted expression.
3161
                             * @param current      The type of the value that was produced by the previous step in the substitution chain.
3162
                             * @param methodHandle A method handle that represents the substituted element.
3163
                             * @param offsets      The offsets of the supplied parameters.
3164
                             * @param offset       The offset of the value that was produced by the previous step.
3165
                             * @return An appropriate stack manipulation.
3166
                             */
3167
                            StackManipulation apply(Target target,
3168
                                                    TypeList.Generic parameters,
3169
                                                    TypeDescription.Generic result,
3170
                                                    TypeDescription.Generic current,
3171
                                                    JavaConstant.MethodHandle methodHandle,
3172
                                                    Map<Integer, Integer> offsets,
3173
                                                    int offset);
3174

3175
                            /**
3176
                             * An offset mapping that loads a stack manipulation.
3177
                             */
3178
                            @HashCodeAndEqualsPlugin.Enhance
3179
                            class ForStackManipulation implements OffsetMapping.Resolved {
3180

3181
                                /**
3182
                                 * The stack manipulation to load.
3183
                                 */
3184
                                private final StackManipulation stackManipulation;
3185

3186
                                /**
3187
                                 * Creates a resolved offset mapping for a stack manipulation.
3188
                                 *
3189
                                 * @param stackManipulation The stack manipulation to load.
3190
                                 */
3191
                                public ForStackManipulation(StackManipulation stackManipulation) {
1✔
3192
                                    this.stackManipulation = stackManipulation;
1✔
3193
                                }
1✔
3194

3195
                                /**
3196
                                 * {@inheritDoc}
3197
                                 */
3198
                                public StackManipulation apply(Target target,
3199
                                                               TypeList.Generic parameters,
3200
                                                               TypeDescription.Generic result,
3201
                                                               TypeDescription.Generic current,
3202
                                                               JavaConstant.MethodHandle methodHandle,
3203
                                                               Map<Integer, Integer> offsets,
3204
                                                               int offset) {
3205
                                    return stackManipulation;
1✔
3206
                                }
3207
                            }
3208
                        }
3209

3210
                        /**
3211
                         * A factory for creating an offset mapping based on an annotation on a parameter, method or constructor.
3212
                         *
3213
                         * @param <T> The type of the annotation.
3214
                         */
3215
                        interface Factory<T extends Annotation> {
3216

3217
                            /**
3218
                             * Returns the type of the annotation for this factory.
3219
                             *
3220
                             * @return The type of the annotation for this factory.
3221
                             */
3222
                            Class<T> getAnnotationType();
3223

3224
                            /**
3225
                             * Creates an offset mapping for an annotation that was found on a non-static method.
3226
                             *
3227
                             * @param target     The method that is the delegated to.
3228
                             * @param annotation The annotation that was found on the method.
3229
                             * @return An appropriate offset mapping.
3230
                             */
3231
                            OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<T> annotation);
3232

3233
                            /**
3234
                             * Creates an offset mapping for a parameter of the method or constructor that is the delegation target.
3235
                             *
3236
                             * @param target     The parameter that is bound to an expression.
3237
                             * @param annotation The annotation that was found on the parameter.
3238
                             * @return An appropriate offset mapping.
3239
                             */
3240
                            OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<T> annotation);
3241

3242
                            /**
3243
                             * An abstract base implementation of a factory for an offset mapping.
3244
                             *
3245
                             * @param <S> The type of the represented annotation.
3246
                             */
3247
                            abstract class AbstractBase<S extends Annotation> implements OffsetMapping.Factory<S> {
1✔
3248

3249
                                /**
3250
                                 * {@inheritDoc}
3251
                                 */
3252
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<S> annotation) {
3253
                                    return make(target.getDeclaringType().asGenericType(), annotation);
×
3254
                                }
3255

3256
                                /**
3257
                                 * {@inheritDoc}
3258
                                 */
3259
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<S> annotation) {
3260
                                    return make(target.getType(), annotation);
1✔
3261
                                }
3262

3263
                                /**
3264
                                 * Returns an offset mapping for the bound method target or parameter.
3265
                                 *
3266
                                 * @param target     The declaring type of a non-static method or a parameter type.
3267
                                 * @param annotation The annotation that was found on the method or parameter.
3268
                                 * @return An appropriate offset mapping.
3269
                                 */
3270
                                protected abstract OffsetMapping make(TypeDescription.Generic target, AnnotationDescription.Loadable<S> annotation);
3271
                            }
3272

3273
                            /**
3274
                             * A factory for an offset mapping that does not support binding a method target.
3275
                             *
3276
                             * @param <S> The type of the represented annotation.
3277
                             */
3278
                            abstract class WithParameterSupportOnly<S extends Annotation> implements OffsetMapping.Factory<S> {
×
3279

3280
                                /**
3281
                                 * {@inheritDoc}
3282
                                 */
3283
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<S> annotation) {
3284
                                    throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
3285
                                }
3286
                            }
3287

3288
                            /**
3289
                             * A simple factory for an offset mapping.
3290
                             *
3291
                             * @param <S> The type of the represented annotation.
3292
                             */
3293
                            @HashCodeAndEqualsPlugin.Enhance
3294
                            class Simple<S extends Annotation> extends OffsetMapping.Factory.AbstractBase<S> {
3295

3296
                                /**
3297
                                 * The type of the bound annotation.
3298
                                 */
3299
                                private final Class<S> annotationType;
3300

3301
                                /**
3302
                                 * The offset mapping to return.
3303
                                 */
3304
                                private final OffsetMapping offsetMapping;
3305

3306
                                /**
3307
                                 * Creates a simple factory for an offset mapping.
3308
                                 *
3309
                                 * @param annotationType The type of the bound annotation.
3310
                                 * @param offsetMapping  The offset mapping to return.
3311
                                 */
3312
                                public Simple(Class<S> annotationType, OffsetMapping offsetMapping) {
×
3313
                                    this.annotationType = annotationType;
×
3314
                                    this.offsetMapping = offsetMapping;
×
3315
                                }
×
3316

3317
                                /**
3318
                                 * {@inheritDoc}
3319
                                 */
3320
                                public Class<S> getAnnotationType() {
3321
                                    return annotationType;
×
3322
                                }
3323

3324
                                @Override
3325
                                protected OffsetMapping make(TypeDescription.Generic target, AnnotationDescription.Loadable<S> annotation) {
3326
                                    return offsetMapping;
×
3327
                                }
3328
                            }
3329
                        }
3330

3331
                        /**
3332
                         * An offset mapping that resolves a given stack manipulation.
3333
                         */
3334
                        @HashCodeAndEqualsPlugin.Enhance
3335
                        class ForStackManipulation implements OffsetMapping {
3336

3337
                            /**
3338
                             * The stack manipulation to apply.
3339
                             */
3340
                            private final StackManipulation stackManipulation;
3341

3342
                            /**
3343
                             * The type of the value that is produced by the stack manipulation.
3344
                             */
3345
                            private final TypeDescription.Generic typeDescription;
3346

3347
                            /**
3348
                             * The type of the parameter or method target that is bound by this mapping.
3349
                             */
3350
                            private final TypeDescription.Generic targetType;
3351

3352
                            /**
3353
                             * Creates a new offset mapping for a stack manipulation.
3354
                             *
3355
                             * @param stackManipulation The stack manipulation to apply.
3356
                             * @param typeDescription   The type of the value that is produced by the stack manipulation.
3357
                             * @param targetType        The type of the parameter or method target that is bound by this mapping.
3358
                             */
3359
                            public ForStackManipulation(StackManipulation stackManipulation, TypeDescription.Generic typeDescription, TypeDescription.Generic targetType) {
1✔
3360
                                this.targetType = targetType;
1✔
3361
                                this.stackManipulation = stackManipulation;
1✔
3362
                                this.typeDescription = typeDescription;
1✔
3363
                            }
1✔
3364

3365
                            /**
3366
                             * Resolves an offset mapping that binds the provided annotation type to a given constant value.
3367
                             *
3368
                             * @param annotationType The annotation type to bind.
3369
                             * @param value          The constant value being bound or {@code null}.
3370
                             * @param <S>            The type of the annotation.
3371
                             * @return An appropriate factory for an offset mapping.
3372
                             */
3373
                            public static <S extends Annotation> OffsetMapping.Factory<S> of(Class<S> annotationType, @MaybeNull Object value) {
3374
                                return value == null
×
3375
                                        ? new OffsetMapping.ForStackManipulation.OfDefaultValue<S>(annotationType)
3376
                                        : new OffsetMapping.ForStackManipulation.Factory<S>(annotationType, ConstantValue.Simple.wrap(value));
×
3377
                            }
3378

3379
                            /**
3380
                             * {@inheritDoc}
3381
                             */
3382
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
3383
                                return new ForStackManipulation.Resolved(assigner, typing, stackManipulation, typeDescription, targetType);
1✔
3384
                            }
3385

3386
                            /**
3387
                             * A resolved offset mapping for a stack manipulation.
3388
                             */
3389
                            @HashCodeAndEqualsPlugin.Enhance
3390
                            protected static class Resolved implements OffsetMapping.Resolved {
3391

3392
                                /**
3393
                                 * The assigner to use.
3394
                                 */
3395
                                private final Assigner assigner;
3396

3397
                                /**
3398
                                 * The typing to apply.
3399
                                 */
3400
                                private final Assigner.Typing typing;
3401

3402
                                /**
3403
                                 * The stack manipulation to apply.
3404
                                 */
3405
                                private final StackManipulation stackManipulation;
3406

3407
                                /**
3408
                                 * The type of the value that is produced by the stack manipulation.
3409
                                 */
3410
                                private final TypeDescription.Generic typeDescription;
3411

3412
                                /**
3413
                                 * The type of the parameter or method target that is bound by this mapping.
3414
                                 */
3415
                                private final TypeDescription.Generic targetType;
3416

3417
                                /**
3418
                                 * Creates a resolved offset mapping for a given stack manipulation.
3419
                                 *
3420
                                 * @param assigner          The assigner to use.
3421
                                 * @param typing            The typing to apply.
3422
                                 * @param stackManipulation The stack manipulation to apply.
3423
                                 * @param typeDescription   The type of the value that is produced by the stack manipulation.
3424
                                 * @param targetType        The type of the parameter or method target that is bound by this mapping.
3425
                                 */
3426
                                protected Resolved(Assigner assigner,
3427
                                                   Assigner.Typing typing,
3428
                                                   StackManipulation stackManipulation,
3429
                                                   TypeDescription.Generic typeDescription,
3430
                                                   TypeDescription.Generic targetType) {
1✔
3431
                                    this.assigner = assigner;
1✔
3432
                                    this.typing = typing;
1✔
3433
                                    this.stackManipulation = stackManipulation;
1✔
3434
                                    this.typeDescription = typeDescription;
1✔
3435
                                    this.targetType = targetType;
1✔
3436
                                }
1✔
3437

3438
                                /**
3439
                                 * {@inheritDoc}
3440
                                 */
3441
                                public StackManipulation apply(Target target,
3442
                                                               TypeList.Generic parameters,
3443
                                                               TypeDescription.Generic result,
3444
                                                               TypeDescription.Generic current,
3445
                                                               JavaConstant.MethodHandle methodHandle,
3446
                                                               Map<Integer, Integer> offsets,
3447
                                                               int offset) {
3448
                                    StackManipulation assignment = assigner.assign(typeDescription, targetType, typing);
1✔
3449
                                    if (!assignment.isValid()) {
1✔
3450
                                        throw new IllegalStateException("Cannot assign " + typeDescription + " to " + targetType);
×
3451
                                    }
3452
                                    return new StackManipulation.Compound(stackManipulation, assignment);
1✔
3453
                                }
3454
                            }
3455

3456
                            /**
3457
                             * A factory that binds the default value of the annotated parameter, i.e. {@code null} for reference types
3458
                             * or the specific version of {@code 0} for primitive types.
3459
                             *
3460
                             * @param <T> The type of the annotation.
3461
                             */
3462
                            @HashCodeAndEqualsPlugin.Enhance
3463
                            public static class OfDefaultValue<T extends Annotation> implements OffsetMapping.Factory<T> {
3464

3465
                                /**
3466
                                 * The annotation type.
3467
                                 */
3468
                                private final Class<T> annotationType;
3469

3470
                                /**
3471
                                 * Creates a new factory for binding a default value.
3472
                                 *
3473
                                 * @param annotationType The annotation type.
3474
                                 */
3475
                                public OfDefaultValue(Class<T> annotationType) {
1✔
3476
                                    this.annotationType = annotationType;
1✔
3477
                                }
1✔
3478

3479
                                /**
3480
                                 * {@inheritDoc}
3481
                                 */
3482
                                public Class<T> getAnnotationType() {
3483
                                    return annotationType;
1✔
3484
                                }
3485

3486
                                /**
3487
                                 * {@inheritDoc}
3488
                                 */
3489
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<T> annotation) {
3490
                                    throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
3491
                                }
3492

3493
                                /**
3494
                                 * {@inheritDoc}
3495
                                 */
3496
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<T> annotation) {
3497
                                    return new ForStackManipulation(DefaultValue.of(target.getType()), target.getType(), target.getType());
1✔
3498
                                }
3499
                            }
3500

3501
                            /**
3502
                             * A factory that binds a given annotation property to the parameter.
3503
                             *
3504
                             * @param <T> The type of the annotation.
3505
                             */
3506
                            @HashCodeAndEqualsPlugin.Enhance
3507
                            public static class OfAnnotationProperty<T extends Annotation> extends OffsetMapping.Factory.WithParameterSupportOnly<T> {
3508

3509
                                /**
3510
                                 * The annotation type.
3511
                                 */
3512
                                private final Class<T> annotationType;
3513

3514
                                /**
3515
                                 * The annotation property to resolve.
3516
                                 */
3517
                                private final MethodDescription.InDefinedShape property;
3518

3519
                                /**
3520
                                 * Creates a factory for assigning an annotation property to the annotated parameter.
3521
                                 *
3522
                                 * @param annotationType The annotation type.
3523
                                 * @param property       The annotation property to resolve.
3524
                                 */
3525
                                protected OfAnnotationProperty(Class<T> annotationType, MethodDescription.InDefinedShape property) {
×
3526
                                    this.annotationType = annotationType;
×
3527
                                    this.property = property;
×
3528
                                }
×
3529

3530
                                /**
3531
                                 * Resolves an offset mapping factory where the provided property is assigned to any parameter that
3532
                                 * is annotated with the given annotation.
3533
                                 *
3534
                                 * @param annotationType The annotation type.
3535
                                 * @param property       The name of the property on the
3536
                                 * @param <S>            The type of the annotation from which the property is read.
3537
                                 * @return An appropriate factory for an offset mapping.
3538
                                 */
3539
                                public static <S extends Annotation> OffsetMapping.Factory<S> of(Class<S> annotationType, String property) {
3540
                                    if (!annotationType.isAnnotation()) {
×
3541
                                        throw new IllegalArgumentException("Not an annotation type: " + annotationType);
×
3542
                                    }
3543
                                    try {
3544
                                        return new ForStackManipulation.OfAnnotationProperty<S>(annotationType, new MethodDescription.ForLoadedMethod(annotationType.getMethod(property)));
×
3545
                                    } catch (NoSuchMethodException exception) {
×
3546
                                        throw new IllegalArgumentException("Cannot find a property " + property + " on " + annotationType, exception);
×
3547
                                    }
3548
                                }
3549

3550
                                /**
3551
                                 * {@inheritDoc}
3552
                                 */
3553
                                public Class<T> getAnnotationType() {
3554
                                    return annotationType;
×
3555
                                }
3556

3557
                                /**
3558
                                 * {@inheritDoc}
3559
                                 */
3560
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<T> annotation) {
3561
                                    ConstantValue value = ConstantValue.Simple.wrapOrNull(annotation.getValue(property).resolve());
×
3562
                                    if (value == null) {
×
3563
                                        throw new IllegalStateException("Not a constant value property: " + property);
×
3564
                                    }
3565
                                    return new ForStackManipulation(value.toStackManipulation(), value.getTypeDescription().asGenericType(), target.getType());
×
3566
                                }
3567
                            }
3568

3569
                            /**
3570
                             * Assigns a value to the annotated parameter that is deserialized from a given input.
3571
                             *
3572
                             * @param <T> The type of the annotation.
3573
                             */
3574
                            @HashCodeAndEqualsPlugin.Enhance
3575
                            public static class OfSerializedConstant<T extends Annotation> extends OffsetMapping.Factory.AbstractBase<T> {
3576

3577
                                /**
3578
                                 * The annotation type.
3579
                                 */
3580
                                private final Class<T> annotationType;
3581

3582
                                /**
3583
                                 * A stack manipulation that represents the deserialization.
3584
                                 */
3585
                                private final StackManipulation deserialization;
3586

3587
                                /**
3588
                                 * A description of the type that is returned as a result of the deserialization.
3589
                                 */
3590
                                private final TypeDescription.Generic typeDescription;
3591

3592
                                /**
3593
                                 * Creates a factory that creates an offset mapping for a value that is deserialized.
3594
                                 *
3595
                                 * @param annotationType  The annotation type.
3596
                                 * @param deserialization A stack manipulation that represents the deserialization.
3597
                                 * @param typeDescription A description of the type that is returned as a result of the deserialization.
3598
                                 */
3599
                                protected OfSerializedConstant(Class<T> annotationType, StackManipulation deserialization, TypeDescription.Generic typeDescription) {
1✔
3600
                                    this.annotationType = annotationType;
1✔
3601
                                    this.deserialization = deserialization;
1✔
3602
                                    this.typeDescription = typeDescription;
1✔
3603
                                }
1✔
3604

3605
                                /**
3606
                                 * Creates a factory for an offset mapping that deserializes a given value that is then assigned to the annotated parameter or used as a method target.
3607
                                 *
3608
                                 * @param type       The annotation type.
3609
                                 * @param value      The serialized value.
3610
                                 * @param targetType The type of the value that is deserialized.
3611
                                 * @param <S>        The type of the annotation.
3612
                                 * @param <U>        The type of the serialized value.
3613
                                 * @return An appropriate factory for an offset mapping.
3614
                                 */
3615
                                public static <S extends Annotation, U extends Serializable> OffsetMapping.Factory<S> of(Class<S> type, U value, Class<? super U> targetType) {
3616
                                    if (!targetType.isInstance(value)) {
1✔
3617
                                        throw new IllegalArgumentException(value + " is no instance of " + targetType);
×
3618
                                    }
3619
                                    return new ForStackManipulation.OfSerializedConstant<S>(type, SerializedConstant.of(value), net.bytebuddy.description.type.TypeDescription.ForLoadedType.of(targetType).asGenericType());
1✔
3620
                                }
3621

3622
                                /**
3623
                                 * {@inheritDoc}
3624
                                 */
3625
                                public Class<T> getAnnotationType() {
3626
                                    return annotationType;
1✔
3627
                                }
3628

3629
                                @Override
3630
                                protected OffsetMapping make(TypeDescription.Generic target, AnnotationDescription.Loadable<T> annotation) {
3631
                                    return new ForStackManipulation(deserialization, typeDescription, target);
1✔
3632
                                }
3633
                            }
3634

3635
                            /**
3636
                             * A factory that invokes a method dynamically and assignes the result to the annotated parameter.
3637
                             *
3638
                             * @param <T> The type of the annotation.
3639
                             */
3640
                            @HashCodeAndEqualsPlugin.Enhance
3641
                            public static class OfDynamicInvocation<T extends Annotation> extends OffsetMapping.Factory.AbstractBase<T> {
3642

3643
                                /**
3644
                                 * The annotation type.
3645
                                 */
3646
                                private final Class<T> annotationType;
3647

3648
                                /**
3649
                                 * The bootstrap method to use.
3650
                                 */
3651
                                private final MethodDescription.InDefinedShape bootstrapMethod;
3652

3653
                                /**
3654
                                 * The constants to provide to the bootstrap method.
3655
                                 */
3656
                                private final List<? extends JavaConstant> arguments;
3657

3658
                                /**
3659
                                 * Creates a factory for an offset mapping that assigns the result of a dynamic method invocation.
3660
                                 *
3661
                                 * @param annotationType  The annotation type.
3662
                                 * @param bootstrapMethod The bootstrap method to use.
3663
                                 * @param arguments       The constants to provide to the bootstrap method.
3664
                                 */
3665
                                public OfDynamicInvocation(Class<T> annotationType, MethodDescription.InDefinedShape bootstrapMethod, List<? extends JavaConstant> arguments) {
×
3666
                                    this.annotationType = annotationType;
×
3667
                                    this.bootstrapMethod = bootstrapMethod;
×
3668
                                    this.arguments = arguments;
×
3669
                                }
×
3670

3671
                                /**
3672
                                 * {@inheritDoc}
3673
                                 */
3674
                                public Class<T> getAnnotationType() {
3675
                                    return annotationType;
×
3676
                                }
3677

3678
                                @Override
3679
                                protected OffsetMapping make(TypeDescription.Generic target, AnnotationDescription.Loadable<T> annotation) {
3680
                                    if (!target.isInterface()) {
×
3681
                                        throw new IllegalArgumentException(target + " is not an interface");
×
3682
                                    } else if (!target.getInterfaces().isEmpty()) {
×
3683
                                        throw new IllegalArgumentException(target + " must not extend other interfaces");
×
3684
                                    } else if (!target.isPublic()) {
×
3685
                                        throw new IllegalArgumentException(target + " is mot public");
×
3686
                                    }
3687
                                    MethodList<?> methodCandidates = target.getDeclaredMethods().filter(isAbstract());
×
3688
                                    if (methodCandidates.size() != 1) {
×
3689
                                        throw new IllegalArgumentException(target + " must declare exactly one abstract method");
×
3690
                                    }
3691
                                    return new OffsetMapping.ForStackManipulation(MethodInvocation.invoke(bootstrapMethod).dynamic(methodCandidates.getOnly().getInternalName(),
×
3692
                                            target.asErasure(),
×
3693
                                            Collections.<TypeDescription>emptyList(),
×
3694
                                            arguments), target, target);
3695
                                }
3696
                            }
3697

3698
                            /**
3699
                             * A factory to produce an offset mapping based upon a stack manipulation..
3700
                             *
3701
                             * @param <T> The type of the annotation.
3702
                             */
3703
                            @HashCodeAndEqualsPlugin.Enhance
3704
                            public static class Factory<T extends Annotation> extends OffsetMapping.Factory.AbstractBase<T> {
3705

3706
                                /**
3707
                                 * The annotation type.
3708
                                 */
3709
                                private final Class<T> annotationType;
3710

3711
                                /**
3712
                                 * The stack manipulation that produces the assigned value.
3713
                                 */
3714
                                private final StackManipulation stackManipulation;
3715

3716
                                /**
3717
                                 * The type of the value that is produced by the stack manipulation.
3718
                                 */
3719
                                private final TypeDescription.Generic typeDescription;
3720

3721
                                /**
3722
                                 * Creates a factory for a given constant value.
3723
                                 *
3724
                                 * @param annotationType The value to assign to the parameter.
3725
                                 * @param value          The value that is bound.
3726
                                 */
3727
                                public Factory(Class<T> annotationType, ConstantValue value) {
3728
                                    this(annotationType, value.toStackManipulation(), value.getTypeDescription().asGenericType());
×
3729
                                }
×
3730

3731
                                /**
3732
                                 * Creates a factory for a given stack manipulation.
3733
                                 *
3734
                                 * @param annotationType    The value to assign to the parameter.
3735
                                 * @param stackManipulation The stack manipulation that produces the assigned value.
3736
                                 * @param typeDescription   The type of the value that is produced by the stack manipulation.
3737
                                 */
3738
                                public Factory(Class<T> annotationType, StackManipulation stackManipulation, TypeDescription.Generic typeDescription) {
×
3739
                                    this.annotationType = annotationType;
×
3740
                                    this.stackManipulation = stackManipulation;
×
3741
                                    this.typeDescription = typeDescription;
×
3742
                                }
×
3743

3744
                                /**
3745
                                 * {@inheritDoc}
3746
                                 */
3747
                                public Class<T> getAnnotationType() {
3748
                                    return annotationType;
×
3749
                                }
3750

3751
                                @Override
3752
                                protected OffsetMapping make(TypeDescription.Generic target, AnnotationDescription.Loadable<T> annotation) {
3753
                                    return new ForStackManipulation(stackManipulation, typeDescription, target);
×
3754
                                }
3755
                            }
3756
                        }
3757

3758
                        /**
3759
                         * An offset mapping that assigns an argument of either the instrumented
3760
                         * method or the substituted expression.
3761
                         */
3762
                        @HashCodeAndEqualsPlugin.Enhance
3763
                        class ForArgument implements OffsetMapping {
3764

3765
                            /**
3766
                             * A description of the targeted type.
3767
                             */
3768
                            private final TypeDescription.Generic targetType;
3769

3770
                            /**
3771
                             * The index of the parameter.
3772
                             */
3773
                            private final int index;
3774

3775
                            /**
3776
                             * The typing to use or {@code null} if the global typing setting should be applied.
3777
                             */
3778
                            @MaybeNull
3779
                            @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
3780
                            private final Assigner.Typing typing;
3781

3782
                            /**
3783
                             * The source providing the argument.
3784
                             */
3785
                            private final Source source;
3786

3787
                            /**
3788
                             * {@code true} if {@code null} or a primitive {@code 0} should be assigned to the parameter
3789
                             * if the provided index is not available.
3790
                             */
3791
                            private final boolean optional;
3792

3793
                            /**
3794
                             * Creates a new offset mapping for an argument to either the substituted expression or the instrumented method.
3795
                             *
3796
                             * @param targetType A description of the targeted type.
3797
                             * @param index      The index of the parameter.
3798
                             * @param typing     The typing to use or {@code null} if the global typing setting should be applied.
3799
                             * @param source     The source providing the argument.
3800
                             * @param optional   {@code true} if {@code null} or a primitive {@code 0} should be assigned to the parameter
3801
                             *                   if the provided index is not available.
3802
                             */
3803
                            public ForArgument(TypeDescription.Generic targetType, int index, @MaybeNull Assigner.Typing typing, Source source, boolean optional) {
1✔
3804
                                this.targetType = targetType;
1✔
3805
                                this.index = index;
1✔
3806
                                this.typing = typing;
1✔
3807
                                this.source = source;
1✔
3808
                                this.optional = optional;
1✔
3809
                            }
1✔
3810

3811
                            /**
3812
                             * {@inheritDoc}
3813
                             */
3814
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
3815
                                return new ForArgument.Resolved(targetType, index, this.typing == null ? typing : this.typing, source, optional, assigner, instrumentedMethod);
1✔
3816
                            }
3817

3818
                            /**
3819
                             * A factory for creating an offset mapping for a parameter value of either the instrumented
3820
                             * method or the substituted element.
3821
                             */
3822
                            protected enum Factory implements OffsetMapping.Factory<Argument> {
1✔
3823

3824
                                /**
3825
                                 * The singleton instance.
3826
                                 */
3827
                                INSTANCE;
1✔
3828

3829
                                /**
3830
                                 * The {@link Argument#value()} property.
3831
                                 */
3832
                                private static final MethodDescription.InDefinedShape ARGUMENT_VALUE;
3833

3834
                                /**
3835
                                 * The {@link Argument#typing()} property.
3836
                                 */
3837
                                private static final MethodDescription.InDefinedShape ARGUMENT_TYPING;
3838

3839
                                /**
3840
                                 * The {@link Argument#source()} property.
3841
                                 */
3842
                                private static final MethodDescription.InDefinedShape ARGUMENT_SOURCE;
3843

3844
                                /**
3845
                                 * The {@link Argument#optional()} property.
3846
                                 */
3847
                                private static final MethodDescription.InDefinedShape ARGUMENT_OPTIONAL;
3848

3849
                                /*
3850
                                 * Resolves all annotation properties.
3851
                                 */
3852
                                static {
3853
                                    MethodList<MethodDescription.InDefinedShape> methods = net.bytebuddy.description.type.TypeDescription.ForLoadedType.of(Argument.class).getDeclaredMethods();
1✔
3854
                                    ARGUMENT_VALUE = methods.filter(named("value")).getOnly();
1✔
3855
                                    ARGUMENT_TYPING = methods.filter(named("typing")).getOnly();
1✔
3856
                                    ARGUMENT_SOURCE = methods.filter(named("source")).getOnly();
1✔
3857
                                    ARGUMENT_OPTIONAL = methods.filter(named("optional")).getOnly();
1✔
3858
                                }
1✔
3859

3860
                                /**
3861
                                 * {@inheritDoc}
3862
                                 */
3863
                                public Class<Argument> getAnnotationType() {
3864
                                    return Argument.class;
1✔
3865
                                }
3866

3867
                                /**
3868
                                 * {@inheritDoc}
3869
                                 */
3870
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<Argument> annotation) {
3871
                                    return new ForArgument(target.getDeclaringType().asGenericType(),
×
3872
                                            annotation.getValue(ARGUMENT_VALUE).resolve(Integer.class),
×
3873
                                            annotation.getValue(ARGUMENT_TYPING).resolve(EnumerationDescription.class).load(Assigner.Typing.class),
×
3874
                                            annotation.getValue(ARGUMENT_SOURCE).resolve(EnumerationDescription.class).load(Source.class),
×
3875
                                            annotation.getValue(ARGUMENT_OPTIONAL).resolve(Boolean.class));
×
3876
                                }
3877

3878
                                /**
3879
                                 * {@inheritDoc}
3880
                                 */
3881
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<Argument> annotation) {
3882
                                    int index = annotation.getValue(ARGUMENT_VALUE).resolve(Integer.class);
1✔
3883
                                    if (index < 0) {
1✔
3884
                                        throw new IllegalStateException("Cannot assign negative parameter index " + index + " for " + target);
×
3885
                                    }
3886
                                    return new ForArgument(target.getType(),
1✔
3887
                                            index,
3888
                                            annotation.getValue(ARGUMENT_TYPING).resolve(EnumerationDescription.class).load(Assigner.Typing.class),
1✔
3889
                                            annotation.getValue(ARGUMENT_SOURCE).resolve(EnumerationDescription.class).load(Source.class),
1✔
3890
                                            annotation.getValue(ARGUMENT_OPTIONAL).resolve(Boolean.class));
1✔
3891
                                }
3892
                            }
3893

3894
                            /**
3895
                             * A resolved offset mapping to the parameter of either the instrumented method or
3896
                             * the substituted element.
3897
                             */
3898
                            @HashCodeAndEqualsPlugin.Enhance
3899
                            protected static class Resolved implements OffsetMapping.Resolved {
3900

3901
                                /**
3902
                                 * The targeted type.
3903
                                 */
3904
                                private final TypeDescription.Generic targetType;
3905

3906
                                /**
3907
                                 * The index of the parameter.
3908
                                 */
3909
                                private final int index;
3910

3911
                                /**
3912
                                 * The typing to use when assigning.
3913
                                 */
3914
                                private final Assigner.Typing typing;
3915

3916
                                /**
3917
                                 * The source providing the argument.
3918
                                 */
3919
                                private final Source source;
3920

3921
                                /**
3922
                                 * {@code true} if {@code null} or a primitive {@code 0} should be assigned to the parameter
3923
                                 * if the provided index is not available.
3924
                                 */
3925
                                private final boolean optional;
3926

3927
                                /**
3928
                                 * The assigner to use.
3929
                                 */
3930
                                private final Assigner assigner;
3931

3932
                                /**
3933
                                 * The instrumented method.
3934
                                 */
3935
                                private final MethodDescription instrumentedMethod;
3936

3937
                                /**
3938
                                 * Creates a resolved offset mapping for assigning a parameter.
3939
                                 *
3940
                                 * @param targetType         The targeted type.
3941
                                 * @param index              The index of the parameter.
3942
                                 * @param typing             The typing to use when assigning.
3943
                                 * @param source             The source providing the argument.
3944
                                 * @param optional           {@code true} if {@code null} or a primitive {@code 0} should be assigned
3945
                                 *                           to the parameter if the provided index is not available.
3946
                                 * @param assigner           The assigner to use.
3947
                                 * @param instrumentedMethod The instrumented method.
3948
                                 */
3949
                                protected Resolved(TypeDescription.Generic targetType,
3950
                                                   int index,
3951
                                                   Assigner.Typing typing,
3952
                                                   Source source,
3953
                                                   boolean optional,
3954
                                                   Assigner assigner,
3955
                                                   MethodDescription instrumentedMethod) {
1✔
3956
                                    this.targetType = targetType;
1✔
3957
                                    this.index = index;
1✔
3958
                                    this.typing = typing;
1✔
3959
                                    this.source = source;
1✔
3960
                                    this.optional = optional;
1✔
3961
                                    this.assigner = assigner;
1✔
3962
                                    this.instrumentedMethod = instrumentedMethod;
1✔
3963
                                }
1✔
3964

3965
                                /**
3966
                                 * {@inheritDoc}
3967
                                 */
3968
                                public StackManipulation apply(Target target,
3969
                                                               TypeList.Generic parameters,
3970
                                                               TypeDescription.Generic result,
3971
                                                               TypeDescription.Generic current,
3972
                                                               JavaConstant.MethodHandle methodHandle,
3973
                                                               Map<Integer, Integer> offsets,
3974
                                                               int offset) {
3975
                                    Source.Value value = source.argument(index, parameters, offsets, target, instrumentedMethod);
1✔
3976
                                    if (value != null) {
1✔
3977
                                        StackManipulation assignment = assigner.assign(value.getTypeDescription(), targetType, typing);
1✔
3978
                                        if (!assignment.isValid()) {
1✔
3979
                                            throw new IllegalStateException("Cannot assign " + value.getTypeDescription() + " to " + targetType);
×
3980
                                        }
3981
                                        return new StackManipulation.Compound(MethodVariableAccess.of(value.getTypeDescription()).loadFrom(value.getOffset()), assignment);
1✔
3982
                                    } else if (optional) {
1✔
3983
                                        return DefaultValue.of(targetType);
1✔
3984
                                    } else {
3985
                                        throw new IllegalStateException("No argument with index " + index + " available for " + target);
1✔
3986
                                    }
3987
                                }
3988
                            }
3989
                        }
3990

3991
                        /**
3992
                         * An offset mapping that assigns the {@code this} reference.
3993
                         */
3994
                        @HashCodeAndEqualsPlugin.Enhance
3995
                        class ForThisReference implements OffsetMapping {
3996

3997
                            /**
3998
                             * The targeted type.
3999
                             */
4000
                            private final TypeDescription.Generic targetType;
4001

4002
                            /**
4003
                             * The typing to use or {@code null} if implicit typing.
4004
                             */
4005
                            @MaybeNull
4006
                            @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
4007
                            private final Assigner.Typing typing;
4008

4009
                            /**
4010
                             * The source providing the reference.
4011
                             */
4012
                            private final Source source;
4013

4014
                            /**
4015
                             * {@code true} if {@code null} or a primitive {@code 0} should be assigned to the parameter
4016
                             * if no {@code this} reference is available.
4017
                             */
4018
                            private final boolean optional;
4019

4020
                            /**
4021
                             * Creates an offset mapping that resolves the {@code this} reference.
4022
                             *
4023
                             * @param targetType The targeted type.
4024
                             * @param typing     The typing to use or {@code null} if implicit typing.
4025
                             * @param source     The source providing the reference.
4026
                             * @param optional   {@code true} if {@code null} or a primitive {@code 0} should be assigned
4027
                             *                   to the parameter if no {@code this} reference is available.
4028
                             */
4029
                            public ForThisReference(TypeDescription.Generic targetType, @MaybeNull Assigner.Typing typing, Source source, boolean optional) {
1✔
4030
                                this.targetType = targetType;
1✔
4031
                                this.typing = typing;
1✔
4032
                                this.source = source;
1✔
4033
                                this.optional = optional;
1✔
4034
                            }
1✔
4035

4036
                            /**
4037
                             * {@inheritDoc}
4038
                             */
4039
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
4040
                                return new ForThisReference.Resolved(targetType, this.typing == null ? typing : this.typing, source, optional, assigner, instrumentedMethod);
1✔
4041
                            }
4042

4043
                            /**
4044
                             * A resolved offset mapping for resolving the {@code this} reference.
4045
                             */
4046
                            @HashCodeAndEqualsPlugin.Enhance
4047
                            protected static class Resolved implements OffsetMapping.Resolved {
4048

4049
                                /**
4050
                                 * The targeted type.
4051
                                 */
4052
                                private final TypeDescription.Generic targetType;
4053

4054
                                /**
4055
                                 * The typing to use..
4056
                                 */
4057
                                private final Assigner.Typing typing;
4058

4059
                                /**
4060
                                 * The source providing the reference.
4061
                                 */
4062
                                private final Source source;
4063

4064
                                /**
4065
                                 * {@code true} if {@code null} or a primitive {@code 0} should be assigned to the parameter
4066
                                 * if no {@code this} reference is available.
4067
                                 */
4068
                                private final boolean optional;
4069

4070
                                /**
4071
                                 * The assigner to use.
4072
                                 */
4073
                                private final Assigner assigner;
4074

4075
                                /**
4076
                                 * The instrumented method.
4077
                                 */
4078
                                private final MethodDescription instrumentedMethod;
4079

4080
                                /**
4081
                                 * Creates a resolved offset mapping for assigning the {@code this} reference.
4082
                                 *
4083
                                 * @param targetType         The targeted type.
4084
                                 * @param typing             The typing to use.
4085
                                 * @param source             The source providing the reference.
4086
                                 * @param optional           {@code true} if {@code null} or a primitive {@code 0} should be assigned
4087
                                 *                           to the parameter if no {@code this} reference is available.
4088
                                 * @param assigner           The assigner to use.
4089
                                 * @param instrumentedMethod The instrumented method.
4090
                                 */
4091
                                protected Resolved(TypeDescription.Generic targetType,
4092
                                                   Assigner.Typing typing,
4093
                                                   Source source,
4094
                                                   boolean optional,
4095
                                                   Assigner assigner,
4096
                                                   MethodDescription instrumentedMethod) {
1✔
4097
                                    this.targetType = targetType;
1✔
4098
                                    this.typing = typing;
1✔
4099
                                    this.source = source;
1✔
4100
                                    this.optional = optional;
1✔
4101
                                    this.assigner = assigner;
1✔
4102
                                    this.instrumentedMethod = instrumentedMethod;
1✔
4103
                                }
1✔
4104

4105
                                /**
4106
                                 * {@inheritDoc}
4107
                                 */
4108
                                public StackManipulation apply(Target target,
4109
                                                               TypeList.Generic parameters,
4110
                                                               TypeDescription.Generic result,
4111
                                                               TypeDescription.Generic current,
4112
                                                               JavaConstant.MethodHandle methodHandle,
4113
                                                               Map<Integer, Integer> offsets,
4114
                                                               int offset) {
4115
                                    Source.Value value = source.self(parameters, offsets, target, instrumentedMethod);
1✔
4116
                                    if (value != null) {
1✔
4117
                                        StackManipulation assignment = assigner.assign(value.getTypeDescription(), targetType, typing);
1✔
4118
                                        if (!assignment.isValid()) {
1✔
4119
                                            throw new IllegalStateException("Cannot assign " + value.getTypeDescription() + " to " + targetType);
×
4120
                                        }
4121
                                        return new StackManipulation.Compound(MethodVariableAccess.of(value.getTypeDescription()).loadFrom(value.getOffset()), assignment);
1✔
4122
                                    } else if (optional) {
1✔
4123
                                        return DefaultValue.of(targetType);
1✔
4124
                                    } else {
4125
                                        throw new IllegalStateException("No this reference available for " + target);
1✔
4126
                                    }
4127
                                }
4128
                            }
4129

4130
                            /**
4131
                             * A factory for creating an offset mapping for binding a {@link This} reference.
4132
                             */
4133
                            protected enum Factory implements OffsetMapping.Factory<This> {
1✔
4134

4135
                                /**
4136
                                 * The singleton instance.
4137
                                 */
4138
                                INSTANCE;
1✔
4139

4140
                                /**
4141
                                 * The {@link This#typing()} property.
4142
                                 */
4143
                                private static final MethodDescription.InDefinedShape THIS_TYPING;
4144

4145
                                /**
4146
                                 * The {@link This#source()} reference.
4147
                                 */
4148
                                private static final MethodDescription.InDefinedShape THIS_SOURCE;
4149

4150
                                /**
4151
                                 * The {@link This#optional()} property.
4152
                                 */
4153
                                private static final MethodDescription.InDefinedShape THIS_OPTIONAL;
4154

4155
                                /*
4156
                                 * Resolves the annotation properties.
4157
                                 */
4158
                                static {
4159
                                    MethodList<MethodDescription.InDefinedShape> methods = net.bytebuddy.description.type.TypeDescription.ForLoadedType.of(This.class).getDeclaredMethods();
1✔
4160
                                    THIS_TYPING = methods.filter(named("typing")).getOnly();
1✔
4161
                                    THIS_SOURCE = methods.filter(named("source")).getOnly();
1✔
4162
                                    THIS_OPTIONAL = methods.filter(named("optional")).getOnly();
1✔
4163
                                }
1✔
4164

4165
                                /**
4166
                                 * {@inheritDoc}
4167
                                 */
4168
                                public Class<This> getAnnotationType() {
4169
                                    return This.class;
1✔
4170
                                }
4171

4172
                                /**
4173
                                 * {@inheritDoc}
4174
                                 */
4175
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<This> annotation) {
4176
                                    return new ForThisReference(target.getDeclaringType().asGenericType(),
×
4177
                                            annotation.getValue(THIS_TYPING).resolve(EnumerationDescription.class).load(Assigner.Typing.class),
×
4178
                                            annotation.getValue(THIS_SOURCE).resolve(EnumerationDescription.class).load(Source.class),
×
4179
                                            annotation.getValue(THIS_OPTIONAL).resolve(Boolean.class));
×
4180
                                }
4181

4182
                                /**
4183
                                 * {@inheritDoc}
4184
                                 */
4185
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<This> annotation) {
4186
                                    return new ForThisReference(target.getType(),
1✔
4187
                                            annotation.getValue(THIS_TYPING).resolve(EnumerationDescription.class).load(Assigner.Typing.class),
1✔
4188
                                            annotation.getValue(THIS_SOURCE).resolve(EnumerationDescription.class).load(Source.class),
1✔
4189
                                            annotation.getValue(THIS_OPTIONAL).resolve(Boolean.class));
1✔
4190
                                }
4191
                            }
4192
                        }
4193

4194
                        /**
4195
                         * An offset mapping that assigns an array containing all arguments to the annotated parameter.
4196
                         */
4197
                        @HashCodeAndEqualsPlugin.Enhance
4198
                        class ForAllArguments implements OffsetMapping {
4199

4200
                            /**
4201
                             * The component type of the annotated parameter.
4202
                             */
4203
                            private final TypeDescription.Generic targetComponentType;
4204

4205
                            /**
4206
                             * The typing to use or {@code null} if implicit typing.
4207
                             */
4208
                            @MaybeNull
4209
                            @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
4210
                            private final Assigner.Typing typing;
4211

4212
                            /**
4213
                             * The source providing the reference.
4214
                             */
4215
                            private final Source source;
4216

4217
                            /**
4218
                             * {@code true} if the {@code this} reference should be included in the created array, if available.
4219
                             */
4220
                            private final boolean includeSelf;
4221

4222
                            /**
4223
                             * {@code true} if {@code null} should be assigned to the parameter if no arguments are available.
4224
                             */
4225
                            private final boolean nullIfEmpty;
4226

4227
                            /**
4228
                             * Creates a new offset mapping for an array containing all supplied arguments.
4229
                             *
4230
                             * @param targetComponentType The component type of the annotated parameter.
4231
                             * @param typing              The typing to use or {@code null} if implicit typing.
4232
                             * @param source              The source providing the reference.
4233
                             * @param includeSelf         {@code true} if the {@code this} reference should be included in the created array, if available.
4234
                             * @param nullIfEmpty         {@code true} if {@code null} should be assigned to the parameter if no arguments are available.
4235
                             */
4236
                            public ForAllArguments(TypeDescription.Generic targetComponentType, @MaybeNull Assigner.Typing typing, Source source, boolean includeSelf, boolean nullIfEmpty) {
1✔
4237
                                this.targetComponentType = targetComponentType;
1✔
4238
                                this.typing = typing;
1✔
4239
                                this.source = source;
1✔
4240
                                this.includeSelf = includeSelf;
1✔
4241
                                this.nullIfEmpty = nullIfEmpty;
1✔
4242
                            }
1✔
4243

4244
                            /**
4245
                             * {@inheritDoc}
4246
                             */
4247
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
4248
                                return new ForAllArguments.Resolved(targetComponentType, this.typing == null ? typing : this.typing, source, includeSelf, nullIfEmpty, assigner, instrumentedMethod);
1✔
4249
                            }
4250

4251
                            /**
4252
                             * A factory for creating an offset mapping containing all supplies arguments.
4253
                             */
4254
                            protected enum Factory implements OffsetMapping.Factory<AllArguments> {
1✔
4255

4256
                                /**
4257
                                 * The singleton instance.
4258
                                 */
4259
                                INSTANCE;
1✔
4260

4261
                                /**
4262
                                 * The {@link AllArguments#typing()} property.
4263
                                 */
4264
                                private static final MethodDescription.InDefinedShape ALL_ARGUMENTS_TYPING;
4265

4266
                                /**
4267
                                 * The {@link AllArguments#source()} property.
4268
                                 */
4269
                                private static final MethodDescription.InDefinedShape ALL_ARGUMENTS_SOURCE;
4270

4271
                                /**
4272
                                 * The {@link AllArguments#includeSelf()} property.
4273
                                 */
4274
                                private static final MethodDescription.InDefinedShape ALL_ARGUMENTS_INCLUDE_SELF;
4275

4276
                                /**
4277
                                 * The {@link AllArguments#nullIfEmpty()} property.
4278
                                 */
4279
                                private static final MethodDescription.InDefinedShape ALL_ARGUMENTS_NULL_IF_EMPTY;
4280

4281
                                /*
4282
                                 * Resolves all annotation properties.
4283
                                 */
4284
                                static {
4285
                                    MethodList<MethodDescription.InDefinedShape> methods = TypeDescription.ForLoadedType.of(AllArguments.class).getDeclaredMethods();
1✔
4286
                                    ALL_ARGUMENTS_TYPING = methods.filter(named("typing")).getOnly();
1✔
4287
                                    ALL_ARGUMENTS_SOURCE = methods.filter(named("source")).getOnly();
1✔
4288
                                    ALL_ARGUMENTS_INCLUDE_SELF = methods.filter(named("includeSelf")).getOnly();
1✔
4289
                                    ALL_ARGUMENTS_NULL_IF_EMPTY = methods.filter(named("nullIfEmpty")).getOnly();
1✔
4290
                                }
1✔
4291

4292
                                /**
4293
                                 * {@inheritDoc}
4294
                                 */
4295
                                public Class<AllArguments> getAnnotationType() {
4296
                                    return AllArguments.class;
1✔
4297
                                }
4298

4299
                                /**
4300
                                 * {@inheritDoc}
4301
                                 */
4302
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<AllArguments> annotation) {
4303
                                    throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
4304
                                }
4305

4306
                                /**
4307
                                 * {@inheritDoc}
4308
                                 */
4309
                                @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.")
4310
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<AllArguments> annotation) {
4311
                                    if (!target.getType().isArray()) {
1✔
4312
                                        throw new IllegalStateException("Expected array as parameter type for " + target);
1✔
4313
                                    }
4314
                                    return new ForAllArguments(target.getType().getComponentType(),
1✔
4315
                                            annotation.getValue(ALL_ARGUMENTS_TYPING).resolve(EnumerationDescription.class).load(Assigner.Typing.class),
1✔
4316
                                            annotation.getValue(ALL_ARGUMENTS_SOURCE).resolve(EnumerationDescription.class).load(Source.class),
1✔
4317
                                            annotation.getValue(ALL_ARGUMENTS_INCLUDE_SELF).resolve(Boolean.class),
1✔
4318
                                            annotation.getValue(ALL_ARGUMENTS_NULL_IF_EMPTY).resolve(Boolean.class));
1✔
4319
                                }
4320
                            }
4321

4322
                            /**
4323
                             * A resolves offset mapping for an array containing all arguments.
4324
                             */
4325
                            @HashCodeAndEqualsPlugin.Enhance
4326
                            protected static class Resolved implements OffsetMapping.Resolved {
4327

4328
                                /**
4329
                                 * The component type of the annotated parameter.
4330
                                 */
4331
                                private final TypeDescription.Generic targetComponentType;
4332

4333
                                /**
4334
                                 * The typing to use.
4335
                                 */
4336
                                private final Assigner.Typing typing;
4337

4338
                                /**
4339
                                 * The source providing the reference.
4340
                                 */
4341
                                private final Source source;
4342

4343
                                /**
4344
                                 * {@code true} if the {@code this} reference should be included in the created array, if available.
4345
                                 */
4346
                                private final boolean includeSelf;
4347

4348
                                /**
4349
                                 * {@code true} if {@code null} should be assigned to the parameter if no arguments are available.
4350
                                 */
4351
                                private final boolean nullIfEmpty;
4352

4353
                                /**
4354
                                 * The assigner to use.
4355
                                 */
4356
                                private final Assigner assigner;
4357

4358
                                /**
4359
                                 * The instrumented method.
4360
                                 */
4361
                                private final MethodDescription instrumentedMethod;
4362

4363
                                /**
4364
                                 * Creates a resolved version for an offset mapping of all arguments.
4365
                                 *
4366
                                 * @param targetComponentType The component type of the annotated parameter.
4367
                                 * @param typing              The typing to use.
4368
                                 * @param source              The source providing the reference.
4369
                                 * @param includeSelf         {@code true} if the {@code this} reference should be included in the created array, if available.
4370
                                 * @param nullIfEmpty         {@code true} if {@code null} should be assigned to the parameter if no arguments are available.
4371
                                 * @param assigner            The assigner to use.
4372
                                 * @param instrumentedMethod  The instrumented method.
4373
                                 */
4374
                                protected Resolved(TypeDescription.Generic targetComponentType,
4375
                                                   Assigner.Typing typing,
4376
                                                   Source source,
4377
                                                   boolean includeSelf,
4378
                                                   boolean nullIfEmpty,
4379
                                                   Assigner assigner,
4380
                                                   MethodDescription instrumentedMethod) {
1✔
4381
                                    this.targetComponentType = targetComponentType;
1✔
4382
                                    this.typing = typing;
1✔
4383
                                    this.source = source;
1✔
4384
                                    this.includeSelf = includeSelf;
1✔
4385
                                    this.nullIfEmpty = nullIfEmpty;
1✔
4386
                                    this.assigner = assigner;
1✔
4387
                                    this.instrumentedMethod = instrumentedMethod;
1✔
4388
                                }
1✔
4389

4390
                                /**
4391
                                 * {@inheritDoc}
4392
                                 */
4393
                                public StackManipulation apply(Target target,
4394
                                                               TypeList.Generic parameters,
4395
                                                               TypeDescription.Generic result,
4396
                                                               TypeDescription.Generic current,
4397
                                                               JavaConstant.MethodHandle methodHandle,
4398
                                                               Map<Integer, Integer> offsets,
4399
                                                               int offset) {
4400
                                    List<Source.Value> values = source.arguments(includeSelf, parameters, offsets, target, instrumentedMethod);
1✔
4401
                                    if (nullIfEmpty && values.isEmpty()) {
1✔
4402
                                        return NullConstant.INSTANCE;
1✔
4403
                                    } else {
4404
                                        List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>();
1✔
4405
                                        for (Source.Value value : values) {
1✔
4406
                                            StackManipulation assignment = assigner.assign(value.getTypeDescription(), targetComponentType, typing);
1✔
4407
                                            if (!assignment.isValid()) {
1✔
4408
                                                throw new IllegalStateException("Cannot assign " + value.getTypeDescription() + " to " + targetComponentType);
×
4409
                                            }
4410
                                            stackManipulations.add(new StackManipulation.Compound(MethodVariableAccess.of(value.getTypeDescription()).loadFrom(value.getOffset()), assignment));
1✔
4411
                                        }
1✔
4412
                                        return ArrayFactory.forType(targetComponentType).withValues(stackManipulations);
1✔
4413
                                    }
4414
                                }
4415
                            }
4416
                        }
4417

4418
                        /**
4419
                         * An offset mapping resolving a method handle to invoke the original expression or the instrumented method.
4420
                         */
4421
                        @HashCodeAndEqualsPlugin.Enhance
4422
                        class ForSelfCallHandle implements OffsetMapping {
4423

4424
                            /**
4425
                             * The source providing the reference.
4426
                             */
4427
                            private final Source source;
4428

4429
                            /**
4430
                             * {@code true} if the handle should be bound to the original arguments.
4431
                             */
4432
                            private final boolean bound;
4433

4434
                            /**
4435
                             * Creates a new offset mapping for a self call handle.
4436
                             *
4437
                             * @param source The source providing the reference.
4438
                             * @param bound  {@code true} if the handle should be bound to the original arguments.
4439
                             */
4440
                            public ForSelfCallHandle(Source source, boolean bound) {
×
4441
                                this.source = source;
×
4442
                                this.bound = bound;
×
4443
                            }
×
4444

4445
                            /**
4446
                             * {@inheritDoc}
4447
                             */
4448
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
4449
                                return bound ? new ForSelfCallHandle.Bound(source, instrumentedMethod) : new ForSelfCallHandle.Unbound(source, instrumentedMethod);
×
4450
                            }
4451

4452
                            /**
4453
                             * A factory for creating an offset mapping for binding a self call handle.
4454
                             */
4455
                            protected enum Factory implements OffsetMapping.Factory<SelfCallHandle> {
1✔
4456

4457
                                /**
4458
                                 * The singleton instance.
4459
                                 */
4460
                                INSTANCE;
1✔
4461

4462
                                /**
4463
                                 * The {@link SelfCallHandle#source()} property.
4464
                                 */
4465
                                private static final MethodDescription.InDefinedShape SELF_CALL_HANDLE_SOURCE;
4466

4467
                                /**
4468
                                 * The {@link SelfCallHandle#bound()} property.
4469
                                 */
4470
                                private static final MethodDescription.InDefinedShape SELF_CALL_HANDLE_BOUND;
4471

4472
                                /*
4473
                                 * Resolves all annotation properties.
4474
                                 */
4475
                                static {
4476
                                    MethodList<MethodDescription.InDefinedShape> methods = TypeDescription.ForLoadedType.of(SelfCallHandle.class).getDeclaredMethods();
1✔
4477
                                    SELF_CALL_HANDLE_SOURCE = methods.filter(named("source")).getOnly();
1✔
4478
                                    SELF_CALL_HANDLE_BOUND = methods.filter(named("bound")).getOnly();
1✔
4479
                                }
1✔
4480

4481
                                /**
4482
                                 * {@inheritDoc}
4483
                                 */
4484
                                public Class<SelfCallHandle> getAnnotationType() {
4485
                                    return SelfCallHandle.class;
1✔
4486
                                }
4487

4488
                                /**
4489
                                 * {@inheritDoc}
4490
                                 */
4491
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<SelfCallHandle> annotation) {
4492
                                    throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
4493
                                }
4494

4495
                                /**
4496
                                 * {@inheritDoc}
4497
                                 */
4498
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<SelfCallHandle> annotation) {
4499
                                    if (!target.getType().asErasure().isAssignableFrom(JavaType.METHOD_HANDLE.getTypeStub())) {
×
4500
                                        throw new IllegalStateException("Cannot assign method handle to " + target);
×
4501
                                    }
4502
                                    return new ForSelfCallHandle(
×
4503
                                            annotation.getValue(SELF_CALL_HANDLE_SOURCE).resolve(EnumerationDescription.class).load(Source.class),
×
4504
                                            annotation.getValue(SELF_CALL_HANDLE_BOUND).resolve(Boolean.class));
×
4505
                                }
4506
                            }
4507

4508
                            /**
4509
                             * Resolves a bound self call handle for an offset mapping.
4510
                             */
4511
                            @HashCodeAndEqualsPlugin.Enhance
4512
                            protected static class Bound implements OffsetMapping.Resolved {
4513

4514
                                /**
4515
                                 * The source providing the reference.
4516
                                 */
4517
                                private final Source source;
4518

4519
                                /**
4520
                                 * The instrumented method.
4521
                                 */
4522
                                private final MethodDescription instrumentedMethod;
4523

4524
                                /**
4525
                                 * Creates an offset mapping for a bound version of a self call handle.
4526
                                 *
4527
                                 * @param source             The source providing the reference.
4528
                                 * @param instrumentedMethod The instrumented method.
4529
                                 */
4530
                                protected Bound(Source source, MethodDescription instrumentedMethod) {
×
4531
                                    this.source = source;
×
4532
                                    this.instrumentedMethod = instrumentedMethod;
×
4533
                                }
×
4534

4535
                                /**
4536
                                 * {@inheritDoc}
4537
                                 */
4538
                                public StackManipulation apply(Target target,
4539
                                                               TypeList.Generic parameters,
4540
                                                               TypeDescription.Generic result,
4541
                                                               TypeDescription.Generic current,
4542
                                                               JavaConstant.MethodHandle methodHandle,
4543
                                                               Map<Integer, Integer> offsets,
4544
                                                               int offset) {
4545
                                    Source.Value dispatched = source.self(parameters, offsets, target, instrumentedMethod);
×
4546
                                    List<Source.Value> values = source.arguments(false, parameters, offsets, target, instrumentedMethod);
×
4547
                                    List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(1 + (values.size()
×
4548
                                            + (dispatched == null ? 0 : 2))
4549
                                            + (values.isEmpty() ? 0 : 1));
×
4550
                                    stackManipulations.add(source.handle(methodHandle, instrumentedMethod).toStackManipulation());
×
4551
                                    if (dispatched != null) {
×
4552
                                        stackManipulations.add(MethodVariableAccess.of(dispatched.getTypeDescription()).loadFrom(dispatched.getOffset()));
×
4553
                                        stackManipulations.add(MethodInvocation.invoke(new MethodDescription.Latent(JavaType.METHOD_HANDLE.getTypeStub(), new MethodDescription.Token("bindTo",
×
4554
                                                Opcodes.ACC_PUBLIC,
4555
                                                JavaType.METHOD_HANDLE.getTypeStub().asGenericType(),
×
4556
                                                new TypeList.Generic.Explicit(TypeDefinition.Sort.describe(Object.class))))));
×
4557
                                    }
4558
                                    if (!values.isEmpty()) {
×
4559
                                        for (Source.Value value : values) {
×
4560
                                            stackManipulations.add(MethodVariableAccess.of(value.getTypeDescription()).loadFrom(value.getOffset()));
×
4561
                                        }
×
4562
                                        stackManipulations.add(MethodInvocation.invoke(new MethodDescription.Latent(JavaType.METHOD_HANDLES.getTypeStub(), new MethodDescription.Token("insertArguments",
×
4563
                                                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
4564
                                                JavaType.METHOD_HANDLE.getTypeStub().asGenericType(),
×
4565
                                                new TypeList.Generic.Explicit(JavaType.METHOD_HANDLE.getTypeStub(), TypeDefinition.Sort.describe(int.class), TypeDefinition.Sort.describe(Object[].class))))));
×
4566
                                    }
4567
                                    return new StackManipulation.Compound(stackManipulations);
×
4568
                                }
4569
                            }
4570

4571
                            /**
4572
                             * Resolves an unbound self call handle for an offset mapping.
4573
                             */
4574
                            @HashCodeAndEqualsPlugin.Enhance
4575
                            protected static class Unbound implements OffsetMapping.Resolved {
4576

4577
                                /**
4578
                                 * The source providing the reference.
4579
                                 */
4580
                                private final Source source;
4581

4582
                                /**
4583
                                 * The instrumented method.
4584
                                 */
4585
                                private final MethodDescription instrumentedMethod;
4586

4587
                                /**
4588
                                 * Creates an offset mapping for an unbound version of a self call handle.
4589
                                 *
4590
                                 * @param source             The source providing the reference.
4591
                                 * @param instrumentedMethod The instrumented method.
4592
                                 */
4593
                                protected Unbound(Source source, MethodDescription instrumentedMethod) {
×
4594
                                    this.source = source;
×
4595
                                    this.instrumentedMethod = instrumentedMethod;
×
4596
                                }
×
4597

4598
                                /**
4599
                                 * {@inheritDoc}
4600
                                 */
4601
                                public StackManipulation apply(Target target,
4602
                                                               TypeList.Generic parameters,
4603
                                                               TypeDescription.Generic result,
4604
                                                               TypeDescription.Generic current,
4605
                                                               JavaConstant.MethodHandle methodHandle,
4606
                                                               Map<Integer, Integer> offsets,
4607
                                                               int offset) {
4608
                                    return source.handle(methodHandle, instrumentedMethod).toStackManipulation();
×
4609
                                }
4610
                            }
4611
                        }
4612

4613
                        /**
4614
                         * An offset mapping that resolves a method handle.
4615
                         */
4616
                        @HashCodeAndEqualsPlugin.Enhance
4617
                        class ForHandle implements OffsetMapping {
4618

4619
                            /**
4620
                             * The type of the method handle.
4621
                             */
4622
                            private final JavaConstant.MethodHandle.HandleType type;
4623

4624
                            /**
4625
                             * The owner of the handle, or {@code void} for the instrumented type.
4626
                             */
4627
                            private final TypeDescription owner;
4628

4629
                            /**
4630
                             * The name of the method handle.
4631
                             */
4632
                            private final String name;
4633

4634
                            /**
4635
                             * The type that is returned from the handle.
4636
                             */
4637
                            private final TypeDescription returnType;
4638

4639
                            /**
4640
                             * The parameter types required by the handle.
4641
                             */
4642
                            private final List<? extends TypeDescription> parameterTypes;
4643

4644
                            /**
4645
                             * Creates an offset mapping for a method handle.
4646
                             *
4647
                             * @param type           The type of the method handle.
4648
                             * @param owner          The owner of the handle, or {@code void} for the instrumented type.
4649
                             * @param name           The name of the method handle.
4650
                             * @param returnType     The type that is returned from the handle.
4651
                             * @param parameterTypes The parameter types required by the handle.
4652
                             */
4653
                            protected ForHandle(JavaConstant.MethodHandle.HandleType type,
4654
                                                TypeDescription owner,
4655
                                                String name,
4656
                                                TypeDescription returnType,
4657
                                                List<? extends TypeDescription> parameterTypes) {
×
4658
                                this.type = type;
×
4659
                                this.owner = owner;
×
4660
                                this.name = name;
×
4661
                                this.returnType = returnType;
×
4662
                                this.parameterTypes = parameterTypes;
×
4663
                            }
×
4664

4665
                            /**
4666
                             * {@inheritDoc}
4667
                             */
4668
                            public Resolved resolve(Assigner assigner,
4669
                                                    Assigner.Typing typing,
4670
                                                    TypeDescription instrumentedType,
4671
                                                    MethodDescription instrumentedMethod) {
4672
                                return new Resolved.ForStackManipulation(new JavaConstantValue(new JavaConstant.MethodHandle(type,
×
4673
                                        owner.represents(void.class) ? instrumentedType : owner,
×
4674
                                        name,
4675
                                        returnType,
4676
                                        parameterTypes)));
4677
                            }
4678

4679
                            /**
4680
                             * A factory to create an offset mapping for a method handle.
4681
                             */
4682
                            protected enum Factory implements OffsetMapping.Factory<Handle> {
1✔
4683

4684
                                /**
4685
                                 * The singleton instance.
4686
                                 */
4687
                                INSTANCE;
1✔
4688

4689
                                /**
4690
                                 * The {@link Handle#type()} method.
4691
                                 */
4692
                                private static final MethodDescription.InDefinedShape HANDLE_TYPE;
4693

4694
                                /**
4695
                                 * The {@link Handle#owner()} method.
4696
                                 */
4697
                                private static final MethodDescription.InDefinedShape HANDLE_OWNER;
4698

4699
                                /**
4700
                                 * The {@link Handle#name()} method.
4701
                                 */
4702
                                private static final MethodDescription.InDefinedShape HANDLE_NAME;
4703

4704
                                /**
4705
                                 * The {@link Handle#returnType()} method.
4706
                                 */
4707
                                private static final MethodDescription.InDefinedShape HANDLE_RETURN_TYPE;
4708

4709
                                /**
4710
                                 * The {@link Handle#parameterTypes()} method.
4711
                                 */
4712
                                private static final MethodDescription.InDefinedShape HANDLE_PARAMETER_TYPES;
4713

4714
                                /*
4715
                                 * Resolves all annotation properties.
4716
                                 */
4717
                                static {
4718
                                    MethodList<MethodDescription.InDefinedShape> methods = TypeDescription.ForLoadedType.of(Handle.class).getDeclaredMethods();
1✔
4719
                                    HANDLE_TYPE = methods.filter(named("type")).getOnly();
1✔
4720
                                    HANDLE_OWNER = methods.filter(named("owner")).getOnly();
1✔
4721
                                    HANDLE_NAME = methods.filter(named("name")).getOnly();
1✔
4722
                                    HANDLE_RETURN_TYPE = methods.filter(named("returnType")).getOnly();
1✔
4723
                                    HANDLE_PARAMETER_TYPES = methods.filter(named("parameterTypes")).getOnly();
1✔
4724
                                }
1✔
4725

4726
                                /**
4727
                                 * {@inheritDoc}
4728
                                 */
4729
                                public Class<Handle> getAnnotationType() {
4730
                                    return Handle.class;
1✔
4731
                                }
4732

4733
                                /**
4734
                                 * {@inheritDoc}
4735
                                 */
4736
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<Handle> annotation) {
4737
                                    throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
4738
                                }
4739

4740
                                /**
4741
                                 * {@inheritDoc}
4742
                                 */
4743
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<Handle> annotation) {
4744
                                    if (!target.getType().asErasure().isAssignableFrom(JavaType.METHOD_HANDLE.getTypeStub())) {
×
4745
                                        throw new IllegalStateException("Cannot assign method handle to " + target);
×
4746
                                    }
4747
                                    return new ForHandle(
×
4748
                                            annotation.getValue(HANDLE_TYPE).resolve(EnumerationDescription.class).load(JavaConstant.MethodHandle.HandleType.class),
×
4749
                                            annotation.getValue(HANDLE_OWNER).resolve(TypeDescription.class),
×
4750
                                            annotation.getValue(HANDLE_NAME).resolve(String.class),
×
4751
                                            annotation.getValue(HANDLE_RETURN_TYPE).resolve(TypeDescription.class),
×
4752
                                            Arrays.asList(annotation.getValue(HANDLE_PARAMETER_TYPES).resolve(TypeDescription[].class)));
×
4753
                                }
4754
                            }
4755
                        }
4756

4757
                        /**
4758
                         * An offset mapping for a dynamic constant.
4759
                         */
4760
                        @HashCodeAndEqualsPlugin.Enhance
4761
                        class ForDynamicConstant implements OffsetMapping {
4762

4763
                            /**
4764
                             * The name of the dynamic constant.
4765
                             */
4766
                            private final String name;
4767

4768
                            /**
4769
                             * The type of the dynamic constant.
4770
                             */
4771
                            private final TypeDescription typeDescription;
4772

4773
                            /**
4774
                             * The type of the bootstrap method.
4775
                             */
4776
                            private final JavaConstant.MethodHandle.HandleType bootstrapType;
4777

4778
                            /**
4779
                             * The type that declares the bootstrap method, or {@code void} if the instrumented type.
4780
                             */
4781
                            private final TypeDescription bootstrapOwner;
4782

4783
                            /**
4784
                             * The name of the bootstrap method.
4785
                             */
4786
                            private final String bootstrapName;
4787

4788
                            /**
4789
                             * The return type of the boostrap method.
4790
                             */
4791
                            private final TypeDescription bootstrapReturnType;
4792

4793
                            /**
4794
                             * The parameter types of the boostrap method.
4795
                             */
4796
                            private final List<? extends TypeDescription> bootstrapParameterTypes;
4797

4798
                            /**
4799
                             * The constant arguments to the bootstrap method.
4800
                             */
4801
                            private final List<JavaConstant> arguments;
4802

4803
                            /**
4804
                             * {@code true} if invokedynamic should be used to bind the constant.
4805
                             */
4806
                            private final boolean invokedynamic;
4807

4808
                            /**
4809
                             * Creates an offset mapping for a dynamic constant.
4810
                             *
4811
                             * @param name                    The name of the dynamic constant.
4812
                             * @param typeDescription         The type of the dynamic constant.
4813
                             * @param bootstrapType           The type of the bootstrap method.
4814
                             * @param bootstrapOwner          The type that declares the bootstrap method, or {@code void} if the instrumented type.
4815
                             * @param bootstrapName           The name of the bootstrap method.
4816
                             * @param bootstrapReturnType     The return type of the boostrap method.
4817
                             * @param bootstrapParameterTypes The parameter types of the boostrap method.
4818
                             * @param arguments               The constant arguments to the bootstrap method.
4819
                             * @param invokedynamic           {@code true} if invokedynamic should be used to bind the constant.
4820
                             */
4821
                            public ForDynamicConstant(String name,
4822
                                                      TypeDescription typeDescription,
4823
                                                      JavaConstant.MethodHandle.HandleType bootstrapType,
4824
                                                      TypeDescription bootstrapOwner,
4825
                                                      String bootstrapName,
4826
                                                      TypeDescription bootstrapReturnType,
4827
                                                      List<? extends TypeDescription> bootstrapParameterTypes,
4828
                                                      List<JavaConstant> arguments,
4829
                                                      boolean invokedynamic) {
1✔
4830
                                this.name = name;
1✔
4831
                                this.typeDescription = typeDescription;
1✔
4832
                                this.bootstrapType = bootstrapType;
1✔
4833
                                this.bootstrapOwner = bootstrapOwner;
1✔
4834
                                this.bootstrapName = bootstrapName;
1✔
4835
                                this.bootstrapReturnType = bootstrapReturnType;
1✔
4836
                                this.bootstrapParameterTypes = bootstrapParameterTypes;
1✔
4837
                                this.arguments = arguments;
1✔
4838
                                this.invokedynamic = invokedynamic;
1✔
4839
                            }
1✔
4840

4841
                            /**
4842
                             * {@inheritDoc}
4843
                             */
4844
                            public Resolved resolve(Assigner assigner,
4845
                                                    Assigner.Typing typing,
4846
                                                    TypeDescription instrumentedType,
4847
                                                    MethodDescription instrumentedMethod) {
4848
                                if (invokedynamic) {
1✔
4849
                                    return new Resolved.ForStackManipulation(new Invokedynamic(name,
1✔
4850
                                            JavaConstant.MethodType.of(typeDescription),
1✔
4851
                                            new JavaConstant.MethodHandle(bootstrapType,
4852
                                                    bootstrapOwner.represents(void.class) ? instrumentedType : bootstrapOwner,
1✔
4853
                                                    bootstrapName,
4854
                                                    bootstrapReturnType,
4855
                                                    bootstrapParameterTypes),
4856
                                            arguments));
4857
                                } else {
4858
                                    return new Resolved.ForStackManipulation(new JavaConstantValue(new JavaConstant.Dynamic(
×
4859
                                            name,
4860
                                            typeDescription,
4861
                                            new JavaConstant.MethodHandle(bootstrapType,
4862
                                                    bootstrapOwner.represents(void.class) ? instrumentedType : bootstrapOwner,
×
4863
                                                    bootstrapName,
4864
                                                    bootstrapReturnType,
4865
                                                    bootstrapParameterTypes),
4866
                                            arguments)));
4867
                                }
4868
                            }
4869

4870
                            /**
4871
                             * A factory to create an offset mapping for a dynamic constant.
4872
                             */
4873
                            protected enum Factory implements OffsetMapping.Factory<DynamicConstant> {
1✔
4874

4875
                                /**
4876
                                 * The singleton instance.
4877
                                 */
4878
                                INSTANCE;
1✔
4879

4880
                                /**
4881
                                 * The {@link DynamicConstant#name()} method.
4882
                                 */
4883
                                private static final MethodDescription.InDefinedShape NAME;
4884

4885
                                /**
4886
                                 * The {@link DynamicConstant#bootstrapType()} method.
4887
                                 */
4888
                                private static final MethodDescription.InDefinedShape BOOTSTRAP_TYPE;
4889

4890
                                /**
4891
                                 * The {@link DynamicConstant#bootstrapOwner()} method.
4892
                                 */
4893
                                private static final MethodDescription.InDefinedShape BOOTSTRAP_OWNER;
4894

4895
                                /**
4896
                                 * The {@link DynamicConstant#bootstrapName()} method.
4897
                                 */
4898
                                private static final MethodDescription.InDefinedShape BOOTSTRAP_NAME;
4899

4900
                                /**
4901
                                 * The {@link DynamicConstant#bootstrapReturnType()} method.
4902
                                 */
4903
                                private static final MethodDescription.InDefinedShape BOOTSTRAP_RETURN_TYPE;
4904

4905
                                /**
4906
                                 * The {@link DynamicConstant#bootstrapParameterTypes()} method.
4907
                                 */
4908
                                private static final MethodDescription.InDefinedShape BOOTSTRAP_PARAMETER_TYPES;
4909

4910
                                /**
4911
                                 * The {@link DynamicConstant#invokedynamic()} method.
4912
                                 */
4913
                                private static final MethodDescription.InDefinedShape INVOKEDYNAMIC;
4914

4915
                                /*
4916
                                 * Resolves all annotation properties.
4917
                                 */
4918
                                static {
4919
                                    MethodList<MethodDescription.InDefinedShape> methods = TypeDescription.ForLoadedType.of(DynamicConstant.class).getDeclaredMethods();
1✔
4920
                                    NAME = methods.filter(named("name")).getOnly();
1✔
4921
                                    BOOTSTRAP_TYPE = methods.filter(named("bootstrapType")).getOnly();
1✔
4922
                                    BOOTSTRAP_OWNER = methods.filter(named("bootstrapOwner")).getOnly();
1✔
4923
                                    BOOTSTRAP_NAME = methods.filter(named("bootstrapName")).getOnly();
1✔
4924
                                    BOOTSTRAP_RETURN_TYPE = methods.filter(named("bootstrapReturnType")).getOnly();
1✔
4925
                                    BOOTSTRAP_PARAMETER_TYPES = methods.filter(named("bootstrapParameterTypes")).getOnly();
1✔
4926
                                    INVOKEDYNAMIC = methods.filter(named("invokedynamic")).getOnly();
1✔
4927
                                }
1✔
4928

4929
                                /**
4930
                                 * {@inheritDoc}
4931
                                 */
4932
                                public Class<DynamicConstant> getAnnotationType() {
4933
                                    return DynamicConstant.class;
1✔
4934
                                }
4935

4936
                                /**
4937
                                 * {@inheritDoc}
4938
                                 */
4939
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<DynamicConstant> annotation) {
4940
                                    throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
4941
                                }
4942

4943
                                /**
4944
                                 * {@inheritDoc}
4945
                                 */
4946
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<DynamicConstant> annotation) {
4947
                                    return new ForDynamicConstant(
1✔
4948
                                            annotation.getValue(NAME).resolve(String.class),
1✔
4949
                                            target.getType().asErasure(),
1✔
4950
                                            annotation.getValue(BOOTSTRAP_TYPE).resolve(EnumerationDescription.class).load(JavaConstant.MethodHandle.HandleType.class),
1✔
4951
                                            annotation.getValue(BOOTSTRAP_OWNER).resolve(TypeDescription.class),
1✔
4952
                                            annotation.getValue(BOOTSTRAP_NAME).resolve(String.class),
1✔
4953
                                            annotation.getValue(BOOTSTRAP_RETURN_TYPE).resolve(TypeDescription.class),
1✔
4954
                                            Arrays.asList(annotation.getValue(BOOTSTRAP_PARAMETER_TYPES).resolve(TypeDescription[].class)),
1✔
4955
                                            Collections.<JavaConstant>emptyList(),
1✔
4956
                                            annotation.getValue(INVOKEDYNAMIC).resolve(Boolean.class));
1✔
4957
                                }
4958
                            }
4959
                        }
4960

4961
                        /**
4962
                         * An offset mapping for a field value.
4963
                         */
4964
                        @HashCodeAndEqualsPlugin.Enhance
4965
                        abstract class ForField implements OffsetMapping {
4966

4967
                            /**
4968
                             * The {@link FieldValue#value()} property.
4969
                             */
4970
                            private static final MethodDescription.InDefinedShape FIELD_VALUE_VALUE;
4971

4972
                            /**
4973
                             * The {@link FieldValue#declaringType()} property.
4974
                             */
4975
                            private static final MethodDescription.InDefinedShape FIELD_VALUE_DECLARING_TYPE;
4976

4977
                            /**
4978
                             * The {@link FieldValue#typing()} property.
4979
                             */
4980
                            private static final MethodDescription.InDefinedShape FIELD_VALUE_TYPING;
4981

4982
                            /*
4983
                             * Resolves all annotation properties.
4984
                             */
4985
                            static {
4986
                                MethodList<MethodDescription.InDefinedShape> methods = TypeDescription.ForLoadedType.of(FieldValue.class).getDeclaredMethods();
1✔
4987
                                FIELD_VALUE_VALUE = methods.filter(named("value")).getOnly();
1✔
4988
                                FIELD_VALUE_DECLARING_TYPE = methods.filter(named("declaringType")).getOnly();
1✔
4989
                                FIELD_VALUE_TYPING = methods.filter(named("typing")).getOnly();
1✔
4990
                            }
1✔
4991

4992
                            /**
4993
                             * A description of the targeted type.
4994
                             */
4995
                            private final TypeDescription.Generic target;
4996

4997
                            /**
4998
                             * The typing to use or {@code null} if implicit typing.
4999
                             */
5000
                            @MaybeNull
5001
                            @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
5002
                            private final Assigner.Typing typing;
5003

5004
                            /**
5005
                             * Creates an offset mapping for a field value.
5006
                             *
5007
                             * @param target A description of the targeted type.
5008
                             * @param typing The typing to use or {@code null} if implicit typing.
5009
                             */
5010
                            protected ForField(TypeDescription.Generic target, @MaybeNull Assigner.Typing typing) {
1✔
5011
                                this.target = target;
1✔
5012
                                this.typing = typing;
1✔
5013
                            }
1✔
5014

5015
                            /**
5016
                             * {@inheritDoc}
5017
                             */
5018
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
5019
                                FieldDescription fieldDescription = resolve(instrumentedType, instrumentedMethod);
1✔
5020
                                if (!fieldDescription.isStatic() && instrumentedMethod.isStatic()) {
1✔
5021
                                    throw new IllegalStateException("Cannot access non-static field " + fieldDescription + " from static method " + instrumentedMethod);
×
5022
                                }
5023
                                StackManipulation assignment = assigner.assign(fieldDescription.getType(), target, this.typing == null ? typing : this.typing);
1✔
5024
                                if (!assignment.isValid()) {
1✔
5025
                                    throw new IllegalStateException("Cannot assign " + fieldDescription + " to " + target);
×
5026
                                }
5027
                                return new OffsetMapping.Resolved.ForStackManipulation(new StackManipulation.Compound(fieldDescription.isStatic()
1✔
5028
                                        ? StackManipulation.Trivial.INSTANCE
5029
                                        : MethodVariableAccess.loadThis(), FieldAccess.forField(fieldDescription).read(), assignment));
1✔
5030
                            }
5031

5032
                            /**
5033
                             * Resolves a description of the field being accessed.
5034
                             *
5035
                             * @param instrumentedType   The instrumented type.
5036
                             * @param instrumentedMethod The instrumented method.
5037
                             * @return A description of the field being accessed.
5038
                             */
5039
                            protected abstract FieldDescription resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod);
5040

5041
                            /**
5042
                             * An offset mapping for an unresolved field value.
5043
                             */
5044
                            @HashCodeAndEqualsPlugin.Enhance
5045
                            public abstract static class Unresolved extends ForField {
5046

5047
                                /**
5048
                                 * Indicates that the name of the field should be inferred from the instrumented method's name as a bean property.
5049
                                 */
5050
                                protected static final String BEAN_PROPERTY = "";
5051

5052
                                /**
5053
                                 * The name of the field being accessed or an empty string if the name of the field should be inferred.
5054
                                 */
5055
                                private final String name;
5056

5057
                                /**
5058
                                 * Creates an offset mapping for the value of an unresolved field.
5059
                                 *
5060
                                 * @param target A description of the targeted type.
5061
                                 * @param typing The typing to use.
5062
                                 * @param name   The name of the field being accessed or an empty string if the name of the field should be inferred.
5063
                                 */
5064
                                protected Unresolved(TypeDescription.Generic target, Assigner.Typing typing, String name) {
5065
                                    super(target, typing);
1✔
5066
                                    this.name = name;
1✔
5067
                                }
1✔
5068

5069
                                @Override
5070
                                protected FieldDescription resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
5071
                                    FieldLocator locator = fieldLocator(instrumentedType);
1✔
5072
                                    FieldLocator.Resolution resolution = name.equals(BEAN_PROPERTY)
1✔
5073
                                            ? FieldLocator.Resolution.Simple.ofBeanAccessor(locator, instrumentedMethod)
1✔
5074
                                            : locator.locate(name);
1✔
5075
                                    if (!resolution.isResolved()) {
1✔
5076
                                        throw new IllegalStateException("Cannot locate field named " + name + " for " + instrumentedType);
×
5077
                                    } else {
5078
                                        return resolution.getField();
1✔
5079
                                    }
5080
                                }
5081

5082
                                /**
5083
                                 * Creates a field locator for the instrumented type.
5084
                                 *
5085
                                 * @param instrumentedType The instrumented type.
5086
                                 * @return An appropriate field locator.
5087
                                 */
5088
                                protected abstract FieldLocator fieldLocator(TypeDescription instrumentedType);
5089

5090
                                /**
5091
                                 * An offset mapping for an unresolved field with an implicit declaring type.
5092
                                 */
5093
                                public static class WithImplicitType extends Unresolved {
5094

5095
                                    /**
5096
                                     * Creates an offset mapping for an unresolved field value with an implicit declaring type.
5097
                                     *
5098
                                     * @param target     A description of the targeted type.
5099
                                     * @param annotation The annotation describing the access.
5100
                                     */
5101
                                    protected WithImplicitType(TypeDescription.Generic target, AnnotationDescription.Loadable<FieldValue> annotation) {
5102
                                        this(target,
1✔
5103
                                                annotation.getValue(FIELD_VALUE_TYPING).resolve(EnumerationDescription.class).load(Assigner.Typing.class),
1✔
5104
                                                annotation.getValue(FIELD_VALUE_VALUE).resolve(String.class));
1✔
5105
                                    }
1✔
5106

5107
                                    /**
5108
                                     * Creates an offset mapping for the value of an unresolved field with an implicit declaring type.
5109
                                     *
5110
                                     * @param target A description of the targeted type.
5111
                                     * @param typing The typing to use.
5112
                                     * @param name   The name of the field being accessed or an empty string if the name of the field should be inferred.
5113
                                     */
5114
                                    public WithImplicitType(TypeDescription.Generic target, Assigner.Typing typing, String name) {
5115
                                        super(target, typing, name);
1✔
5116
                                    }
1✔
5117

5118
                                    @Override
5119
                                    protected FieldLocator fieldLocator(TypeDescription instrumentedType) {
5120
                                        return new FieldLocator.ForClassHierarchy(instrumentedType);
1✔
5121
                                    }
5122
                                }
5123

5124
                                /**
5125
                                 * An offset mapping for an unresolved field value with an explicit declaring type.
5126
                                 */
5127
                                @HashCodeAndEqualsPlugin.Enhance
5128
                                public static class WithExplicitType extends Unresolved {
5129

5130
                                    /**
5131
                                     * The field's declaring type.
5132
                                     */
5133
                                    private final TypeDescription declaringType;
5134

5135
                                    /**
5136
                                     * Creates an offset mapping for the value of an unresolved field with an explicit declaring type.
5137
                                     *
5138
                                     * @param target        A description of the targeted type.
5139
                                     * @param annotation    The annotation describing the field access.
5140
                                     * @param declaringType The field's declaring type.
5141
                                     */
5142
                                    protected WithExplicitType(TypeDescription.Generic target, AnnotationDescription.Loadable<FieldValue> annotation, TypeDescription declaringType) {
5143
                                        this(target,
1✔
5144
                                                annotation.getValue(FIELD_VALUE_TYPING).resolve(EnumerationDescription.class).load(Assigner.Typing.class),
1✔
5145
                                                annotation.getValue(FIELD_VALUE_VALUE).resolve(String.class),
1✔
5146
                                                declaringType);
5147
                                    }
1✔
5148

5149
                                    /**
5150
                                     * Creates an offset mapping for the value of an unresolved field with an explicit declaring type.
5151
                                     *
5152
                                     * @param target        A description of the targeted type.
5153
                                     * @param typing        The typing to use.
5154
                                     * @param name          The name of the field being accessed or an empty string if the name of the field should be inferred.
5155
                                     * @param declaringType The field's declaring type.
5156
                                     */
5157
                                    public WithExplicitType(TypeDescription.Generic target, Assigner.Typing typing, String name, TypeDescription declaringType) {
5158
                                        super(target, typing, name);
1✔
5159
                                        this.declaringType = declaringType;
1✔
5160
                                    }
1✔
5161

5162
                                    @Override
5163
                                    protected FieldLocator fieldLocator(TypeDescription instrumentedType) {
5164
                                        if (!declaringType.represents(TargetType.class) && !instrumentedType.isAssignableTo(declaringType)) {
1✔
5165
                                            throw new IllegalStateException(declaringType + " is no super type of " + instrumentedType);
×
5166
                                        }
5167
                                        return new FieldLocator.ForExactType(TargetType.resolve(declaringType, instrumentedType));
1✔
5168
                                    }
5169
                                }
5170

5171
                                /**
5172
                                 * A factory for creating an offset mapping for a field value.
5173
                                 */
5174
                                protected enum Factory implements OffsetMapping.Factory<FieldValue> {
1✔
5175

5176
                                    /**
5177
                                     * The singleton instance.
5178
                                     */
5179
                                    INSTANCE;
1✔
5180

5181
                                    /**
5182
                                     * {@inheritDoc}
5183
                                     */
5184
                                    public Class<FieldValue> getAnnotationType() {
5185
                                        return FieldValue.class;
1✔
5186
                                    }
5187

5188
                                    /**
5189
                                     * {@inheritDoc}
5190
                                     */
5191
                                    public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<FieldValue> annotation) {
5192
                                        TypeDescription declaringType = annotation.getValue(FIELD_VALUE_DECLARING_TYPE).resolve(TypeDescription.class);
×
5193
                                        return declaringType.represents(void.class)
×
5194
                                                ? new Unresolved.WithImplicitType(target.getDeclaringType().asGenericType(), annotation)
×
5195
                                                : new Unresolved.WithExplicitType(target.getDeclaringType().asGenericType(), annotation, declaringType);
×
5196
                                    }
5197

5198
                                    /**
5199
                                     * {@inheritDoc}
5200
                                     */
5201
                                    public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<FieldValue> annotation) {
5202
                                        TypeDescription declaringType = annotation.getValue(FIELD_VALUE_DECLARING_TYPE).resolve(TypeDescription.class);
1✔
5203
                                        return declaringType.represents(void.class)
1✔
5204
                                                ? new Unresolved.WithImplicitType(target.getType(), annotation)
1✔
5205
                                                : new Unresolved.WithExplicitType(target.getType(), annotation, declaringType);
1✔
5206
                                    }
5207
                                }
5208
                            }
5209

5210
                            /**
5211
                             * An offset mapping for a resolved field access.
5212
                             */
5213
                            @HashCodeAndEqualsPlugin.Enhance
5214
                            public static class Resolved extends ForField {
5215

5216
                                /**
5217
                                 * A description of the field being accessed.
5218
                                 */
5219
                                private final FieldDescription fieldDescription;
5220

5221
                                /**
5222
                                 * Creates a resolved offset mapping for a field access.
5223
                                 *
5224
                                 * @param target           A description of the targeted type.
5225
                                 * @param typing           The typing to use or {@code null} if implicit typing.
5226
                                 * @param fieldDescription A description of the field accessed.
5227
                                 */
5228
                                public Resolved(TypeDescription.Generic target, Assigner.Typing typing, FieldDescription fieldDescription) {
5229
                                    super(target, typing);
1✔
5230
                                    this.fieldDescription = fieldDescription;
1✔
5231
                                }
1✔
5232

5233
                                @Override
5234
                                @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
5235
                                protected FieldDescription resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
5236
                                    if (!fieldDescription.isStatic() && !fieldDescription.getDeclaringType().asErasure().isAssignableFrom(instrumentedType)) {
1✔
5237
                                        throw new IllegalStateException(fieldDescription + " is no member of " + instrumentedType);
×
5238
                                    } else if (!fieldDescription.isVisibleTo(instrumentedType)) {
1✔
5239
                                        throw new IllegalStateException("Cannot access " + fieldDescription + " from " + instrumentedType);
×
5240
                                    }
5241
                                    return fieldDescription;
1✔
5242
                                }
5243

5244
                                /**
5245
                                 * A factory for creating a resolved offset mapping of a field value.
5246
                                 *
5247
                                 * @param <T> The type of the annotation.
5248
                                 */
5249
                                @HashCodeAndEqualsPlugin.Enhance
5250
                                public static class Factory<T extends Annotation> extends OffsetMapping.Factory.AbstractBase<T> {
5251

5252
                                    /**
5253
                                     * The annotation type.
5254
                                     */
5255
                                    private final Class<T> annotationType;
5256

5257
                                    /**
5258
                                     * The field being accessed.
5259
                                     */
5260
                                    private final FieldDescription fieldDescription;
5261

5262
                                    /**
5263
                                     * The typing to use.
5264
                                     */
5265
                                    private final Assigner.Typing typing;
5266

5267
                                    /**
5268
                                     * Creates a factory for reading a given field.
5269
                                     *
5270
                                     * @param annotationType   The annotation type.
5271
                                     * @param fieldDescription The field being accessed.
5272
                                     */
5273
                                    public Factory(Class<T> annotationType, FieldDescription fieldDescription) {
5274
                                        this(annotationType, fieldDescription, Assigner.Typing.STATIC);
1✔
5275
                                    }
1✔
5276

5277
                                    /**
5278
                                     * Creates a factory for reading a given field.
5279
                                     *
5280
                                     * @param annotationType   The annotation type.
5281
                                     * @param fieldDescription The field being accessed.
5282
                                     * @param typing           The typing to use.
5283
                                     */
5284
                                    public Factory(Class<T> annotationType, FieldDescription fieldDescription, Assigner.Typing typing) {
1✔
5285
                                        this.annotationType = annotationType;
1✔
5286
                                        this.fieldDescription = fieldDescription;
1✔
5287
                                        this.typing = typing;
1✔
5288
                                    }
1✔
5289

5290
                                    /**
5291
                                     * {@inheritDoc}
5292
                                     */
5293
                                    public Class<T> getAnnotationType() {
5294
                                        return annotationType;
1✔
5295
                                    }
5296

5297
                                    @Override
5298
                                    protected OffsetMapping make(TypeDescription.Generic target, AnnotationDescription.Loadable<T> annotation) {
5299
                                        return new ForField.Resolved(target, typing, fieldDescription);
1✔
5300
                                    }
5301
                                }
5302
                            }
5303
                        }
5304

5305
                        /**
5306
                         * An offset mapping for a method handle representing a field getter or setter.
5307
                         */
5308
                        @HashCodeAndEqualsPlugin.Enhance
5309
                        abstract class ForFieldHandle implements OffsetMapping {
5310

5311
                            /**
5312
                             * The type of access to the field.
5313
                             */
5314
                            private final Access access;
5315

5316
                            /**
5317
                             * Creates an offset mapping for a field getter or setter.
5318
                             *
5319
                             * @param access The type of access to the field.
5320
                             */
5321
                            protected ForFieldHandle(Access access) {
×
5322
                                this.access = access;
×
5323
                            }
×
5324

5325
                            /**
5326
                             * {@inheritDoc}
5327
                             */
5328
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
5329
                                FieldDescription fieldDescription = resolve(instrumentedType, instrumentedMethod);
×
5330
                                if (!fieldDescription.isStatic() && instrumentedMethod.isStatic()) {
×
5331
                                    throw new IllegalStateException("Cannot access non-static field " + fieldDescription + " from static method " + instrumentedMethod);
×
5332
                                }
5333
                                if (fieldDescription.isStatic()) {
×
5334
                                    return new OffsetMapping.Resolved.ForStackManipulation(access.resolve(fieldDescription.asDefined()).toStackManipulation());
×
5335
                                } else {
5336
                                    return new OffsetMapping.Resolved.ForStackManipulation(new StackManipulation.Compound(
×
5337
                                            access.resolve(fieldDescription.asDefined()).toStackManipulation(), MethodVariableAccess.REFERENCE.loadFrom(THIS_REFERENCE),
×
5338
                                            MethodInvocation.invoke(new MethodDescription.Latent(JavaType.METHOD_HANDLE.getTypeStub(), new MethodDescription.Token("bindTo",
×
5339
                                                    Opcodes.ACC_PUBLIC,
5340
                                                    JavaType.METHOD_HANDLE.getTypeStub().asGenericType(),
×
5341
                                                    new TypeList.Generic.Explicit(TypeDefinition.Sort.describe(Object.class)))))));
×
5342
                                }
5343
                            }
5344

5345
                            /**
5346
                             * Resolves a description of the field being accessed.
5347
                             *
5348
                             * @param instrumentedType   The instrumented type.
5349
                             * @param instrumentedMethod The instrumented method.
5350
                             * @return A description of the field being accessed.
5351
                             */
5352
                            protected abstract FieldDescription resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod);
5353

5354
                            /**
5355
                             * The type of access to the field.
5356
                             */
5357
                            public enum Access {
×
5358

5359
                                /**
5360
                                 * Describes a field getter.
5361
                                 */
5362
                                GETTER {
×
5363
                                    @Override
5364
                                    protected JavaConstant.MethodHandle resolve(FieldDescription.InDefinedShape fieldDescription) {
5365
                                        return JavaConstant.MethodHandle.ofGetter(fieldDescription);
×
5366
                                    }
5367
                                },
5368

5369
                                /**
5370
                                 * Describes a field setter.
5371
                                 */
5372
                                SETTER {
×
5373
                                    @Override
5374
                                    protected JavaConstant.MethodHandle resolve(FieldDescription.InDefinedShape fieldDescription) {
5375
                                        return JavaConstant.MethodHandle.ofSetter(fieldDescription);
×
5376
                                    }
5377
                                };
5378

5379
                                /**
5380
                                 * Resolves a handle for the represented field access.
5381
                                 *
5382
                                 * @param fieldDescription The field that is being accessed.
5383
                                 * @return An appropriate method handle.
5384
                                 */
5385
                                protected abstract JavaConstant.MethodHandle resolve(FieldDescription.InDefinedShape fieldDescription);
5386
                            }
5387

5388
                            /**
5389
                             * An offset mapping for an unresolved field handle.
5390
                             */
5391
                            @HashCodeAndEqualsPlugin.Enhance
5392
                            public abstract static class Unresolved extends ForFieldHandle {
5393

5394
                                /**
5395
                                 * Indicates that the field's name should be resolved as a bean property.
5396
                                 */
5397
                                protected static final String BEAN_PROPERTY = "";
5398

5399
                                /**
5400
                                 * The name of the field or an empty string if the name should be resolved from the instrumented method.
5401
                                 */
5402
                                private final String name;
5403

5404
                                /**
5405
                                 * Creates an offset mapping for an unresolved field handle.
5406
                                 *
5407
                                 * @param access The type of access to the field.
5408
                                 * @param name   The name of the field or an empty string if the name should be resolved from the instrumented method.
5409
                                 */
5410
                                public Unresolved(Access access, String name) {
5411
                                    super(access);
×
5412
                                    this.name = name;
×
5413
                                }
×
5414

5415
                                @Override
5416
                                protected FieldDescription resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
5417
                                    FieldLocator locator = fieldLocator(instrumentedType);
×
5418
                                    FieldLocator.Resolution resolution = name.equals(BEAN_PROPERTY)
×
5419
                                            ? FieldLocator.Resolution.Simple.ofBeanAccessor(locator, instrumentedMethod)
×
5420
                                            : locator.locate(name);
×
5421
                                    if (!resolution.isResolved()) {
×
5422
                                        throw new IllegalStateException("Cannot locate field named " + name + " for " + instrumentedType);
×
5423
                                    } else {
5424
                                        return resolution.getField();
×
5425
                                    }
5426
                                }
5427

5428
                                /**
5429
                                 * Resolves a field locator for the instrumented type.
5430
                                 *
5431
                                 * @param instrumentedType The instrumented type.
5432
                                 * @return Returns an appropriate field locator.
5433
                                 */
5434
                                protected abstract FieldLocator fieldLocator(TypeDescription instrumentedType);
5435

5436
                                /**
5437
                                 * An offset mapping for an unresolved field handle with an implicit declaring type.
5438
                                 */
5439
                                public static class WithImplicitType extends Unresolved {
5440

5441
                                    /**
5442
                                     * Creates an offset mapping for an unresolved field handle with an implicit declaring type.
5443
                                     *
5444
                                     * @param access The type of access to the field.
5445
                                     * @param name   The name of the field or an empty string if the name should be resolved from the instrumented method.
5446
                                     */
5447
                                    public WithImplicitType(Access access, String name) {
5448
                                        super(access, name);
×
5449
                                    }
×
5450

5451
                                    @Override
5452
                                    protected FieldLocator fieldLocator(TypeDescription instrumentedType) {
5453
                                        return new FieldLocator.ForClassHierarchy(instrumentedType);
×
5454
                                    }
5455
                                }
5456

5457
                                /**
5458
                                 * An offset mapping for an unresolved field handle with an explicit declaring type.
5459
                                 */
5460
                                @HashCodeAndEqualsPlugin.Enhance
5461
                                public static class WithExplicitType extends Unresolved {
5462

5463
                                    /**
5464
                                     * The field's declaring type.
5465
                                     */
5466
                                    private final TypeDescription declaringType;
5467

5468
                                    /**
5469
                                     * Creates an offset mapping for an unresolved field handle with an explicit declaring type.
5470
                                     *
5471
                                     * @param access        The type of access to the field.
5472
                                     * @param name          The name of the field or an empty string if the name should be resolved from the instrumented method.
5473
                                     * @param declaringType The field's declaring type.
5474
                                     */
5475
                                    public WithExplicitType(Access access, String name, TypeDescription declaringType) {
5476
                                        super(access, name);
×
5477
                                        this.declaringType = declaringType;
×
5478
                                    }
×
5479

5480
                                    @Override
5481
                                    protected FieldLocator fieldLocator(TypeDescription instrumentedType) {
5482
                                        if (!declaringType.represents(TargetType.class) && !instrumentedType.isAssignableTo(declaringType)) {
×
5483
                                            throw new IllegalStateException(declaringType + " is no super type of " + instrumentedType);
×
5484
                                        }
5485
                                        return new FieldLocator.ForExactType(TargetType.resolve(declaringType, instrumentedType));
×
5486
                                    }
5487
                                }
5488

5489
                                /**
5490
                                 * A factory for creating a method handle representing a getter for the targeted field.
5491
                                 */
5492
                                protected enum GetterFactory implements OffsetMapping.Factory<FieldGetterHandle> {
1✔
5493

5494
                                    /**
5495
                                     * The singleton instance.
5496
                                     */
5497
                                    INSTANCE;
1✔
5498

5499
                                    /**
5500
                                     * The {@link FieldGetterHandle#value()} method.
5501
                                     */
5502
                                    private static final MethodDescription.InDefinedShape FIELD_GETTER_HANDLE_VALUE;
5503

5504
                                    /**
5505
                                     * The {@link FieldGetterHandle#declaringType()} method.
5506
                                     */
5507
                                    private static final MethodDescription.InDefinedShape FIELD_GETTER_HANDLE_DECLARING_TYPE;
5508

5509
                                    /*
5510
                                     * Resolves all annotation properties.
5511
                                     */
5512
                                    static {
5513
                                        MethodList<MethodDescription.InDefinedShape> methods = TypeDescription.ForLoadedType.of(FieldGetterHandle.class).getDeclaredMethods();
1✔
5514
                                        FIELD_GETTER_HANDLE_VALUE = methods.filter(named("value")).getOnly();
1✔
5515
                                        FIELD_GETTER_HANDLE_DECLARING_TYPE = methods.filter(named("declaringType")).getOnly();
1✔
5516
                                    }
1✔
5517

5518
                                    /**
5519
                                     * {@inheritDoc}
5520
                                     */
5521
                                    public Class<FieldGetterHandle> getAnnotationType() {
5522
                                        return FieldGetterHandle.class;
1✔
5523
                                    }
5524

5525
                                    /**
5526
                                     * {@inheritDoc}
5527
                                     */
5528
                                    public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<FieldGetterHandle> annotation) {
5529
                                        throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
5530
                                    }
5531

5532
                                    /**
5533
                                     * {@inheritDoc}
5534
                                     */
5535
                                    public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<FieldGetterHandle> annotation) {
5536
                                        if (!target.getType().asErasure().isAssignableFrom(JavaType.METHOD_HANDLE.getTypeStub())) {
×
5537
                                            throw new IllegalStateException("Cannot assign method handle to " + target);
×
5538
                                        }
5539
                                        TypeDescription declaringType = annotation.getValue(FIELD_GETTER_HANDLE_DECLARING_TYPE).resolve(TypeDescription.class);
×
5540
                                        return declaringType.represents(void.class)
×
5541
                                                ? new ForFieldHandle.Unresolved.WithImplicitType(Access.GETTER, annotation.getValue(FIELD_GETTER_HANDLE_VALUE).resolve(String.class))
×
5542
                                                : new ForFieldHandle.Unresolved.WithExplicitType(Access.GETTER, annotation.getValue(FIELD_GETTER_HANDLE_VALUE).resolve(String.class), declaringType);
×
5543
                                    }
5544
                                }
5545

5546
                                /**
5547
                                 * A factory for creating a method handle representing a setter for the targeted field.
5548
                                 */
5549
                                protected enum SetterFactory implements OffsetMapping.Factory<FieldSetterHandle> {
1✔
5550

5551
                                    /**
5552
                                     * The singleton instance.
5553
                                     */
5554
                                    INSTANCE;
1✔
5555

5556
                                    /**
5557
                                     * The {@link FieldGetterHandle#value()} method.
5558
                                     */
5559
                                    private static final MethodDescription.InDefinedShape FIELD_SETTER_HANDLE_VALUE;
5560

5561
                                    /**
5562
                                     * The {@link FieldGetterHandle#declaringType()} method.
5563
                                     */
5564
                                    private static final MethodDescription.InDefinedShape FIELD_SETTER_HANDLE_DECLARING_TYPE;
5565

5566
                                    /*
5567
                                     * Resolves the annotation properties.
5568
                                     */
5569
                                    static {
5570
                                        MethodList<MethodDescription.InDefinedShape> methods = TypeDescription.ForLoadedType.of(FieldSetterHandle.class).getDeclaredMethods();
1✔
5571
                                        FIELD_SETTER_HANDLE_VALUE = methods.filter(named("value")).getOnly();
1✔
5572
                                        FIELD_SETTER_HANDLE_DECLARING_TYPE = methods.filter(named("declaringType")).getOnly();
1✔
5573
                                    }
1✔
5574

5575
                                    /**
5576
                                     * {@inheritDoc}
5577
                                     */
5578
                                    public Class<FieldSetterHandle> getAnnotationType() {
5579
                                        return FieldSetterHandle.class;
1✔
5580
                                    }
5581

5582
                                    /**
5583
                                     * {@inheritDoc}
5584
                                     */
5585
                                    public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<FieldSetterHandle> annotation) {
5586
                                        throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
5587
                                    }
5588

5589
                                    /**
5590
                                     * {@inheritDoc}
5591
                                     */
5592
                                    public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<FieldSetterHandle> annotation) {
5593
                                        if (!target.getType().asErasure().isAssignableFrom(JavaType.METHOD_HANDLE.getTypeStub())) {
×
5594
                                            throw new IllegalStateException("Cannot assign method handle to " + target);
×
5595
                                        }
5596
                                        TypeDescription declaringType = annotation.getValue(FIELD_SETTER_HANDLE_DECLARING_TYPE).resolve(TypeDescription.class);
×
5597
                                        return declaringType.represents(void.class)
×
5598
                                                ? new ForFieldHandle.Unresolved.WithImplicitType(Access.SETTER, annotation.getValue(FIELD_SETTER_HANDLE_VALUE).resolve(String.class))
×
5599
                                                : new ForFieldHandle.Unresolved.WithExplicitType(Access.SETTER, annotation.getValue(FIELD_SETTER_HANDLE_VALUE).resolve(String.class), declaringType);
×
5600
                                    }
5601
                                }
5602
                            }
5603

5604
                            /**
5605
                             * An offset mapping for a resolved field handle.
5606
                             */
5607
                            @HashCodeAndEqualsPlugin.Enhance
5608
                            public static class Resolved extends OffsetMapping.ForFieldHandle {
5609

5610
                                /**
5611
                                 * The field that is being accessed.
5612
                                 */
5613
                                private final FieldDescription fieldDescription;
5614

5615
                                /**
5616
                                 * Creates a resolved mapping for a field access handle.
5617
                                 *
5618
                                 * @param access           The type of access.
5619
                                 * @param fieldDescription The field that is being accessed.
5620
                                 */
5621
                                public Resolved(Access access, FieldDescription fieldDescription) {
5622
                                    super(access);
×
5623
                                    this.fieldDescription = fieldDescription;
×
5624
                                }
×
5625

5626
                                @Override
5627
                                @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
5628
                                protected FieldDescription resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
5629
                                    if (!fieldDescription.isStatic() && !fieldDescription.getDeclaringType().asErasure().isAssignableFrom(instrumentedType)) {
×
5630
                                        throw new IllegalStateException(fieldDescription + " is no member of " + instrumentedType);
×
5631
                                    } else if (!fieldDescription.isVisibleTo(instrumentedType)) {
×
5632
                                        throw new IllegalStateException("Cannot access " + fieldDescription + " from " + instrumentedType);
×
5633
                                    }
5634
                                    return fieldDescription;
×
5635
                                }
5636

5637
                                /**
5638
                                 * A factory to create an offset mapping for a resolved field handle.
5639
                                 *
5640
                                 * @param <T> The type of the annotation.
5641
                                 */
5642
                                @HashCodeAndEqualsPlugin.Enhance
5643
                                public static class Factory<T extends Annotation> implements OffsetMapping.Factory<T> {
5644

5645
                                    /**
5646
                                     * The annotation type.
5647
                                     */
5648
                                    private final Class<T> annotationType;
5649

5650
                                    /**
5651
                                     * The field being accessed.
5652
                                     */
5653
                                    private final FieldDescription fieldDescription;
5654

5655
                                    /**
5656
                                     * The type of access.
5657
                                     */
5658
                                    private final Access access;
5659

5660
                                    /**
5661
                                     * Creates a new factory for a field access handle.
5662
                                     *
5663
                                     * @param annotationType   The annotation type.
5664
                                     * @param fieldDescription The field being accessed.
5665
                                     * @param access           The type of access.
5666
                                     */
5667
                                    public Factory(Class<T> annotationType, FieldDescription fieldDescription, Access access) {
×
5668
                                        this.annotationType = annotationType;
×
5669
                                        this.fieldDescription = fieldDescription;
×
5670
                                        this.access = access;
×
5671
                                    }
×
5672

5673
                                    /**
5674
                                     * {@inheritDoc}
5675
                                     */
5676
                                    public Class<T> getAnnotationType() {
5677
                                        return annotationType;
×
5678
                                    }
5679

5680
                                    /**
5681
                                     * {@inheritDoc}
5682
                                     */
5683
                                    public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<T> annotation) {
5684
                                        throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
5685
                                    }
5686

5687
                                    /**
5688
                                     * {@inheritDoc}
5689
                                     */
5690
                                    public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<T> annotation) {
5691
                                        if (!target.getType().asErasure().isAssignableFrom(JavaType.METHOD_HANDLE.getTypeStub())) {
×
5692
                                            throw new IllegalStateException("Cannot assign method handle to " + target);
×
5693
                                        }
5694
                                        return new ForFieldHandle.Resolved(access, fieldDescription);
×
5695
                                    }
5696
                                }
5697
                            }
5698
                        }
5699

5700
                        /**
5701
                         * An offset mapping for describing a representation of the substituted element or the instrumented method.
5702
                         */
5703
                        @HashCodeAndEqualsPlugin.Enhance
5704
                        class ForOrigin implements OffsetMapping {
5705

5706
                            /**
5707
                             * The sort of the origin representation.
5708
                             */
5709
                            private final Sort sort;
5710

5711
                            /**
5712
                             * The source providing the reference.
5713
                             */
5714
                            private final Source source;
5715

5716
                            /**
5717
                             * Creates an offset mapping a representation of the substituted element or instrumented method.
5718
                             *
5719
                             * @param sort   The sort of the origin representation.
5720
                             * @param source The source providing the reference.
5721
                             */
5722
                            protected ForOrigin(Sort sort, Source source) {
1✔
5723
                                this.sort = sort;
1✔
5724
                                this.source = source;
1✔
5725
                            }
1✔
5726

5727
                            /**
5728
                             * {@inheritDoc}
5729
                             */
5730
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
5731
                                return new ForOrigin.Resolved(sort, source, instrumentedMethod);
1✔
5732
                            }
5733

5734
                            /**
5735
                             * The sort of the origin expression.
5736
                             */
5737
                            protected enum Sort {
1✔
5738

5739
                                /**
5740
                                 * Represents the supplied value as a {@link Method}.
5741
                                 */
5742
                                METHOD {
1✔
5743
                                    @Override
5744
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5745
                                        return member instanceof MethodDescription && ((MethodDescription) member).isMethod();
1✔
5746
                                    }
5747

5748
                                    @Override
5749
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5750
                                        return MethodConstant.of(((MethodDescription) member).asDefined());
1✔
5751
                                    }
5752
                                },
5753

5754
                                /**
5755
                                 * Represents the supplied value as a {@link Constructor}.
5756
                                 */
5757
                                CONSTRUCTOR {
1✔
5758
                                    @Override
5759
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5760
                                        return member instanceof MethodDescription && ((MethodDescription) member).isConstructor();
×
5761
                                    }
5762

5763
                                    @Override
5764
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5765
                                        return MethodConstant.of(((MethodDescription) member).asDefined());
×
5766
                                    }
5767
                                },
5768

5769
                                /**
5770
                                 * Represents the supplied value as a {@link Field}.
5771
                                 */
5772
                                FIELD {
1✔
5773
                                    @Override
5774
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5775
                                        return member instanceof FieldDescription;
1✔
5776
                                    }
5777

5778
                                    @Override
5779
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5780
                                        return new FieldConstant(((FieldDescription) member).asDefined());
1✔
5781
                                    }
5782
                                },
5783

5784
                                /**
5785
                                 * Represents the supplied value as a modifier as an integer.
5786
                                 */
5787
                                MODIFIERS {
1✔
5788
                                    @Override
5789
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5790
                                        return true;
×
5791
                                    }
5792

5793
                                    @Override
5794
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5795
                                        return IntegerConstant.forValue(member.getModifiers());
×
5796
                                    }
5797
                                },
5798

5799
                                /**
5800
                                 * Represents the supplied value as a {@code java.lang.reflect.Executable}.
5801
                                 */
5802
                                EXECUTABLE {
1✔
5803
                                    @Override
5804
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5805
                                        return member instanceof MethodDescription;
×
5806
                                    }
5807

5808
                                    @Override
5809
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5810
                                        return MethodConstant.of(((MethodDescription) member).asDefined());
×
5811
                                    }
5812
                                },
5813

5814
                                /**
5815
                                 * Represents the supplied value as a {@link Class}.
5816
                                 */
5817
                                TYPE {
1✔
5818
                                    @Override
5819
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5820
                                        return true;
1✔
5821
                                    }
5822

5823
                                    @Override
5824
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5825
                                        return ClassConstant.of(member.getDeclaringType().asErasure());
1✔
5826
                                    }
5827
                                },
5828

5829
                                /**
5830
                                 * Represents the supplied value as a {@code java.lang.invoke.MethodHandles.Lookup}.
5831
                                 */
5832
                                LOOKUP {
1✔
5833
                                    @Override
5834
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5835
                                        return true;
1✔
5836
                                    }
5837

5838
                                    @Override
5839
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5840
                                        return MethodInvocation.lookup();
1✔
5841
                                    }
5842
                                },
5843

5844
                                /**
5845
                                 * Represents the supplied value as a {@code java.lang.invoke.MethodHandle}.
5846
                                 */
5847
                                METHOD_HANDLE {
1✔
5848
                                    @Override
5849
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5850
                                        return true;
1✔
5851
                                    }
5852

5853
                                    @Override
5854
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5855
                                        JavaConstant.MethodHandle handle;
5856
                                        if (member instanceof MethodDescription) {
1✔
5857
                                            handle = JavaConstant.MethodHandle.of(((MethodDescription) member).asDefined());
1✔
5858
                                        } else if (member instanceof FieldDescription) {
1✔
5859
                                            handle = returnType.represents(void.class)
1✔
5860
                                                    ? JavaConstant.MethodHandle.ofSetter(((FieldDescription) member).asDefined())
1✔
5861
                                                    : JavaConstant.MethodHandle.ofGetter(((FieldDescription) member).asDefined());
1✔
5862
                                        } else {
5863
                                            throw new IllegalStateException("Unexpected byte code element: " + member);
×
5864
                                        }
5865
                                        return handle.toStackManipulation();
1✔
5866
                                    }
5867
                                },
5868

5869
                                /**
5870
                                 * Represents the supplied value as a {@code java.lang.invoke.MethodType}.
5871
                                 */
5872
                                METHOD_TYPE {
1✔
5873
                                    @Override
5874
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5875
                                        return true;
1✔
5876
                                    }
5877

5878
                                    @Override
5879
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5880
                                        return JavaConstant.MethodType.of(returnType, parameterTypes).toStackManipulation();
1✔
5881
                                    }
5882
                                },
5883

5884
                                /**
5885
                                 * Represents the supplied value as its {@link Object#toString()} representation.
5886
                                 */
5887
                                STRING {
1✔
5888
                                    @Override
5889
                                    protected boolean isRepresentable(ByteCodeElement.Member member) {
5890
                                        return true;
1✔
5891
                                    }
5892

5893
                                    @Override
5894
                                    protected StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType) {
5895
                                        return new TextConstant(member.toString());
1✔
5896
                                    }
5897
                                };
5898

5899
                                /**
5900
                                 * Checks if the supplied member can be represented by this sort.
5901
                                 *
5902
                                 * @param member The member that is considered for binding.
5903
                                 * @return {@code true} if the supplied element can be represented.
5904
                                 */
5905
                                protected abstract boolean isRepresentable(ByteCodeElement.Member member);
5906

5907
                                /**
5908
                                 * Creates a stack manipulation for the supplied byte code element.
5909
                                 *
5910
                                 * @param member         The member that is being bound.
5911
                                 * @param parameterTypes The parameter types.
5912
                                 * @param returnType     The return type.
5913
                                 * @return A stack manipulation loading the supplied byte code element's representation onto the stack.
5914
                                 */
5915
                                protected abstract StackManipulation resolve(ByteCodeElement.Member member, List<TypeDescription> parameterTypes, TypeDescription returnType);
5916
                            }
5917

5918
                            /**
5919
                             * A factory for an offset mapping that describes a representation of the substituted element or instrumented method.
5920
                             */
5921
                            protected enum Factory implements OffsetMapping.Factory<Origin> {
1✔
5922

5923
                                /**
5924
                                 * The singleton instance.
5925
                                 */
5926
                                INSTANCE;
1✔
5927

5928
                                /**
5929
                                 * The {@link Origin#source()} property.
5930
                                 */
5931
                                private static final MethodDescription.InDefinedShape ORIGIN_TYPE = TypeDescription.ForLoadedType.of(Origin.class)
1✔
5932
                                        .getDeclaredMethods()
1✔
5933
                                        .filter(named("source"))
1✔
5934
                                        .getOnly();
1✔
5935

5936
                                /**
5937
                                 * {@inheritDoc}
5938
                                 */
5939
                                public Class<Origin> getAnnotationType() {
5940
                                    return Origin.class;
1✔
5941
                                }
5942

5943
                                /**
5944
                                 * {@inheritDoc}
5945
                                 */
5946
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<Origin> annotation) {
5947
                                    throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
5948
                                }
5949

5950
                                /**
5951
                                 * {@inheritDoc}
5952
                                 */
5953
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<Origin> annotation) {
5954
                                    Sort sort;
5955
                                    if (target.getType().asErasure().represents(Class.class)) {
1✔
5956
                                        sort = Sort.TYPE;
1✔
5957
                                    } else if (target.getType().asErasure().represents(Method.class)) {
1✔
5958
                                        sort = Sort.METHOD;
1✔
5959
                                    } else if (target.getType().asErasure().represents(Constructor.class)) {
1✔
5960
                                        sort = Sort.CONSTRUCTOR;
×
5961
                                    } else if (target.getType().asErasure().represents(Field.class)) {
1✔
5962
                                        sort = Sort.FIELD;
1✔
5963
                                    } else if (target.getType().asErasure().represents(int.class)) {
1✔
5964
                                        sort = Sort.MODIFIERS;
×
5965
                                    } else if (JavaType.EXECUTABLE.getTypeStub().equals(target.getType().asErasure())) {
1✔
5966
                                        sort = Sort.EXECUTABLE;
×
5967
                                    } else if (JavaType.METHOD_HANDLE.getTypeStub().equals(target.getType().asErasure())) {
1✔
5968
                                        sort = Sort.METHOD_HANDLE;
1✔
5969
                                    } else if (JavaType.METHOD_TYPE.getTypeStub().equals(target.getType().asErasure())) {
1✔
5970
                                        sort = Sort.METHOD_TYPE;
1✔
5971
                                    } else if (JavaType.METHOD_HANDLES_LOOKUP.getTypeStub().equals(target.getType().asErasure())) {
1✔
5972
                                        sort = Sort.LOOKUP;
1✔
5973
                                    } else if (target.getType().asErasure().isAssignableFrom(String.class)) {
1✔
5974
                                        sort = Sort.STRING;
1✔
5975
                                    } else {
5976
                                        throw new IllegalStateException("Non-supported type " + target.getType() + " for @Origin annotation");
×
5977
                                    }
5978
                                    return new ForOrigin(sort, annotation.getValue(ORIGIN_TYPE).resolve(EnumerationDescription.class).load(Source.class));
1✔
5979
                                }
5980
                            }
5981

5982
                            /**
5983
                             * A resolved offset mapping for a representation of the substituted expression or instrumented method.
5984
                             */
5985
                            @HashCodeAndEqualsPlugin.Enhance
5986
                            protected static class Resolved implements OffsetMapping.Resolved {
5987

5988
                                /**
5989
                                 * The sort of the origin representation.
5990
                                 */
5991
                                private final Sort sort;
5992

5993
                                /**
5994
                                 * The source providing the reference.
5995
                                 */
5996
                                private final Source source;
5997

5998
                                /**
5999
                                 * The instrumented method.
6000
                                 */
6001
                                private final MethodDescription instrumentedMethod;
6002

6003
                                /**
6004
                                 * Creates a resolved version of an offset mapping for describing the substituted expression or instrumented method.
6005
                                 *
6006
                                 * @param sort               The sort of the origin representation.
6007
                                 * @param source             The source providing the reference.
6008
                                 * @param instrumentedMethod The instrumented method.
6009
                                 */
6010
                                protected Resolved(Sort sort, Source source, MethodDescription instrumentedMethod) {
1✔
6011
                                    this.sort = sort;
1✔
6012
                                    this.source = source;
1✔
6013
                                    this.instrumentedMethod = instrumentedMethod;
1✔
6014
                                }
1✔
6015

6016
                                /**
6017
                                 * {@inheritDoc}
6018
                                 */
6019
                                public StackManipulation apply(Target target,
6020
                                                               TypeList.Generic parameters,
6021
                                                               TypeDescription.Generic result,
6022
                                                               TypeDescription.Generic current,
6023
                                                               JavaConstant.MethodHandle methodHandle,
6024
                                                               Map<Integer, Integer> offsets,
6025
                                                               int offset) {
6026
                                    if (!source.isRepresentable(sort, target, instrumentedMethod)) {
1✔
6027
                                        throw new IllegalStateException("Cannot represent " + sort + " for " + source + " in " + instrumentedMethod);
×
6028
                                    }
6029
                                    return source.resolve(sort, target, parameters, result, instrumentedMethod);
1✔
6030
                                }
6031
                            }
6032
                        }
6033

6034
                        /**
6035
                         * An offset mapping that assigns a stub value.
6036
                         */
6037
                        @HashCodeAndEqualsPlugin.Enhance
6038
                        class ForStubValue implements OffsetMapping {
6039

6040
                            /**
6041
                             * The source providing the reference.
6042
                             */
6043
                            private final Source source;
6044

6045
                            /**
6046
                             * Creates an offset mapping for a stub value.
6047
                             *
6048
                             * @param source The source providing the reference.
6049
                             */
6050
                            protected ForStubValue(Source source) {
1✔
6051
                                this.source = source;
1✔
6052
                            }
1✔
6053

6054
                            /**
6055
                             * {@inheritDoc}
6056
                             */
6057
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
6058
                                return new Resolved(source, instrumentedMethod);
1✔
6059
                            }
6060

6061
                            /**
6062
                             * A resolved offset mapping for an offset mapping of a stub value.
6063
                             */
6064
                            @HashCodeAndEqualsPlugin.Enhance
6065
                            protected static class Resolved implements OffsetMapping.Resolved {
6066

6067
                                /**
6068
                                 * The source providing the reference.
6069
                                 */
6070
                                private final Source source;
6071

6072
                                /**
6073
                                 * The instrumented method.
6074
                                 */
6075
                                private final MethodDescription instrumentedMethod;
6076

6077
                                /**
6078
                                 * Creates a resolved version of an offset mapping for a stub value.
6079
                                 *
6080
                                 * @param source             The source providing the reference.
6081
                                 * @param instrumentedMethod The instrumented method.
6082
                                 */
6083
                                protected Resolved(Source source, MethodDescription instrumentedMethod) {
1✔
6084
                                    this.source = source;
1✔
6085
                                    this.instrumentedMethod = instrumentedMethod;
1✔
6086
                                }
1✔
6087

6088
                                /**
6089
                                 * {@inheritDoc}
6090
                                 */
6091
                                public StackManipulation apply(Target target,
6092
                                                               TypeList.Generic parameters,
6093
                                                               TypeDescription.Generic result,
6094
                                                               TypeDescription.Generic current,
6095
                                                               JavaConstant.MethodHandle methodHandle,
6096
                                                               Map<Integer, Integer> offsets,
6097
                                                               int offset) {
6098
                                    return DefaultValue.of(source.handle(methodHandle, instrumentedMethod).getReturnType());
1✔
6099
                                }
6100
                            }
6101

6102
                            /**
6103
                             * A factory for creating an offset mapping for a stub value.
6104
                             */
6105
                            @HashCodeAndEqualsPlugin.Enhance
1✔
6106
                            protected enum Factory implements OffsetMapping.Factory<StubValue> {
6107

6108
                                /**
6109
                                 * The singleton instance.
6110
                                 */
6111
                                INSTANCE;
1✔
6112

6113
                                /**
6114
                                 * The {@link StubValue#source()} property.
6115
                                 */
6116
                                private static final MethodDescription.InDefinedShape STUB_VALUE_SOURCE = TypeDescription.ForLoadedType.of(StubValue.class)
1✔
6117
                                        .getDeclaredMethods()
1✔
6118
                                        .filter(named("source"))
1✔
6119
                                        .getOnly();
1✔
6120

6121
                                /**
6122
                                 * {@inheritDoc}
6123
                                 */
6124
                                public Class<StubValue> getAnnotationType() {
6125
                                    return StubValue.class;
1✔
6126
                                }
6127

6128
                                /**
6129
                                 * {@inheritDoc}
6130
                                 */
6131
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<StubValue> annotation) {
6132
                                    throw new UnsupportedOperationException("This factory does not support binding a method receiver");
×
6133
                                }
6134

6135
                                /**
6136
                                 * {@inheritDoc}
6137
                                 */
6138
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<StubValue> annotation) {
6139
                                    if (!target.getType().represents(Object.class)) {
1✔
6140
                                        throw new IllegalStateException("Expected " + target + " to declare an Object type");
1✔
6141
                                    }
6142
                                    return new ForStubValue(annotation.getValue(STUB_VALUE_SOURCE).resolve(EnumerationDescription.class).load(Source.class));
1✔
6143
                                }
6144
                            }
6145
                        }
6146

6147
                        /**
6148
                         * An offset mapping that assigns the value of the previous chain instruction.
6149
                         */
6150
                        @HashCodeAndEqualsPlugin.Enhance
6151
                        class ForCurrent implements OffsetMapping {
6152

6153
                            /**
6154
                             * The type of the targeted expression.
6155
                             */
6156
                            private final TypeDescription.Generic targetType;
6157

6158
                            /**
6159
                             * The typing to use or {@code null} if implicit typing.
6160
                             */
6161
                            @MaybeNull
6162
                            @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
6163
                            private final Assigner.Typing typing;
6164

6165
                            /**
6166
                             * Creates an offset mapping for the previous chain instruction.
6167
                             *
6168
                             * @param targetType The type of the targeted expression.
6169
                             * @param typing     The typing to use or {@code null} if implicit typing.
6170
                             */
6171
                            public ForCurrent(TypeDescription.Generic targetType, @MaybeNull Assigner.Typing typing) {
1✔
6172
                                this.targetType = targetType;
1✔
6173
                                this.typing = typing;
1✔
6174
                            }
1✔
6175

6176
                            /**
6177
                             * {@inheritDoc}
6178
                             */
6179
                            public OffsetMapping.Resolved resolve(Assigner assigner, Assigner.Typing typing, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
6180
                                return new ForCurrent.Resolved(targetType, assigner, this.typing == null ? typing : this.typing);
1✔
6181
                            }
6182

6183
                            /**
6184
                             * A factory for creating an offset mapping for assigning the result of the previous chain instruction.
6185
                             */
6186
                            protected enum Factory implements OffsetMapping.Factory<Current> {
1✔
6187

6188
                                /**
6189
                                 * The singleton instance.
6190
                                 */
6191
                                INSTANCE;
1✔
6192

6193
                                /**
6194
                                 * The {@link Current#typing()} property.
6195
                                 */
6196
                                private static final MethodDescription.InDefinedShape CURRENT_TYPING = TypeDescription.ForLoadedType.of(Current.class)
1✔
6197
                                        .getDeclaredMethods()
1✔
6198
                                        .filter(named("typing"))
1✔
6199
                                        .getOnly();
1✔
6200

6201
                                /**
6202
                                 * {@inheritDoc}
6203
                                 */
6204
                                public Class<Current> getAnnotationType() {
6205
                                    return Current.class;
1✔
6206
                                }
6207

6208
                                /**
6209
                                 * {@inheritDoc}
6210
                                 */
6211
                                public OffsetMapping make(MethodDescription.InDefinedShape target, AnnotationDescription.Loadable<Current> annotation) {
6212
                                    return new ForCurrent(target.getDeclaringType().asGenericType(),
×
6213
                                            annotation.getValue(CURRENT_TYPING).resolve(EnumerationDescription.class).load(Assigner.Typing.class));
×
6214
                                }
6215

6216
                                /**
6217
                                 * {@inheritDoc}
6218
                                 */
6219
                                public OffsetMapping make(ParameterDescription.InDefinedShape target, AnnotationDescription.Loadable<Current> annotation) {
6220
                                    return new ForCurrent(target.getType(), annotation.getValue(CURRENT_TYPING).resolve(EnumerationDescription.class).load(Assigner.Typing.class));
1✔
6221
                                }
6222
                            }
6223

6224
                            /**
6225
                             * A resolved offset mapping for assigning the previous chain instruction.
6226
                             */
6227
                            @HashCodeAndEqualsPlugin.Enhance
6228
                            protected static class Resolved implements OffsetMapping.Resolved {
6229

6230
                                /**
6231
                                 * The type of the targeted expression.
6232
                                 */
6233
                                private final TypeDescription.Generic targetType;
6234

6235
                                /**
6236
                                 * The assigner to use.
6237
                                 */
6238
                                private final Assigner assigner;
6239

6240
                                /**
6241
                                 * The typing to use.
6242
                                 */
6243
                                private final Assigner.Typing typing;
6244

6245
                                /**
6246
                                 * Creates a resolved offset mapping for assigning the previous chain instruction.
6247
                                 *
6248
                                 * @param targetType The type of the targeted expression.
6249
                                 * @param assigner   The assigner to use.
6250
                                 * @param typing     The typing to use.
6251
                                 */
6252
                                public Resolved(TypeDescription.Generic targetType, Assigner assigner, Assigner.Typing typing) {
1✔
6253
                                    this.targetType = targetType;
1✔
6254
                                    this.assigner = assigner;
1✔
6255
                                    this.typing = typing;
1✔
6256
                                }
1✔
6257

6258
                                /**
6259
                                 * {@inheritDoc}
6260
                                 */
6261
                                public StackManipulation apply(Target target,
6262
                                                               TypeList.Generic parameters,
6263
                                                               TypeDescription.Generic result,
6264
                                                               TypeDescription.Generic current,
6265
                                                               JavaConstant.MethodHandle methodHandle,
6266
                                                               Map<Integer, Integer> offsets,
6267
                                                               int offset) {
6268
                                    StackManipulation assignment = assigner.assign(current, targetType, typing);
1✔
6269
                                    if (!assignment.isValid()) {
1✔
6270
                                        throw new IllegalStateException("Cannot assign " + current + " to " + targetType);
×
6271
                                    }
6272
                                    return new StackManipulation.Compound(MethodVariableAccess.of(current).loadFrom(offset), assignment);
1✔
6273
                                }
6274
                            }
6275
                        }
6276
                    }
6277

6278
                    /**
6279
                     * A dispatcher for invoking a delegation method.
6280
                     */
6281
                    protected interface Dispatcher {
6282

6283
                        /**
6284
                         * Resolves a dispatcher for a given instrumented type and method.
6285
                         *
6286
                         * @param instrumentedType   The instrumented type.
6287
                         * @param instrumentedMethod The instrumented method.
6288
                         * @return A resolved version of this dispatcher.
6289
                         */
6290
                        Dispatcher.Resolved resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod);
6291

6292
                        /**
6293
                         * A dispatcher that has been resolved for a given instrumented type and method.
6294
                         */
6295
                        interface Resolved {
6296

6297
                            StackManipulation initialize();
6298

6299
                            /**
6300
                             * Creates a stack manipulation for a given substitution target.
6301
                             *
6302
                             * @param target       The target member of invokedynamic invocation.
6303
                             * @param methodHandle A method handle that describes the invocation.
6304
                             * @return A stack manipulation that executes the represented delegation.
6305
                             */
6306
                            StackManipulation apply(Target target, JavaConstant.MethodHandle methodHandle);
6307
                        }
6308

6309
                        /**
6310
                         * A factory for creating a dispatcher.
6311
                         */
6312
                        interface Factory {
6313

6314
                            /**
6315
                             * Creates a dispatcher for a given delegation method.
6316
                             *
6317
                             * @param delegate The method or constructor to delegate to.
6318
                             * @return An appropriate dispatcher.
6319
                             */
6320
                            Dispatcher make(MethodDescription.InDefinedShape delegate);
6321
                        }
6322

6323
                        /**
6324
                         * A dispatcher that invokes a delegate method directly.
6325
                         */
6326
                        @HashCodeAndEqualsPlugin.Enhance
6327
                        class ForRegularInvocation implements Dispatcher, Dispatcher.Resolved {
6328

6329
                            /**
6330
                             * The delegation method.
6331
                             */
6332
                            private final MethodDescription delegate;
6333

6334
                            /**
6335
                             * Creates a dispatcher for a regular method invocation.
6336
                             *
6337
                             * @param delegate The delegation method.
6338
                             */
6339
                            protected ForRegularInvocation(MethodDescription delegate) {
1✔
6340
                                this.delegate = delegate;
1✔
6341
                            }
1✔
6342

6343
                            /**
6344
                             * {@inheritDoc}
6345
                             */
6346
                            public Resolved resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
6347
                                return this;
1✔
6348
                            }
6349

6350
                            /**
6351
                             * {@inheritDoc}
6352
                             */
6353
                            public StackManipulation initialize() {
6354
                                return delegate.isConstructor()
1✔
6355
                                        ? new StackManipulation.Compound(TypeCreation.of(delegate.getDeclaringType().asErasure()), Duplication.SINGLE)
1✔
6356
                                        : StackManipulation.Trivial.INSTANCE;
6357
                            }
6358

6359
                            /**
6360
                             * {@inheritDoc}
6361
                             */
6362
                            public StackManipulation apply(Target target, JavaConstant.MethodHandle methodHandle) {
6363
                                return MethodInvocation.invoke(delegate);
1✔
6364
                            }
6365

6366
                            /**
6367
                             * A factory for creating a dispatcher for a regular method invocation.
6368
                             */
6369
                            protected enum Factory implements Dispatcher.Factory {
1✔
6370

6371
                                /**
6372
                                 * The singleton instance.
6373
                                 */
6374
                                INSTANCE;
1✔
6375

6376
                                /**
6377
                                 * {@inheritDoc}
6378
                                 */
6379
                                public Dispatcher make(MethodDescription.InDefinedShape delegate) {
6380
                                    return new ForRegularInvocation(delegate);
1✔
6381
                                }
6382
                            }
6383
                        }
6384

6385
                        /**
6386
                         * A method dispatcher that is using a dynamic method invocation.
6387
                         */
6388
                        @HashCodeAndEqualsPlugin.Enhance
6389
                        class ForDynamicInvocation implements Dispatcher {
6390

6391
                            /**
6392
                             * The bootstrap method.
6393
                             */
6394
                            private final MethodDescription.InDefinedShape bootstrapMethod;
6395

6396
                            /**
6397
                             * The delegation method.
6398
                             */
6399
                            private final MethodDescription.InDefinedShape delegate;
6400

6401
                            /**
6402
                             * A resolver for supplying arguments to the bootstrap method.
6403
                             */
6404
                            private final BootstrapArgumentResolver resolver;
6405

6406
                            /**
6407
                             * Creates a dispatcher for a dynamic method invocation.
6408
                             *
6409
                             * @param bootstrapMethod The bootstrap method.
6410
                             * @param delegate        The delegation method.
6411
                             * @param resolver        A resolver for supplying arguments to the bootstrap method.
6412
                             */
6413
                            protected ForDynamicInvocation(MethodDescription.InDefinedShape bootstrapMethod,
6414
                                                           MethodDescription.InDefinedShape delegate,
6415
                                                           BootstrapArgumentResolver resolver) {
×
6416
                                this.bootstrapMethod = bootstrapMethod;
×
6417
                                this.delegate = delegate;
×
6418
                                this.resolver = resolver;
×
6419
                            }
×
6420

6421
                            /**
6422
                             * Creates a dispatcher factory for a dynamic method invocation.
6423
                             *
6424
                             * @param bootstrapMethod The bootstrap method.
6425
                             * @param resolverFactory A resolver for supplying arguments to the bootstrap method.
6426
                             * @return An appropriate dispatcher factory.
6427
                             */
6428
                            protected static Dispatcher.Factory of(MethodDescription.InDefinedShape bootstrapMethod,
6429
                                                                   BootstrapArgumentResolver.Factory resolverFactory) {
6430
                                if (!bootstrapMethod.isInvokeBootstrap()) {
×
6431
                                    throw new IllegalStateException("Not a bootstrap method: " + bootstrapMethod);
×
6432
                                }
6433
                                return new ForDynamicInvocation.Factory(bootstrapMethod, resolverFactory);
×
6434
                            }
6435

6436
                            /**
6437
                             * {@inheritDoc}
6438
                             */
6439
                            public Dispatcher.Resolved resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
6440
                                return new ForDynamicInvocation.Resolved(bootstrapMethod, delegate, resolver.resolve(instrumentedType, instrumentedMethod));
×
6441
                            }
6442

6443
                            /**
6444
                             * A resolved dispatcher for a dynamically bound method invocation.
6445
                             */
6446
                            @HashCodeAndEqualsPlugin.Enhance
6447
                            protected static class Resolved implements Dispatcher.Resolved {
6448

6449
                                /**
6450
                                 * The bootstrap method.
6451
                                 */
6452
                                private final MethodDescription.InDefinedShape bootstrapMethod;
6453

6454
                                /**
6455
                                 * The delegation target.
6456
                                 */
6457
                                private final MethodDescription.InDefinedShape delegate;
6458

6459
                                /**
6460
                                 * The bootstrap argument resolver to use.
6461
                                 */
6462
                                private final BootstrapArgumentResolver.Resolved resolver;
6463

6464
                                /**
6465
                                 * Creates a resolved dispatcher of a dynamic method dispatcher.
6466
                                 *
6467
                                 * @param bootstrapMethod The bootstrap method.
6468
                                 * @param delegate        The delegation target.
6469
                                 * @param resolver        The bootstrap argument resolver to use.
6470
                                 */
6471
                                protected Resolved(MethodDescription.InDefinedShape bootstrapMethod,
6472
                                                   MethodDescription.InDefinedShape delegate,
6473
                                                   BootstrapArgumentResolver.Resolved resolver) {
×
6474
                                    this.bootstrapMethod = bootstrapMethod;
×
6475
                                    this.delegate = delegate;
×
6476
                                    this.resolver = resolver;
×
6477
                                }
×
6478

6479
                                /**
6480
                                 * {@inheritDoc}
6481
                                 */
6482
                                public StackManipulation initialize() {
6483
                                    return StackManipulation.Trivial.INSTANCE;
×
6484
                                }
6485

6486
                                /**
6487
                                 * {@inheritDoc}
6488
                                 */
6489
                                public StackManipulation apply(Target target, JavaConstant.MethodHandle methodHandle) {
6490
                                    List<JavaConstant> constants = resolver.make(target, methodHandle);
×
6491
                                    if (!bootstrapMethod.isInvokeBootstrap(TypeList.Explicit.of(constants))) {
×
6492
                                        throw new IllegalArgumentException(bootstrapMethod + " is not accepting advice bootstrap arguments: " + constants);
×
6493
                                    }
6494
                                    return MethodInvocation.invoke(bootstrapMethod).dynamic(delegate.getInternalName(),
×
6495
                                            delegate.getReturnType().asErasure(),
×
6496
                                            delegate.getParameters().asTypeList().asErasures(),
×
6497
                                            constants);
6498
                                }
6499
                            }
6500

6501
                            /**
6502
                             * A factory for a dynamic method invocation of the dispatcher method or constructor.
6503
                             */
6504
                            @HashCodeAndEqualsPlugin.Enhance
6505
                            protected static class Factory implements Dispatcher.Factory {
6506

6507
                                /**
6508
                                 * The bootstrap method.
6509
                                 */
6510
                                private final MethodDescription.InDefinedShape bootstrapMethod;
6511

6512
                                /**
6513
                                 * A factory for a bootstrap argument resolver.
6514
                                 */
6515
                                private final BootstrapArgumentResolver.Factory resolverFactory;
6516

6517
                                /**
6518
                                 * Creates a new factory for a dispatcher using a dynamic method invocation.
6519
                                 *
6520
                                 * @param bootstrapMethod The bootstrap method.
6521
                                 * @param resolverFactory A factory for a bootstrap argument resolver.
6522
                                 */
6523
                                protected Factory(MethodDescription.InDefinedShape bootstrapMethod,
6524
                                                  BootstrapArgumentResolver.Factory resolverFactory) {
×
6525
                                    this.bootstrapMethod = bootstrapMethod;
×
6526
                                    this.resolverFactory = resolverFactory;
×
6527
                                }
×
6528

6529
                                /**
6530
                                 * {@inheritDoc}
6531
                                 */
6532
                                public Dispatcher make(MethodDescription.InDefinedShape delegate) {
6533
                                    return new ForDynamicInvocation(bootstrapMethod, delegate, resolverFactory.make(delegate));
×
6534
                                }
6535
                            }
6536
                        }
6537
                    }
6538

6539
                    /**
6540
                     * A resolver for supplying arguments to a bootstrap method which is binding the delegation method's invocation.
6541
                     */
6542
                    public interface BootstrapArgumentResolver {
6543

6544
                        /**
6545
                         * Resolves this resolver for a given instrumented type and method.
6546
                         *
6547
                         * @param instrumentedType   The instrumented type.
6548
                         * @param instrumentedMethod The instrumented method.
6549
                         * @return A resolved version of this argument resolver.
6550
                         */
6551
                        BootstrapArgumentResolver.Resolved resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod);
6552

6553
                        /**
6554
                         * A resolved version of a bootstrap argument handler.
6555
                         */
6556
                        interface Resolved {
6557

6558
                            /**
6559
                             * Returns the constant values to supply to the bootstrap method.
6560
                             *
6561
                             * @param target       The target member of invokedynamic invocation.
6562
                             * @param methodHandle A method handle that represents the substituted element.
6563
                             * @return A list of constant values to supply to the bootstrap method.
6564
                             */
6565
                            List<JavaConstant> make(Target target, JavaConstant.MethodHandle methodHandle);
6566
                        }
6567

6568
                        /**
6569
                         * A factory for a bootstrap argument resolver.
6570
                         */
6571
                        interface Factory {
6572

6573
                            /**
6574
                             * Creates a bootstrap argument resolver for a given delegation method.
6575
                             *
6576
                             * @param delegate The method or constructor to which to delegate.
6577
                             * @return An appropriate bootstrap argument resolver.
6578
                             */
6579
                            BootstrapArgumentResolver make(MethodDescription.InDefinedShape delegate);
6580
                        }
6581

6582
                        /**
6583
                         * An implementation that supplies a default set of arguments to a bootstrap method. The arguments are:
6584
                         * <ul>
6585
                         * <li>A {@code java.lang.invoke.MethodHandles.Lookup} representing the source method.</li>
6586
                         * <li>A {@link String} representing the target's internal name.</li>
6587
                         * <li>A {@code java.lang.invoke.MethodType} representing the type that is requested for binding.</li>
6588
                         * <li>A {@link String} representation of the delegate's binary class name.</li>
6589
                         * <li>A {@link Class} representing the receiver type of the substituted element.</li>
6590
                         * <li>A {@link String} representing the internal name of the substituted element.</li>
6591
                         * <li>A {@code java.lang.invoke.MethodHandle} to the substituted element.</li>
6592
                         * <li>A {@link Class} describing the instrumented type.</li>
6593
                         * <li>A {@link String} representing the instrumented method or constructor.</li>
6594
                         * </ul>
6595
                         */
6596
                        @HashCodeAndEqualsPlugin.Enhance
6597
                        class ForDefaultValues implements BootstrapArgumentResolver {
6598

6599
                            /**
6600
                             * The delegation target.
6601
                             */
6602
                            private final MethodDescription.InDefinedShape delegate;
6603

6604
                            /**
6605
                             * Creates a default bootstrap argument resolver.
6606
                             *
6607
                             * @param delegate The delegation target.
6608
                             */
6609
                            protected ForDefaultValues(MethodDescription.InDefinedShape delegate) {
×
6610
                                this.delegate = delegate;
×
6611
                            }
×
6612

6613
                            /**
6614
                             * {@inheritDoc}
6615
                             */
6616
                            public BootstrapArgumentResolver.Resolved resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
6617
                                return new Resolved(delegate, instrumentedType, instrumentedMethod);
×
6618
                            }
6619

6620
                            /**
6621
                             * A resolved default bootstrap argument resolver.
6622
                             */
6623
                            @HashCodeAndEqualsPlugin.Enhance
6624
                            protected static class Resolved implements BootstrapArgumentResolver.Resolved {
6625

6626
                                /**
6627
                                 * The delegation target.
6628
                                 */
6629
                                private final MethodDescription.InDefinedShape delegate;
6630

6631
                                /**
6632
                                 * The instrumented type.
6633
                                 */
6634
                                private final TypeDescription instrumentedType;
6635

6636
                                /**
6637
                                 * The instrumented method.
6638
                                 */
6639
                                private final MethodDescription instrumentedMethod;
6640

6641
                                /**
6642
                                 * Creates a resolved version of a bootstrap argument resolver.
6643
                                 *
6644
                                 * @param delegate           The delegation target.
6645
                                 * @param instrumentedType   The instrumented type.
6646
                                 * @param instrumentedMethod The instrumented method.
6647
                                 */
6648
                                protected Resolved(MethodDescription.InDefinedShape delegate, TypeDescription instrumentedType, MethodDescription instrumentedMethod) {
×
6649
                                    this.delegate = delegate;
×
6650
                                    this.instrumentedType = instrumentedType;
×
6651
                                    this.instrumentedMethod = instrumentedMethod;
×
6652
                                }
×
6653

6654
                                /**
6655
                                 * {@inheritDoc}
6656
                                 */
6657
                                public List<JavaConstant> make(Target target, JavaConstant.MethodHandle methodHandle) {
6658
                                    if (instrumentedMethod.isTypeInitializer()) {
×
6659
                                        return Arrays.asList(JavaConstant.Simple.ofLoaded(delegate.getDeclaringType().getName()),
×
6660
                                                JavaConstant.Simple.of(target instanceof Target.ForMember
×
6661
                                                        ? ((Target.ForMember) target).getReceiverType()
×
6662
                                                        : TypeDescription.ForLoadedType.of(void.class)),
×
6663
                                                JavaConstant.Simple.ofLoaded(target.getName()),
×
6664
                                                methodHandle,
6665
                                                JavaConstant.Simple.of(instrumentedType),
×
6666
                                                JavaConstant.Simple.ofLoaded(instrumentedMethod.getInternalName()));
×
6667
                                    } else {
6668
                                        return Arrays.asList(JavaConstant.Simple.ofLoaded(delegate.getDeclaringType().getName()),
×
6669
                                                JavaConstant.Simple.of(target instanceof Target.ForMember
×
6670
                                                        ? ((Target.ForMember) target).getReceiverType()
×
6671
                                                        : TypeDescription.ForLoadedType.of(void.class)),
×
6672
                                                JavaConstant.Simple.ofLoaded(target.getName()),
×
6673
                                                methodHandle,
6674
                                                JavaConstant.Simple.of(instrumentedType),
×
6675
                                                JavaConstant.Simple.ofLoaded(instrumentedMethod.getInternalName()),
×
6676
                                                JavaConstant.MethodHandle.of(instrumentedMethod.asDefined()));
×
6677
                                    }
6678
                                }
6679
                            }
6680

6681
                            /**
6682
                             * A factory for creating a default bootstrap argument resolver.
6683
                             */
6684
                            public enum Factory implements BootstrapArgumentResolver.Factory {
×
6685

6686
                                /**
6687
                                 * The singleton instance.
6688
                                 */
6689
                                INSTANCE;
×
6690

6691
                                /**
6692
                                 * {@inheritDoc}
6693
                                 */
6694
                                public BootstrapArgumentResolver make(MethodDescription.InDefinedShape delegate) {
6695
                                    return new ForDefaultValues(delegate);
×
6696
                                }
6697
                            }
6698
                        }
6699
                    }
6700

6701
                    /**
6702
                     * A factory for a {@link ForDelegation} which allows for a custom configuration.
6703
                     */
6704
                    public static class WithCustomMapping {
6705

6706
                        /**
6707
                         * The dispatcher factory to use.
6708
                         */
6709
                        private final Dispatcher.Factory dispatcherFactory;
6710

6711
                        /**
6712
                         * A mapping of offset mapping factories by their respective annotation type.
6713
                         */
6714
                        private final Map<Class<? extends Annotation>, OffsetMapping.Factory<?>> offsetMappings;
6715

6716
                        /**
6717
                         * Creates a factory for a {@link ForDelegation} with a custom value.
6718
                         *
6719
                         * @param dispatcherFactory The dispatcher factory to use.
6720
                         * @param offsetMappings    A mapping of offset mapping factories by their respective annotation type.
6721
                         */
6722
                        protected WithCustomMapping(Dispatcher.Factory dispatcherFactory, Map<Class<? extends Annotation>, OffsetMapping.Factory<?>> offsetMappings) {
1✔
6723
                            this.dispatcherFactory = dispatcherFactory;
1✔
6724
                            this.offsetMappings = offsetMappings;
1✔
6725
                        }
1✔
6726

6727
                        /**
6728
                         * Binds the supplied annotation to a type constant of the supplied value. Constants can be strings, method handles, method types
6729
                         * and any primitive or the value {@code null}.
6730
                         *
6731
                         * @param type  The type of the annotation being bound.
6732
                         * @param value The value to bind to the annotation or {@code null} to bind the parameter type's default value.
6733
                         * @param <T>   The annotation type.
6734
                         * @return A new builder for a delegate that considers the supplied annotation type during binding.
6735
                         */
6736
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, @MaybeNull Object value) {
6737
                            return bind(OffsetMapping.ForStackManipulation.of(type, value));
×
6738
                        }
6739

6740
                        /**
6741
                         * Binds the supplied annotation to the value of the supplied field. The field must be visible by the
6742
                         * instrumented type and must be declared by a super type of the instrumented field.
6743
                         *
6744
                         * @param type  The type of the annotation being bound.
6745
                         * @param field The field to bind to this annotation.
6746
                         * @param <T>   The annotation type.
6747
                         * @return A new builder for a delegate that considers the supplied annotation type during binding.
6748
                         */
6749
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, Field field) {
6750
                            return bind(type, new FieldDescription.ForLoadedField(field));
1✔
6751
                        }
6752

6753
                        /**
6754
                         * Binds the supplied annotation to the value of the supplied field. The field must be visible by the
6755
                         * instrumented type and must be declared by a super type of the instrumented field. The binding is defined
6756
                         * as read-only and applied static typing.
6757
                         *
6758
                         * @param type             The type of the annotation being bound.
6759
                         * @param fieldDescription The field to bind to this annotation.
6760
                         * @param <T>              The annotation type.
6761
                         * @return A new builder for a delegate that considers the supplied annotation type during binding.
6762
                         */
6763
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, FieldDescription fieldDescription) {
6764
                            return bind(new OffsetMapping.ForField.Resolved.Factory<T>(type, fieldDescription));
1✔
6765
                        }
6766

6767
                        /**
6768
                         * Binds the supplied annotation to the supplied type constant.
6769
                         *
6770
                         * @param type  The type of the annotation being bound.
6771
                         * @param value The type constant to bind.
6772
                         * @param <T>   The annotation type.
6773
                         * @return A new builder for a delegate that considers the supplied annotation type during binding.
6774
                         */
6775
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, Class<?> value) {
6776
                            return bind(type, TypeDescription.ForLoadedType.of(value));
×
6777
                        }
6778

6779
                        /**
6780
                         * Binds the supplied annotation to the supplied type constant.
6781
                         *
6782
                         * @param type  The type of the annotation being bound.
6783
                         * @param value The type constant to bind.
6784
                         * @param <T>   The annotation type.
6785
                         * @return A new builder for a delegate that considers the supplied annotation type during binding.
6786
                         */
6787
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, TypeDescription value) {
6788
                            return bind(new OffsetMapping.ForStackManipulation.Factory<T>(type, ConstantValue.Simple.wrap(value)));
×
6789
                        }
6790

6791
                        /**
6792
                         * Binds the supplied annotation to the supplied enumeration constant.
6793
                         *
6794
                         * @param type  The type of the annotation being bound.
6795
                         * @param value The enumeration constant to bind.
6796
                         * @param <T>   The annotation type.
6797
                         * @return A new builder for a delegate that considers the supplied annotation type during binding.
6798
                         */
6799
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, Enum<?> value) {
6800
                            return bind(type, new EnumerationDescription.ForLoadedEnumeration(value));
×
6801
                        }
6802

6803
                        /**
6804
                         * Binds the supplied annotation to the supplied enumeration constant.
6805
                         *
6806
                         * @param type  The type of the annotation being bound.
6807
                         * @param value The enumeration constant to bind.
6808
                         * @param <T>   The annotation type.
6809
                         * @return A new builder for a delegate that considers the supplied annotation type during binding.
6810
                         */
6811
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, EnumerationDescription value) {
6812
                            return bind(new OffsetMapping.ForStackManipulation.Factory<T>(type, ConstantValue.Simple.wrap(value)));
×
6813
                        }
6814

6815
                        /**
6816
                         * Binds the supplied annotation to the supplied fixed value.
6817
                         *
6818
                         * @param type  The type of the annotation being bound.
6819
                         * @param value The value to bind to this annotation.
6820
                         * @param <T>   The annotation type.
6821
                         * @return A new builder for a delegate that considers the supplied annotation type during binding.
6822
                         */
6823
                        @SuppressWarnings("unchecked")
6824
                        public <T extends Annotation> WithCustomMapping bindSerialized(Class<T> type, Serializable value) {
6825
                            return bindSerialized(type, value, (Class<Serializable>) value.getClass());
1✔
6826
                        }
6827

6828
                        /**
6829
                         * Binds the supplied annotation to the supplied fixed value.
6830
                         *
6831
                         * @param type       The type of the annotation being bound.
6832
                         * @param value      The value to bind to this annotation.
6833
                         * @param targetType The type of {@code value} as which the instance should be treated.
6834
                         * @param <T>        The annotation type.
6835
                         * @param <S>        The type of the serialized instance.
6836
                         * @return A new builder for a delegate that considers the supplied annotation type during binding.
6837
                         */
6838
                        public <T extends Annotation, S extends Serializable> WithCustomMapping bindSerialized(Class<T> type, S value, Class<? super S> targetType) {
6839
                            return bind(OffsetMapping.ForStackManipulation.OfSerializedConstant.of(type, value, targetType));
1✔
6840
                        }
6841

6842
                        /**
6843
                         * Binds the supplied annotation to the annotation's property of the specified name.
6844
                         *
6845
                         * @param type     The type of the annotation being bound.
6846
                         * @param property The name of the annotation property to be bound.
6847
                         * @param <T>      The annotation type.
6848
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6849
                         */
6850
                        public <T extends Annotation> WithCustomMapping bindProperty(Class<T> type, String property) {
6851
                            return bind(OffsetMapping.ForStackManipulation.OfAnnotationProperty.of(type, property));
×
6852
                        }
6853

6854
                        /**
6855
                         * Binds the supplied annotation to the given Java constant.
6856
                         *
6857
                         * @param type     The type of the annotation being bound.
6858
                         * @param constant The constant value that is bound.
6859
                         * @param <T>      The annotation type.
6860
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6861
                         */
6862
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, ConstantValue constant) {
6863
                            return bind(new OffsetMapping.ForStackManipulation.Factory<T>(type, constant.toStackManipulation(), constant.getTypeDescription().asGenericType()));
×
6864
                        }
6865

6866
                        /**
6867
                         * Binds the supplied annotation to the annotation's property of the specified name.
6868
                         *
6869
                         * @param type              The type of the annotation being bound.
6870
                         * @param stackManipulation The stack manipulation loading the bound value.
6871
                         * @param targetType        The type of the loaded value.
6872
                         * @param <T>               The annotation type.
6873
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6874
                         */
6875
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, StackManipulation stackManipulation, java.lang.reflect.Type targetType) {
6876
                            return bind(type, stackManipulation, TypeDefinition.Sort.describe(targetType));
×
6877
                        }
6878

6879
                        /**
6880
                         * Binds the supplied annotation to the annotation's property of the specified name.
6881
                         *
6882
                         * @param type              The type of the annotation being bound.
6883
                         * @param stackManipulation The stack manipulation loading the bound value.
6884
                         * @param targetType        The type of the loaded value.
6885
                         * @param <T>               The annotation type.
6886
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6887
                         */
6888
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, StackManipulation stackManipulation, TypeDescription.Generic targetType) {
6889
                            return bind(new OffsetMapping.ForStackManipulation.Factory<T>(type, stackManipulation, targetType));
×
6890
                        }
6891

6892
                        /**
6893
                         * Binds the supplied annotation as a lambda expression via the JVM's lambda metafactory.
6894
                         *
6895
                         * @param type                The type of the annotation being bound.
6896
                         * @param constructor         The constructor being bound as the lambda expression's implementation.
6897
                         * @param functionalInterface The functional interface that represents the lambda expression.
6898
                         * @param <T>                 The annotation type.
6899
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6900
                         */
6901
                        public <T extends Annotation> WithCustomMapping bindLambda(Class<T> type, Constructor<?> constructor, Class<?> functionalInterface) {
6902
                            return bindLambda(type, new MethodDescription.ForLoadedConstructor(constructor), TypeDescription.ForLoadedType.of(functionalInterface));
×
6903
                        }
6904

6905
                        /**
6906
                         * Binds the supplied annotation as a lambda expression via the JVM's lambda metafactory.
6907
                         *
6908
                         * @param type                The type of the annotation being bound.
6909
                         * @param constructor         The constructor being bound as the lambda expression's implementation.
6910
                         * @param functionalInterface The functional interface that represents the lambda expression.
6911
                         * @param methodGraphCompiler The method graph compiler that resolves the functional method of the function interface.
6912
                         * @param <T>                 The annotation type.
6913
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6914
                         */
6915
                        public <T extends Annotation> WithCustomMapping bindLambda(Class<T> type, Constructor<?> constructor, Class<?> functionalInterface, MethodGraph.Compiler methodGraphCompiler) {
6916
                            return bindLambda(type, new MethodDescription.ForLoadedConstructor(constructor), TypeDescription.ForLoadedType.of(functionalInterface), methodGraphCompiler);
×
6917
                        }
6918

6919
                        /**
6920
                         * Binds the supplied annotation as a lambda expression via the JVM's lambda metafactory.
6921
                         *
6922
                         * @param type                The type of the annotation being bound.
6923
                         * @param method              The method being bound as the lambda expression's implementation.
6924
                         * @param functionalInterface The functional interface that represents the lambda expression.
6925
                         * @param <T>                 The annotation type.
6926
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6927
                         */
6928
                        public <T extends Annotation> WithCustomMapping bindLambda(Class<T> type, Method method, Class<?> functionalInterface) {
6929
                            return bindLambda(type, new MethodDescription.ForLoadedMethod(method), TypeDescription.ForLoadedType.of(functionalInterface));
×
6930
                        }
6931

6932
                        /**
6933
                         * Binds the supplied annotation as a lambda expression via the JVM's lambda metafactory.
6934
                         *
6935
                         * @param type                The type of the annotation being bound.
6936
                         * @param method              The method being bound as the lambda expression's implementation.
6937
                         * @param functionalInterface The functional interface that represents the lambda expression.
6938
                         * @param methodGraphCompiler The method graph compiler that resolves the functional method of the function interface.
6939
                         * @param <T>                 The annotation type.
6940
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6941
                         */
6942
                        public <T extends Annotation> WithCustomMapping bindLambda(Class<T> type, Method method, Class<?> functionalInterface, MethodGraph.Compiler methodGraphCompiler) {
6943
                            return bindLambda(type, new MethodDescription.ForLoadedMethod(method), TypeDescription.ForLoadedType.of(functionalInterface), methodGraphCompiler);
×
6944
                        }
6945

6946
                        /**
6947
                         * Binds the supplied annotation as a lambda expression via the JVM's lambda metafactory.
6948
                         *
6949
                         * @param type                The type of the annotation being bound.
6950
                         * @param methodDescription   The method or constructor being bound as the lambda expression's implementation.
6951
                         * @param functionalInterface The functional interface that represents the lambda expression.
6952
                         * @param <T>                 The annotation type.
6953
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6954
                         */
6955
                        public <T extends Annotation> WithCustomMapping bindLambda(Class<T> type, MethodDescription.InDefinedShape methodDescription, TypeDescription functionalInterface) {
6956
                            return bindLambda(type, methodDescription, functionalInterface, MethodGraph.Compiler.DEFAULT);
×
6957
                        }
6958

6959
                        /**
6960
                         * Binds the supplied annotation as a lambda expression via the JVM's lambda metafactory.
6961
                         *
6962
                         * @param type                The type of the annotation being bound.
6963
                         * @param methodDescription   The method or constuctor being bound as the lambda expression's implementation.
6964
                         * @param functionalInterface The functional interface that represents the lambda expression.
6965
                         * @param methodGraphCompiler The method graph compiler that resolves the functional method of the function interface.
6966
                         * @param <T>                 The annotation type.
6967
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
6968
                         */
6969
                        public <T extends Annotation> WithCustomMapping bindLambda(Class<T> type,
6970
                                                                                   MethodDescription.InDefinedShape methodDescription,
6971
                                                                                   TypeDescription functionalInterface,
6972
                                                                                   MethodGraph.Compiler methodGraphCompiler) {
6973
                            if (!functionalInterface.isInterface()) {
×
6974
                                throw new IllegalArgumentException(functionalInterface + " is not an interface type");
×
6975
                            }
6976
                            MethodList<?> methods = methodGraphCompiler.compile((TypeDefinition) functionalInterface).listNodes().asMethodList().filter(isAbstract());
×
6977
                            if (methods.size() != 1) {
×
6978
                                throw new IllegalArgumentException(functionalInterface + " does not define exactly one abstract method: " + methods);
×
6979
                            }
6980
                            return bindDynamic(type, new MethodDescription.Latent(new TypeDescription.Latent("java.lang.invoke.LambdaMetafactory",
×
6981
                                            Opcodes.ACC_PUBLIC,
6982
                                            TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class)),
×
6983
                                            "metafactory",
6984
                                            Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC,
6985
                                            Collections.<TypeVariableToken>emptyList(),
×
6986
                                            JavaType.CALL_SITE.getTypeStub().asGenericType(),
×
6987
                                            Arrays.asList(
×
6988
                                                    new ParameterDescription.Token(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub().asGenericType()),
×
6989
                                                    new ParameterDescription.Token(TypeDescription.ForLoadedType.of(String.class).asGenericType()),
×
6990
                                                    new ParameterDescription.Token(JavaType.METHOD_TYPE.getTypeStub().asGenericType()),
×
6991
                                                    new ParameterDescription.Token(JavaType.METHOD_TYPE.getTypeStub().asGenericType()),
×
6992
                                                    new ParameterDescription.Token(JavaType.METHOD_HANDLE.getTypeStub().asGenericType()),
×
6993
                                                    new ParameterDescription.Token(JavaType.METHOD_TYPE.getTypeStub().asGenericType())),
×
6994
                                            Collections.<TypeDescription.Generic>emptyList(),
×
6995
                                            Collections.<AnnotationDescription>emptyList(),
×
6996
                                            AnnotationValue.UNDEFINED,
6997
                                            TypeDescription.Generic.UNDEFINED),
6998
                                    JavaConstant.MethodType.ofSignature(methods.asDefined().getOnly()),
×
6999
                                    JavaConstant.MethodHandle.of(methodDescription),
×
7000
                                    JavaConstant.MethodType.ofSignature(methods.asDefined().getOnly()));
×
7001
                        }
7002

7003
                        /**
7004
                         * Binds the supplied annotation to a dynamically bootstrapped value.
7005
                         *
7006
                         * @param type            The type of the annotation being bound.
7007
                         * @param bootstrapMethod The bootstrap method returning the call site.
7008
                         * @param constant        The arguments supplied to the bootstrap method.
7009
                         * @param <T>             The annotation type.
7010
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
7011
                         */
7012
                        public <T extends Annotation> WithCustomMapping bindDynamic(Class<T> type, Method bootstrapMethod, Object... constant) {
7013
                            return bindDynamic(type, bootstrapMethod, Arrays.asList(constant));
×
7014
                        }
7015

7016
                        /**
7017
                         * Binds the supplied annotation to a dynamically bootstrapped value.
7018
                         *
7019
                         * @param type            The type of the annotation being bound.
7020
                         * @param bootstrapMethod The bootstrap method returning the call site.
7021
                         * @param constants       The arguments supplied to the bootstrap method.
7022
                         * @param <T>             The annotation type.
7023
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
7024
                         */
7025
                        public <T extends Annotation> WithCustomMapping bindDynamic(Class<T> type, Method bootstrapMethod, List<?> constants) {
7026
                            return bindDynamic(type, new MethodDescription.ForLoadedMethod(bootstrapMethod), constants);
×
7027
                        }
7028

7029
                        /**
7030
                         * Binds the supplied annotation to a dynamically bootstrapped value.
7031
                         *
7032
                         * @param type            The type of the annotation being bound.
7033
                         * @param bootstrapMethod The bootstrap constructor returning the call site.
7034
                         * @param constant        The arguments supplied to the bootstrap method.
7035
                         * @param <T>             The annotation type.
7036
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
7037
                         */
7038
                        public <T extends Annotation> WithCustomMapping bindDynamic(Class<T> type, Constructor<?> bootstrapMethod, Object... constant) {
7039
                            return bindDynamic(type, bootstrapMethod, Arrays.asList(constant));
×
7040
                        }
7041

7042
                        /**
7043
                         * Binds the supplied annotation to a dynamically bootstrapped value.
7044
                         *
7045
                         * @param type            The type of the annotation being bound.
7046
                         * @param bootstrapMethod The bootstrap constructor returning the call site.
7047
                         * @param constants       The arguments supplied to the bootstrap method.
7048
                         * @param <T>             The annotation type.
7049
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
7050
                         */
7051
                        public <T extends Annotation> WithCustomMapping bindDynamic(Class<T> type, Constructor<?> bootstrapMethod, List<?> constants) {
7052
                            return bindDynamic(type, new MethodDescription.ForLoadedConstructor(bootstrapMethod), constants);
×
7053
                        }
7054

7055
                        /**
7056
                         * Binds the supplied annotation to a dynamically bootstrapped value.
7057
                         *
7058
                         * @param type            The type of the annotation being bound.
7059
                         * @param bootstrapMethod The bootstrap method or constructor returning the call site.
7060
                         * @param constant        The arguments supplied to the bootstrap method.
7061
                         * @param <T>             The annotation type.
7062
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
7063
                         */
7064
                        public <T extends Annotation> WithCustomMapping bindDynamic(Class<T> type, MethodDescription.InDefinedShape bootstrapMethod, Object... constant) {
7065
                            return bindDynamic(type, bootstrapMethod, Arrays.asList(constant));
×
7066
                        }
7067

7068
                        /**
7069
                         * Binds the supplied annotation to a dynamically bootstrapped value.
7070
                         *
7071
                         * @param type            The type of the annotation being bound.
7072
                         * @param bootstrapMethod The bootstrap method or constructor returning the call site.
7073
                         * @param constants       The arguments supplied to the bootstrap method.
7074
                         * @param <T>             The annotation type.
7075
                         * @return A new builder for a delegate that considers the supplied annotation during binding.
7076
                         */
7077
                        public <T extends Annotation> WithCustomMapping bindDynamic(Class<T> type, MethodDescription.InDefinedShape bootstrapMethod, List<?> constants) {
7078
                            List<JavaConstant> arguments = JavaConstant.Simple.wrap(constants);
×
7079
                            if (!bootstrapMethod.isInvokeBootstrap(TypeList.Explicit.of(arguments))) {
×
7080
                                throw new IllegalArgumentException("Not a valid bootstrap method " + bootstrapMethod + " for " + arguments);
×
7081
                            }
7082
                            return bind(new OffsetMapping.ForStackManipulation.OfDynamicInvocation<T>(type, bootstrapMethod, arguments));
×
7083
                        }
7084

7085
                        /**
7086
                         * Binds the supplied annotation to the annotation's property of the specified name.
7087
                         *
7088
                         * @param type          The type of the annotation being bound.
7089
                         * @param offsetMapping The offset mapping being bound.
7090
                         * @param <T>           The annotation type.
7091
                         * @return A new builder for a delegation that considers the supplied annotation during binding.
7092
                         */
7093
                        public <T extends Annotation> WithCustomMapping bind(Class<T> type, OffsetMapping offsetMapping) {
7094
                            return bind(new OffsetMapping.Factory.Simple<T>(type, offsetMapping));
×
7095
                        }
7096

7097
                        /**
7098
                         * Binds an annotation to a dynamically computed value. Whenever the {@link ForDelegation} target discovers the given annotation on
7099
                         * a parameter of an advice method, the dynamic value is asked to provide a value that is then assigned to the parameter in question.
7100
                         *
7101
                         * @param offsetMapping The dynamic value that is computed for binding the parameter to a value.
7102
                         * @return A new builder for a delegation that considers the supplied annotation type during binding.
7103
                         */
7104
                        public WithCustomMapping bind(OffsetMapping.Factory<?> offsetMapping) {
7105
                            Map<Class<? extends Annotation>, OffsetMapping.Factory<?>> offsetMappings = new LinkedHashMap<Class<? extends Annotation>, OffsetMapping.Factory<?>>(this.offsetMappings);
1✔
7106
                            if (!offsetMapping.getAnnotationType().isAnnotation()) {
1✔
7107
                                throw new IllegalArgumentException("Not an annotation type: " + offsetMapping.getAnnotationType());
×
7108
                            } else if (offsetMappings.put(offsetMapping.getAnnotationType(), offsetMapping) != null) {
1✔
7109
                                throw new IllegalArgumentException("Annotation type already mapped: " + offsetMapping.getAnnotationType());
×
7110
                            }
7111
                            return new WithCustomMapping(dispatcherFactory, offsetMappings);
1✔
7112
                        }
7113

7114
                        /**
7115
                         * Defines the supplied constructor as a dynamic invocation bootstrap target for delegating advice methods. The bootstrap
7116
                         * method arguments are:
7117
                         * <ul>
7118
                         * <li>A {@code java.lang.invoke.MethodHandles.Lookup} representing the source method.</li>
7119
                         * <li>A {@link String} representing the constructor's internal name {@code <init>}.</li>
7120
                         * <li>A {@code java.lang.invoke.MethodType} representing the type that is requested for binding.</li>
7121
                         * <li>A {@link String} representation of the delegate's binary class name.</li>
7122
                         * <li>A {@link Class} representing the receiver type of the substituted element.</li>
7123
                         * <li>A {@link String} representing the internal name of the substituted element.</li>
7124
                         * <li>A {@code java.lang.invoke.MethodHandle} to the substituted element.</li>
7125
                         * <li>A {@link Class} describing the instrumented type.</li>
7126
                         * <li>A {@link String} representing the instrumented method or constructor.</li>
7127
                         * </ul>
7128
                         *
7129
                         * @param constructor The bootstrap constructor.
7130
                         * @return A new builder for a delegation within a member substitution that uses the supplied constructor for bootstrapping.
7131
                         */
7132
                        public WithCustomMapping bootstrap(Constructor<?> constructor) {
7133
                            return bootstrap(new MethodDescription.ForLoadedConstructor(constructor));
×
7134
                        }
7135

7136
                        /**
7137
                         * Defines the supplied constructor as a dynamic invocation bootstrap target for delegating advice methods.
7138
                         *
7139
                         * @param constructor     The bootstrap method or constructor.
7140
                         * @param resolverFactory A factory for resolving the arguments to the bootstrap method.
7141
                         * @return A new builder for a delegation within a member substitution that uses the supplied constructor for bootstrapping.
7142
                         */
7143
                        public WithCustomMapping bootstrap(Constructor<?> constructor, BootstrapArgumentResolver.Factory resolverFactory) {
7144
                            return bootstrap(new MethodDescription.ForLoadedConstructor(constructor), resolverFactory);
×
7145
                        }
7146

7147
                        /**
7148
                         * Defines the supplied method as a dynamic invocation bootstrap target for delegating advice methods. The bootstrap
7149
                         * method arguments are:
7150
                         * <ul>
7151
                         * <li>A {@code java.lang.invoke.MethodHandles.Lookup} representing the source method.</li>
7152
                         * <li>A {@link String} representing the method's name.</li>
7153
                         * <li>A {@code java.lang.invoke.MethodType} representing the type that is requested for binding.</li>
7154
                         * <li>A {@link String} representation of the delegate's binary class name.</li>
7155
                         * <li>A {@link Class} representing the receiver type of the substituted element.</li>
7156
                         * <li>A {@link String} representing the internal name of the substituted element.</li>
7157
                         * <li>A {@code java.lang.invoke.MethodHandle} to the substituted element.</li>
7158
                         * <li>A {@link Class} describing the instrumented type.</li>
7159
                         * <li>A {@link String} representing the instrumented method or constructor.</li>
7160
                         * </ul>
7161
                         *
7162
                         * @param method The bootstrap method.
7163
                         * @return A new builder for a delegation within a member substitution that uses the supplied method for bootstrapping.
7164
                         */
7165
                        public WithCustomMapping bootstrap(Method method) {
7166
                            return bootstrap(new MethodDescription.ForLoadedMethod(method));
×
7167
                        }
7168

7169
                        /**
7170
                         * Defines the supplied method as a dynamic invocation bootstrap target for delegating advice methods.
7171
                         *
7172
                         * @param method          The bootstrap method or constructor.
7173
                         * @param resolverFactory A factory for resolving the arguments to the bootstrap method.
7174
                         * @return A new builder for a delegation within a member substitution that uses the supplied method for bootstrapping.
7175
                         */
7176
                        public WithCustomMapping bootstrap(Method method, BootstrapArgumentResolver.Factory resolverFactory) {
7177
                            return bootstrap(new MethodDescription.ForLoadedMethod(method), resolverFactory);
×
7178
                        }
7179

7180
                        /**
7181
                         * Defines the supplied method description as a dynamic invocation bootstrap target for delegating advice methods. The bootstrap
7182
                         * method arguments are:
7183
                         * <ul>
7184
                         * <li>A {@code java.lang.invoke.MethodHandles.Lookup} representing the source method.</li>
7185
                         * <li>A {@link String} representing the target's internal name.</li>
7186
                         * <li>A {@code java.lang.invoke.MethodType} representing the type that is requested for binding.</li>
7187
                         * <li>A {@link String} representation of the delegate's binary class name.</li>
7188
                         * <li>A {@link Class} representing the receiver type of the substituted element.</li>
7189
                         * <li>A {@link String} representing the internal name of the substituted element.</li>
7190
                         * <li>A {@code java.lang.invoke.MethodHandle} to the substituted element.</li>
7191
                         * <li>A {@link Class} describing the instrumented type.</li>
7192
                         * <li>A {@link String} representing the instrumented method or constructor.</li>
7193
                         * <li>A method handle of the instrumented method or constructor, only if the instrumented method is not a type initializer.</li>
7194
                         * </ul>
7195
                         *
7196
                         * @param bootstrap The bootstrap method or constructor.
7197
                         * @return A new builder for a delegation within a member substitution that uses the supplied method or constructor for bootstrapping.
7198
                         */
7199
                        public WithCustomMapping bootstrap(MethodDescription.InDefinedShape bootstrap) {
7200
                            return bootstrap(bootstrap, BootstrapArgumentResolver.ForDefaultValues.Factory.INSTANCE);
×
7201
                        }
7202

7203
                        /**
7204
                         * Defines the supplied method description as a dynamic invocation bootstrap target for delegating advice methods.
7205
                         *
7206
                         * @param bootstrap       The bootstrap method or constructor.
7207
                         * @param resolverFactory A factory for resolving the arguments to the bootstrap method.
7208
                         * @return A new builder for a delegation within a member substitution that uses the supplied method or constructor for bootstrapping.
7209
                         */
7210
                        public WithCustomMapping bootstrap(MethodDescription.InDefinedShape bootstrap, BootstrapArgumentResolver.Factory resolverFactory) {
7211
                            return new WithCustomMapping(Dispatcher.ForDynamicInvocation.of(bootstrap, resolverFactory), offsetMappings);
×
7212
                        }
7213

7214
                        /**
7215
                         * Returns a delegating step factory for the supplied method.
7216
                         *
7217
                         * @param method The method to delegate to.
7218
                         * @return An appropriate step factory.
7219
                         */
7220
                        public Step.Factory<Target> to(Method method) {
7221
                            return to(new MethodDescription.ForLoadedMethod(method));
1✔
7222
                        }
7223

7224
                        /**
7225
                         * Returns a delegating step factory for the supplied constructor.
7226
                         *
7227
                         * @param constructor the constructor to delegate to.
7228
                         * @return An appropriate step factory.
7229
                         */
7230
                        public Step.Factory<Target> to(Constructor<?> constructor) {
7231
                            return to(new MethodDescription.ForLoadedConstructor(constructor));
×
7232
                        }
7233

7234
                        /**
7235
                         * Returns a delegating step factory for the supplied method description.
7236
                         *
7237
                         * @param methodDescription A description of the method or constructor to delegate to.
7238
                         * @return An appropriate step factory.
7239
                         */
7240
                        public Step.Factory<Target> to(MethodDescription.InDefinedShape methodDescription) {
7241
                            return ForDelegation.to(methodDescription, dispatcherFactory, new ArrayList<OffsetMapping.Factory<?>>(offsetMappings.values()));
1✔
7242
                        }
7243
                    }
7244
                }
7245
            }
7246

7247
            /**
7248
             * A factory for creating a substitution chain.
7249
             *
7250
             * @param <U> The type of the matched target.
7251
             */
7252
            @HashCodeAndEqualsPlugin.Enhance
7253
            public static class Factory<U extends Target> implements Substitution.Factory<U> {
7254

7255
                /**
7256
                 * The assigner to use.
7257
                 */
7258
                private final Assigner assigner;
7259

7260
                /**
7261
                 * The typing of the assignment to use.
7262
                 */
7263
                private final Assigner.Typing typing;
7264

7265
                /**
7266
                 * The substitution steps to apply.
7267
                 */
7268
                private final List<Step.Factory<? super U>> steps;
7269

7270
                /**
7271
                 * Creates a new factory for a substitution chain.
7272
                 *
7273
                 * @param assigner The assigner to use.
7274
                 * @param typing   The typing of the assignment to use.
7275
                 * @param steps    The substitution steps to apply.
7276
                 */
7277
                protected Factory(Assigner assigner, Assigner.Typing typing, List<Step.Factory<? super U>> steps) {
1✔
7278
                    this.assigner = assigner;
1✔
7279
                    this.typing = typing;
1✔
7280
                    this.steps = steps;
1✔
7281
                }
1✔
7282

7283
                /**
7284
                 * {@inheritDoc}
7285
                 */
7286
                public Substitution<? super U> make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
7287
                    if (steps.isEmpty()) {
1✔
7288
                        return Stubbing.INSTANCE;
1✔
7289
                    }
7290
                    List<Step<? super U>> steps = new ArrayList<Step<? super U>>(this.steps.size());
1✔
7291
                    for (Step.Factory<? super U> step : this.steps) {
1✔
7292
                        steps.add(step.make(assigner, typing, instrumentedType, instrumentedMethod));
1✔
7293
                    }
1✔
7294
                    return new Chain<U>(assigner, typing, steps);
1✔
7295
                }
7296

7297
                /**
7298
                 * Appends the supplied steps to the substitution chain.
7299
                 *
7300
                 * @param step The steps to append.
7301
                 * @return A new substitution chain that is equal to this substitution chain but with the supplied steps appended.
7302
                 */
7303
                @SafeVarargsPlugin.Enhance
7304
                @SuppressWarnings("unchecked") // In absence of @SafeVarargs
7305
                public final Factory<U> executing(Step.Factory<? super U>... step) {
7306
                    return executing(Arrays.asList(step));
×
7307
                }
7308

7309
                /**
7310
                 * Appends the supplied steps to the substitution chain.
7311
                 *
7312
                 * @param steps The steps to append.
7313
                 * @return A new substitution chain that is equal to this substitution chain but with the supplied steps appended.
7314
                 */
7315
                public Factory<U> executing(List<? extends Step.Factory<? super U>> steps) {
7316
                    return new Factory<U>(assigner, typing, CompoundList.of(this.steps, steps));
1✔
7317
                }
7318
            }
7319
        }
7320
    }
7321

7322
    /**
7323
     * A replacement combines a {@link Substitution} and a way of choosing if this substitution should be applied for a discovered member.
7324
     */
7325
    protected interface Replacement {
7326

7327
        /**
7328
         * Binds this replacement for a field that was discovered.
7329
         *
7330
         * @param instrumentedType   The instrumented type.
7331
         * @param instrumentedMethod The instrumented method.
7332
         * @param typeDescription    The type on which the field was read.
7333
         * @param fieldDescription   The field that was discovered.
7334
         * @param writeAccess        {@code true} if this field was written to.
7335
         * @return A binding for the discovered field access.
7336
         */
7337
        Binding bind(TypeDescription instrumentedType,
7338
                     MethodDescription instrumentedMethod,
7339
                     TypeDescription typeDescription,
7340
                     FieldDescription fieldDescription,
7341
                     boolean writeAccess);
7342

7343
        /**
7344
         * Binds this replacement for a field that was discovered.
7345
         *
7346
         * @param instrumentedType   The instrumented type.FieldDescription
7347
         * @param instrumentedMethod The instrumented method.
7348
         * @param typeDescription    The type on which the method was invoked.
7349
         * @param methodDescription  The method that was discovered.
7350
         * @param invocationType     The invocation type for this method.
7351
         * @return A binding for the discovered method invocation.
7352
         */
7353
        Binding bind(TypeDescription instrumentedType,
7354
                     MethodDescription instrumentedMethod,
7355
                     TypeDescription typeDescription,
7356
                     MethodDescription methodDescription,
7357
                     InvocationType invocationType);
7358

7359
        /**
7360
         * Binds this replacement for a dynamic method invocation that was discovered.
7361
         *
7362
         * @param instrumentedType   The instrumented type.FieldDescription
7363
         * @param instrumentedMethod The instrumented method.
7364
         * @param methodHandle       The method handle of the bootstrap method.
7365
         * @param name               The name of the method that is bound.
7366
         * @param methodType         The type of the method that is bound.
7367
         * @param constants          The constant arguments to the bootstrap method.
7368
         * @return A binding for the discovered method invocation.
7369
         */
7370
        Binding bind(TypeDescription instrumentedType,
7371
                     MethodDescription instrumentedMethod,
7372
                     JavaConstant.MethodHandle methodHandle,
7373
                     JavaConstant.MethodType methodType,
7374
                     String name,
7375
                     List<JavaConstant> constants);
7376

7377
        /**
7378
         * A binding for a replacement of a field or method access within another method.
7379
         */
7380
        interface Binding {
7381

7382
            /**
7383
             * Returns {@code true} if this binding is resolved.
7384
             *
7385
             * @return {@code true} if this binding is resolved.
7386
             */
7387
            boolean isBound();
7388

7389
            /**
7390
             * Creates a stack manipulation that represents the substitution. This method can only be called for actually bound bindings.
7391
             *
7392
             * @param parameters        The parameters that are accessible to the substitution target.
7393
             * @param result            The result that is expected from the substitution target or {@code void} if none is expected.
7394
             * @param methodHandle      A method handle that represents the original expression that is being substituted.
7395
             * @param stackManipulation The original byte code expression that is being substituted.
7396
             * @param freeOffset        The first offset that can be used for storing local variables.
7397
             * @return A stack manipulation that represents the replacement.
7398
             */
7399
            StackManipulation make(TypeList.Generic parameters,
7400
                                   TypeDescription.Generic result,
7401
                                   JavaConstant.MethodHandle methodHandle,
7402
                                   StackManipulation stackManipulation,
7403
                                   int freeOffset);
7404

7405
            /**
7406
             * An unresolved binding.
7407
             */
7408
            enum Unresolved implements Binding {
1✔
7409

7410
                /**
7411
                 * The singleton instance.
7412
                 */
7413
                INSTANCE;
1✔
7414

7415
                /**
7416
                 * {@inheritDoc}
7417
                 */
7418
                public boolean isBound() {
7419
                    return false;
1✔
7420
                }
7421

7422
                /**
7423
                 * {@inheritDoc}
7424
                 */
7425
                public StackManipulation make(TypeList.Generic parameters, TypeDescription.Generic result, JavaConstant.MethodHandle methodHandle, StackManipulation stackManipulation, int freeOffset) {
7426
                    throw new IllegalStateException("Cannot resolve unresolved binding");
×
7427
                }
7428
            }
7429

7430
            /**
7431
             * A binding that was resolved for a field or method expression.
7432
             */
7433
            @HashCodeAndEqualsPlugin.Enhance
7434
            class ForMember implements Binding {
7435

7436
                /**
7437
                 * The type on which a field or method was accessed.
7438
                 */
7439
                private final TypeDescription receiver;
7440

7441
                /**
7442
                 * The field or method that was accessed.
7443
                 */
7444
                private final ByteCodeElement.Member member;
7445

7446
                /**
7447
                 * The substitution to apply.
7448
                 */
7449
                private final Substitution<? super Target.ForMember> substitution;
7450

7451
                /**
7452
                 * Creates a new resolved binding.
7453
                 *
7454
                 * @param receiver     The type on which a field or method was accessed.
7455
                 * @param member       The field or method that was accessed.
7456
                 * @param substitution The substitution to apply.
7457
                 */
7458
                protected ForMember(TypeDescription receiver, ByteCodeElement.Member member, Substitution<? super Target.ForMember> substitution) {
1✔
7459
                    this.receiver = receiver;
1✔
7460
                    this.member = member;
1✔
7461
                    this.substitution = substitution;
1✔
7462
                }
1✔
7463

7464
                /**
7465
                 * {@inheritDoc}
7466
                 */
7467
                public boolean isBound() {
7468
                    return true;
1✔
7469
                }
7470

7471
                /**
7472
                 * {@inheritDoc}
7473
                 */
7474
                public StackManipulation make(TypeList.Generic parameters,
7475
                                              TypeDescription.Generic result,
7476
                                              JavaConstant.MethodHandle methodHandle,
7477
                                              StackManipulation stackManipulation,
7478
                                              int freeOffset) {
7479
                    return substitution.resolve(new Target.ForMember(receiver, member),
1✔
7480
                            parameters,
7481
                            result,
7482
                            methodHandle,
7483
                            stackManipulation,
7484
                            freeOffset);
7485
                }
7486
            }
7487

7488
            /**
7489
             * A binding that was resolved for an invokedynamic expression.
7490
             */
7491
            @HashCodeAndEqualsPlugin.Enhance
7492
            class ForDynamicInvocation implements Binding {
7493

7494
                /**
7495
                 * The type of the lambda expression that is to be bound.
7496
                 */
7497
                private final JavaConstant.MethodType methodType;
7498

7499
                /**
7500
                 * The name of the lambda expression target.
7501
                 */
7502
                private final String name;
7503

7504
                /**
7505
                 * The constant arguments supplied to the bootstrap method.
7506
                 */
7507
                private final List<JavaConstant> arguments;
7508

7509
                /**
7510
                 * The substitution to apply.
7511
                 */
7512
                private final Substitution<? super Target.ForDynamicInvocation> substitution;
7513

7514
                /**
7515
                 * Creates a resolved binding for an invokedynamic expression.
7516
                 *
7517
                 * @param methodType   The type of the lambda expression that is to be bound.
7518
                 * @param name         The name of the lambda expression target.
7519
                 * @param arguments    The constant arguments supplied to the bootstrap method.
7520
                 * @param substitution The substitution to apply.
7521
                 */
7522
                protected ForDynamicInvocation(JavaConstant.MethodType methodType, String name, List<JavaConstant> arguments, Substitution<? super Target.ForDynamicInvocation> substitution) {
1✔
7523
                    this.methodType = methodType;
1✔
7524
                    this.name = name;
1✔
7525
                    this.arguments = arguments;
1✔
7526
                    this.substitution = substitution;
1✔
7527
                }
1✔
7528

7529
                /**
7530
                 * {@inheritDoc}
7531
                 */
7532
                public boolean isBound() {
7533
                    return true;
1✔
7534
                }
7535

7536
                /**
7537
                 * {@inheritDoc}
7538
                 */
7539
                public StackManipulation make(TypeList.Generic parameters,
7540
                                              TypeDescription.Generic result,
7541
                                              JavaConstant.MethodHandle methodHandle,
7542
                                              StackManipulation stackManipulation,
7543
                                              int freeOffset) {
7544
                    return substitution.resolve(new Target.ForDynamicInvocation(methodType, name, arguments),
1✔
7545
                            parameters,
7546
                            result,
7547
                            methodHandle,
7548
                            stackManipulation,
7549
                            freeOffset);
7550
                }
7551
            }
7552
        }
7553

7554
        /**
7555
         * A factory for creating a replacement for an instrumented method.
7556
         */
7557
        interface Factory {
7558

7559
            /**
7560
             * Creates a replacement for an instrumented method.
7561
             *
7562
             * @param instrumentedType   The instrumented type.
7563
             * @param instrumentedMethod The instrumented method.
7564
             * @param typePool           The type pool being used within the member substitution being applied.
7565
             * @return A replacement to use within the supplied instrumented method.
7566
             */
7567
            Replacement make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool);
7568

7569
            /**
7570
             * A compound factory.
7571
             */
7572
            @HashCodeAndEqualsPlugin.Enhance
7573
            class Compound implements Factory {
7574

7575
                /**
7576
                 * A list of represented factories.
7577
                 */
7578
                private final List<Factory> factories;
7579

7580
                /**
7581
                 * Creates a new compound factory.
7582
                 *
7583
                 * @param factory A list of represented factories.
7584
                 */
7585
                protected Compound(Factory... factory) {
7586
                    this(Arrays.asList(factory));
1✔
7587
                }
1✔
7588

7589
                /**
7590
                 * Creates a new compound factory.
7591
                 *
7592
                 * @param factories A list of represented factories.
7593
                 */
7594
                protected Compound(List<? extends Factory> factories) {
1✔
7595
                    this.factories = new ArrayList<Factory>();
1✔
7596
                    for (Factory factory : factories) {
1✔
7597
                        if (factory instanceof Compound) {
1✔
7598
                            this.factories.addAll(((Compound) factory).factories);
×
7599
                        } else if (!(factory instanceof NoOp)) {
1✔
7600
                            this.factories.add(factory);
1✔
7601
                        }
7602
                    }
1✔
7603
                }
1✔
7604

7605
                /**
7606
                 * {@inheritDoc}
7607
                 */
7608
                public Replacement make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
7609
                    List<Replacement> replacements = new ArrayList<Replacement>();
1✔
7610
                    for (Factory factory : factories) {
1✔
7611
                        replacements.add(factory.make(instrumentedType, instrumentedMethod, typePool));
1✔
7612
                    }
1✔
7613
                    return new ForFirstBinding(replacements);
1✔
7614
                }
7615
            }
7616
        }
7617

7618
        /**
7619
         * Describes a method invocation type.
7620
         */
7621
        enum InvocationType {
1✔
7622

7623
            /**
7624
             * Describes a virtual method invocation.
7625
             */
7626
            VIRTUAL,
1✔
7627

7628
            /**
7629
             * Describes a super method invocation.
7630
             */
7631
            SUPER,
1✔
7632

7633
            /**
7634
             * Describes any method invocation that is not virtual or a super method invocation.
7635
             */
7636
            OTHER;
1✔
7637

7638
            /**
7639
             * Resolves an invocation type.
7640
             *
7641
             * @param opcode            The opcode that is used for invoking the method.
7642
             * @param methodDescription The method that is being invoked.
7643
             * @return The invocation type for the method given that opcode.
7644
             */
7645
            protected static InvocationType of(int opcode, MethodDescription methodDescription) {
7646
                switch (opcode) {
1✔
7647
                    case Opcodes.INVOKEVIRTUAL:
7648
                    case Opcodes.INVOKEINTERFACE:
7649
                        return InvocationType.VIRTUAL;
1✔
7650
                    case Opcodes.INVOKESPECIAL:
7651
                        return methodDescription.isVirtual() ? SUPER : OTHER;
1✔
7652
                    default:
7653
                        return OTHER;
1✔
7654
                }
7655
            }
7656

7657
            /**
7658
             * Checks if this invocation type matches the specified inputs.
7659
             *
7660
             * @param includeVirtualCalls {@code true} if a virtual method should be matched.
7661
             * @param includeSuperCalls   {@code true} if a super method call should be matched.
7662
             * @return {@code true} if this invocation type matches the specified parameters.
7663
             */
7664
            protected boolean matches(boolean includeVirtualCalls, boolean includeSuperCalls) {
7665
                switch (this) {
1✔
7666
                    case VIRTUAL:
7667
                        return includeVirtualCalls;
1✔
7668
                    case SUPER:
7669
                        return includeSuperCalls;
1✔
7670
                    default:
7671
                        return true;
1✔
7672
                }
7673
            }
7674
        }
7675

7676
        /**
7677
         * A non-operational replacement.
7678
         */
7679
        enum NoOp implements Replacement, Factory {
1✔
7680

7681
            /**
7682
             * The singleton instance.
7683
             */
7684
            INSTANCE;
1✔
7685

7686
            /**
7687
             * {@inheritDoc}
7688
             */
7689
            public Replacement make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
7690
                return this;
×
7691
            }
7692

7693
            /**
7694
             * {@inheritDoc}
7695
             */
7696
            public Binding bind(TypeDescription instrumentedType,
7697
                                MethodDescription instrumentedMethod,
7698
                                TypeDescription typeDescription,
7699
                                FieldDescription fieldDescription,
7700
                                boolean writeAccess) {
7701
                return Binding.Unresolved.INSTANCE;
×
7702
            }
7703

7704
            /**
7705
             * {@inheritDoc}
7706
             */
7707
            public Binding bind(TypeDescription instrumentedType,
7708
                                MethodDescription instrumentedMethod,
7709
                                TypeDescription typeDescription,
7710
                                MethodDescription methodDescription,
7711
                                InvocationType invocationType) {
7712
                return Binding.Unresolved.INSTANCE;
×
7713
            }
7714

7715
            /**
7716
             * {@inheritDoc}
7717
             */
7718
            public Binding bind(TypeDescription instrumentedType,
7719
                                MethodDescription instrumentedMethod,
7720
                                JavaConstant.MethodHandle methodHandle,
7721
                                JavaConstant.MethodType methodType,
7722
                                String name,
7723
                                List<JavaConstant> constants) {
7724
                return Binding.Unresolved.INSTANCE;
×
7725
            }
7726
        }
7727

7728
        /**
7729
         * A replacement that substitutes a member based on a row of element matchers.
7730
         */
7731
        @HashCodeAndEqualsPlugin.Enhance
7732
        class ForElementMatchers implements Replacement {
7733

7734
            /**
7735
             * The field matcher to consider when discovering fields.
7736
             */
7737
            private final ElementMatcher<? super FieldDescription> fieldMatcher;
7738

7739
            /**
7740
             * The method matcher to consider when discovering methods.
7741
             */
7742
            private final ElementMatcher<? super MethodDescription> methodMatcher;
7743

7744
            /**
7745
             * {@code true} if field reading access should be matched.
7746
             */
7747
            private final boolean matchFieldRead;
7748

7749
            /**
7750
             * {@code true} if field writing access should be matched.
7751
             */
7752
            private final boolean matchFieldWrite;
7753

7754
            /**
7755
             * {@code true} if virtual method calls should be matched.
7756
             */
7757
            private final boolean includeVirtualCalls;
7758

7759
            /**
7760
             * {@code true} if super method calls should be matched.
7761
             */
7762
            private final boolean includeSuperCalls;
7763

7764
            /**
7765
             * The substitution to trigger if a member is matched.
7766
             */
7767
            private final Substitution<? super Target.ForMember> substitution;
7768

7769
            /**
7770
             * Creates a new replacement that triggers a substitution based on a row of matchers.
7771
             *
7772
             * @param fieldMatcher        The field matcher to consider when discovering fields.
7773
             * @param methodMatcher       The method matcher to consider when discovering methods.
7774
             * @param matchFieldRead      {@code true} if field reading access should be matched.
7775
             * @param matchFieldWrite     {@code true} if field writing access should be matched.
7776
             * @param includeVirtualCalls {@code true} if virtual method calls should be matched.
7777
             * @param includeSuperCalls   {@code true} if super method calls should be matched.
7778
             * @param substitution        The substitution to trigger if a member is matched.
7779
             */
7780
            protected ForElementMatchers(ElementMatcher<? super FieldDescription> fieldMatcher,
7781
                                         ElementMatcher<? super MethodDescription> methodMatcher,
7782
                                         boolean matchFieldRead,
7783
                                         boolean matchFieldWrite,
7784
                                         boolean includeVirtualCalls,
7785
                                         boolean includeSuperCalls,
7786
                                         Substitution<? super Target.ForMember> substitution) {
1✔
7787
                this.fieldMatcher = fieldMatcher;
1✔
7788
                this.methodMatcher = methodMatcher;
1✔
7789
                this.matchFieldRead = matchFieldRead;
1✔
7790
                this.matchFieldWrite = matchFieldWrite;
1✔
7791
                this.includeVirtualCalls = includeVirtualCalls;
1✔
7792
                this.includeSuperCalls = includeSuperCalls;
1✔
7793
                this.substitution = substitution;
1✔
7794
            }
1✔
7795

7796
            /**
7797
             * {@inheritDoc}
7798
             */
7799
            public Binding bind(TypeDescription instrumentedType,
7800
                                MethodDescription instrumentedMethod,
7801
                                TypeDescription typeDescription,
7802
                                FieldDescription fieldDescription,
7803
                                boolean writeAccess) {
7804
                return (writeAccess ? matchFieldWrite : matchFieldRead) && fieldMatcher.matches(fieldDescription)
1✔
7805
                        ? new Binding.ForMember(typeDescription, fieldDescription, substitution)
7806
                        : Binding.Unresolved.INSTANCE;
7807
            }
7808

7809
            /**
7810
             * {@inheritDoc}
7811
             */
7812
            public Binding bind(TypeDescription instrumentedType,
7813
                                MethodDescription instrumentedMethod,
7814
                                TypeDescription typeDescription,
7815
                                MethodDescription methodDescription,
7816
                                InvocationType invocationType) {
7817
                return invocationType.matches(includeVirtualCalls, includeSuperCalls) && methodMatcher.matches(methodDescription)
1✔
7818
                        ? new Binding.ForMember(typeDescription, methodDescription, substitution)
7819
                        : Binding.Unresolved.INSTANCE;
7820
            }
7821

7822
            /**
7823
             * {@inheritDoc}
7824
             */
7825
            public Binding bind(TypeDescription instrumentedType,
7826
                                MethodDescription instrumentedMethod,
7827
                                JavaConstant.MethodHandle methodHandle,
7828
                                JavaConstant.MethodType methodType,
7829
                                String name,
7830
                                List<JavaConstant> constants) {
7831
                return Binding.Unresolved.INSTANCE;
×
7832
            }
7833

7834
            /**
7835
             * A factory for creating a replacement that chooses members based on a row of element matchers.
7836
             */
7837
            @HashCodeAndEqualsPlugin.Enhance
7838
            protected static class Factory implements Replacement.Factory {
7839

7840
                /**
7841
                 * The field matcher to consider when discovering fields.
7842
                 */
7843
                private final ElementMatcher<? super FieldDescription> fieldMatcher;
7844

7845
                /**
7846
                 * The method matcher to consider when discovering methods.
7847
                 */
7848
                private final ElementMatcher<? super MethodDescription> methodMatcher;
7849

7850
                /**
7851
                 * {@code true} if field reading access should be matched.
7852
                 */
7853
                private final boolean matchFieldRead;
7854

7855
                /**
7856
                 * {@code true} if field writing access should be matched.
7857
                 */
7858
                private final boolean matchFieldWrite;
7859

7860
                /**
7861
                 * {@code true} if virtual method calls should be matched.
7862
                 */
7863
                private final boolean includeVirtualCalls;
7864

7865
                /**
7866
                 * {@code true} if super method calls should be matched.
7867
                 */
7868
                private final boolean includeSuperCalls;
7869

7870
                /**
7871
                 * The substitution factory to create a substitution from.
7872
                 */
7873
                private final Substitution.Factory<? super Target.ForMember> substitutionFactory;
7874

7875
                /**
7876
                 * Creates a new replacement that triggers a substitution based on a row of matchers.
7877
                 *
7878
                 * @param fieldMatcher        The field matcher to consider when discovering fields.
7879
                 * @param methodMatcher       The method matcher to consider when discovering methods.
7880
                 * @param matchFieldRead      {@code true} if field reading access should be matched.
7881
                 * @param matchFieldWrite     {@code true} if field writing access should be matched.
7882
                 * @param includeVirtualCalls {@code true} if virtual method calls should be matched.
7883
                 * @param includeSuperCalls   {@code true} if super method calls should be matched.
7884
                 * @param substitutionFactory The substitution factory to create a substitution from.
7885
                 */
7886
                protected Factory(ElementMatcher<? super FieldDescription> fieldMatcher,
7887
                                  ElementMatcher<? super MethodDescription> methodMatcher,
7888
                                  boolean matchFieldRead,
7889
                                  boolean matchFieldWrite,
7890
                                  boolean includeVirtualCalls,
7891
                                  boolean includeSuperCalls,
7892
                                  Substitution.Factory<? super Target.ForMember> substitutionFactory) {
1✔
7893
                    this.fieldMatcher = fieldMatcher;
1✔
7894
                    this.methodMatcher = methodMatcher;
1✔
7895
                    this.matchFieldRead = matchFieldRead;
1✔
7896
                    this.matchFieldWrite = matchFieldWrite;
1✔
7897
                    this.includeVirtualCalls = includeVirtualCalls;
1✔
7898
                    this.includeSuperCalls = includeSuperCalls;
1✔
7899
                    this.substitutionFactory = substitutionFactory;
1✔
7900
                }
1✔
7901

7902
                /**
7903
                 * Creates a factory for applying a substitution on all matched byte code elements for all access types.
7904
                 *
7905
                 * @param matcher The matcher to apply.
7906
                 * @param factory The substitution factory to create a substitution from.
7907
                 * @return An appropriate replacement factory for the supplied matcher and substitution factory.
7908
                 */
7909
                protected static Replacement.Factory of(ElementMatcher<? super ByteCodeElement.Member> matcher, Substitution.Factory<? super Target.ForMember> factory) {
7910
                    return new Factory(matcher, matcher, true, true, true, true, factory);
×
7911
                }
7912

7913
                /**
7914
                 * Creates a factory that only matches field access for given access types.
7915
                 *
7916
                 * @param matcher         The matcher to identify fields for substitution.
7917
                 * @param matchFieldRead  {@code true} if field read access should be matched.
7918
                 * @param matchFieldWrite {@code true} if field write access should be matched.
7919
                 * @param factory         The substitution factory to apply for fields that match the specified criteria.
7920
                 * @return An appropriate replacement factory.
7921
                 */
7922
                protected static Replacement.Factory ofField(ElementMatcher<? super FieldDescription> matcher, boolean matchFieldRead, boolean matchFieldWrite, Substitution.Factory<? super Target.ForMember> factory) {
7923
                    return new Factory(matcher, none(), matchFieldRead, matchFieldWrite, false, false, factory);
1✔
7924
                }
7925

7926
                /**
7927
                 * Creates a factory that only matches method and constructor invocations for given invocation types.
7928
                 *
7929
                 * @param matcher             The matcher to identify methods and constructors for substitution.
7930
                 * @param includeVirtualCalls {@code true} if virtual method calls should be matched.
7931
                 * @param includeSuperCalls   {@code true} if super method calls should be matched.
7932
                 * @param factory             The substitution factory to apply for methods and constructors that match the specified criteria.
7933
                 * @return An appropriate replacement factory.
7934
                 */
7935
                protected static Replacement.Factory ofMethod(ElementMatcher<? super MethodDescription> matcher, boolean includeVirtualCalls, boolean includeSuperCalls, Substitution.Factory<? super Target.ForMember> factory) {
7936
                    return new Factory(none(), matcher, false, false, includeVirtualCalls, includeSuperCalls, factory);
1✔
7937
                }
7938

7939
                /**
7940
                 * {@inheritDoc}
7941
                 */
7942
                public Replacement make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
7943
                    return new ForElementMatchers(fieldMatcher,
1✔
7944
                            methodMatcher,
7945
                            matchFieldRead,
7946
                            matchFieldWrite,
7947
                            includeVirtualCalls,
7948
                            includeSuperCalls,
7949
                            substitutionFactory.make(instrumentedType, instrumentedMethod, typePool));
1✔
7950
                }
7951
            }
7952
        }
7953

7954
        /**
7955
         * A replacement that substitutes a invokedynamic instruction.
7956
         */
7957
        @HashCodeAndEqualsPlugin.Enhance
7958
        class ForDynamicInvocation implements Replacement {
7959

7960
            /**
7961
             * A matcher for an invokedynamic bootstrap method.
7962
             */
7963
            private final ElementMatcher<? super JavaConstant.MethodHandle> handleMatcher;
7964

7965
            /**
7966
             * A matcher for an invokedynamic instruction's name.
7967
             */
7968
            private final ElementMatcher.Junction<? super String> nameMatcher;
7969

7970
            /**
7971
             * A matcher for an invokedynamic instruction's result type.
7972
             */
7973
            private final ElementMatcher.Junction<? super JavaConstant.MethodType> typeMatcher;
7974

7975
            /**
7976
             * A matcher for an invokedynamic instruction's constant arguments.
7977
             */
7978
            private final ElementMatcher.Junction<? super List<JavaConstant>> argumentsMatcher;
7979

7980
            /**
7981
             * The substitution to apply.
7982
             */
7983
            private final Substitution<? super Target.ForDynamicInvocation> substitution;
7984

7985
            /**
7986
             * Creates a replacement for an invokedynamic instruction.
7987
             *
7988
             * @param handleMatcher    A matcher for an invokedynamic bootstrap method.
7989
             * @param nameMatcher      A matcher for an invokedynamic instruction's name.
7990
             * @param typeMatcher      A matcher for an invokedynamic instruction's result type.
7991
             * @param argumentsMatcher A matcher for an invokedynamic instruction's constant arguments.
7992
             * @param substitution     The substitution to apply.
7993
             */
7994
            protected ForDynamicInvocation(ElementMatcher<? super JavaConstant.MethodHandle> handleMatcher,
7995
                                           ElementMatcher.Junction<? super String> nameMatcher,
7996
                                           ElementMatcher.Junction<? super JavaConstant.MethodType> typeMatcher,
7997
                                           ElementMatcher.Junction<? super List<JavaConstant>> argumentsMatcher,
7998
                                           Substitution<? super Target.ForDynamicInvocation> substitution) {
1✔
7999
                this.handleMatcher = handleMatcher;
1✔
8000
                this.nameMatcher = nameMatcher;
1✔
8001
                this.typeMatcher = typeMatcher;
1✔
8002
                this.argumentsMatcher = argumentsMatcher;
1✔
8003
                this.substitution = substitution;
1✔
8004
            }
1✔
8005

8006
            /**
8007
             * {@inheritDoc}
8008
             */
8009
            public Binding bind(TypeDescription instrumentedType,
8010
                                MethodDescription instrumentedMethod,
8011
                                TypeDescription typeDescription,
8012
                                FieldDescription fieldDescription,
8013
                                boolean writeAccess) {
8014
                return Binding.Unresolved.INSTANCE;
×
8015
            }
8016

8017
            /**
8018
             * {@inheritDoc}
8019
             */
8020
            public Binding bind(TypeDescription instrumentedType,
8021
                                MethodDescription instrumentedMethod,
8022
                                TypeDescription typeDescription,
8023
                                MethodDescription methodDescription,
8024
                                InvocationType invocationType) {
8025
                return Binding.Unresolved.INSTANCE;
×
8026
            }
8027

8028
            /**
8029
             * {@inheritDoc}
8030
             */
8031
            public Binding bind(TypeDescription instrumentedType,
8032
                                MethodDescription instrumentedMethod,
8033
                                JavaConstant.MethodHandle methodHandle,
8034
                                JavaConstant.MethodType methodType,
8035
                                String name,
8036
                                List<JavaConstant> constants) {
8037
                if (handleMatcher.matches(methodHandle)
1✔
8038
                        && nameMatcher.matches(name)
1✔
8039
                        && typeMatcher.matches(methodType)
1✔
8040
                        && argumentsMatcher.matches(constants)) {
1✔
8041
                    return new Binding.ForDynamicInvocation(methodType, name, constants, substitution);
1✔
8042
                }
8043
                return Binding.Unresolved.INSTANCE;
×
8044
            }
8045

8046
            /**
8047
             * A factory for a replacement for an invokedynamic instruction.
8048
             */
8049
            @HashCodeAndEqualsPlugin.Enhance
8050
            protected static class Factory implements Replacement.Factory {
8051

8052
                /**
8053
                 * A matcher for an invokedynamic bootstrap method.
8054
                 */
8055
                private final ElementMatcher<? super JavaConstant.MethodHandle> handleMatcher;
8056

8057
                /**
8058
                 * A matcher for an invokedynamic instruction's name.
8059
                 */
8060
                private final ElementMatcher.Junction<? super String> nameMatcher;
8061

8062
                /**
8063
                 * A matcher for an invokedynamic instruction's result type.
8064
                 */
8065
                private final ElementMatcher.Junction<? super JavaConstant.MethodType> typeMatcher;
8066

8067
                /**
8068
                 * A matcher for an invokedynamic instruction's constant arguments.
8069
                 */
8070
                private final ElementMatcher.Junction<? super List<JavaConstant>> argumentsMatcher;
8071

8072
                /**
8073
                 * A factory for creating a substitution.
8074
                 */
8075
                private final Substitution.Factory<? super Target.ForDynamicInvocation> substitutionFactory;
8076

8077
                /**
8078
                 * Creates a factory for a replacement for a replacement for an invokedynamic instruction.
8079
                 *
8080
                 * @param handleMatcher       A matcher for an invokedynamic bootstrap method.
8081
                 * @param nameMatcher         A matcher for an invokedynamic instruction's name.
8082
                 * @param typeMatcher         A matcher for an invokedynamic instruction's result type.
8083
                 * @param argumentsMatcher    A matcher for an invokedynamic instruction's constant arguments.
8084
                 * @param substitutionFactory A factory for creating a substitution.
8085
                 */
8086
                protected Factory(ElementMatcher<? super JavaConstant.MethodHandle> handleMatcher,
8087
                                  ElementMatcher.Junction<? super String> nameMatcher,
8088
                                  ElementMatcher.Junction<? super JavaConstant.MethodType> typeMatcher,
8089
                                  ElementMatcher.Junction<? super List<JavaConstant>> argumentsMatcher,
8090
                                  Substitution.Factory<? super Target.ForDynamicInvocation> substitutionFactory) {
1✔
8091
                    this.handleMatcher = handleMatcher;
1✔
8092
                    this.nameMatcher = nameMatcher;
1✔
8093
                    this.typeMatcher = typeMatcher;
1✔
8094
                    this.argumentsMatcher = argumentsMatcher;
1✔
8095
                    this.substitutionFactory = substitutionFactory;
1✔
8096
                }
1✔
8097

8098
                /**
8099
                 * {@inheritDoc}
8100
                 */
8101
                public Replacement make(TypeDescription instrumentedType, MethodDescription instrumentedMethod, TypePool typePool) {
8102
                    return new ForDynamicInvocation(handleMatcher,
1✔
8103
                            nameMatcher,
8104
                            typeMatcher,
8105
                            argumentsMatcher,
8106
                            substitutionFactory.make(instrumentedType, instrumentedMethod, typePool));
1✔
8107
                }
8108
            }
8109
        }
8110

8111
        /**
8112
         * A replacement that only resolves the first matching replacement of a list of replacements.
8113
         */
8114
        @HashCodeAndEqualsPlugin.Enhance
8115
        class ForFirstBinding implements Replacement {
8116

8117
            /**
8118
             * The list of replacements to consider.
8119
             */
8120
            private final List<? extends Replacement> replacements;
8121

8122
            /**
8123
             * Creates a new replacement that triggers the first matching replacement, if any.
8124
             *
8125
             * @param replacements The list of replacements to consider.
8126
             */
8127
            protected ForFirstBinding(List<? extends Replacement> replacements) {
1✔
8128
                this.replacements = replacements;
1✔
8129
            }
1✔
8130

8131
            /**
8132
             * {@inheritDoc}
8133
             */
8134
            public Binding bind(TypeDescription instrumentedType,
8135
                                MethodDescription instrumentedMethod,
8136
                                TypeDescription typeDescription,
8137
                                FieldDescription fieldDescription,
8138
                                boolean writeAccess) {
8139
                for (Replacement replacement : replacements) {
1✔
8140
                    Binding binding = replacement.bind(instrumentedType, instrumentedMethod, typeDescription, fieldDescription, writeAccess);
1✔
8141
                    if (binding.isBound()) {
1✔
8142
                        return binding;
1✔
8143
                    }
8144
                }
1✔
8145
                return Binding.Unresolved.INSTANCE;
1✔
8146
            }
8147

8148
            /**
8149
             * {@inheritDoc}
8150
             */
8151
            public Binding bind(TypeDescription instrumentedType,
8152
                                MethodDescription instrumentedMethod,
8153
                                TypeDescription typeDescription,
8154
                                MethodDescription methodDescription,
8155
                                InvocationType invocationType) {
8156
                for (Replacement replacement : replacements) {
1✔
8157
                    Binding binding = replacement.bind(instrumentedType, instrumentedMethod, typeDescription, methodDescription, invocationType);
1✔
8158
                    if (binding.isBound()) {
1✔
8159
                        return binding;
1✔
8160
                    }
8161
                }
1✔
8162
                return Binding.Unresolved.INSTANCE;
1✔
8163
            }
8164

8165
            /**
8166
             * {@inheritDoc}
8167
             */
8168
            public Binding bind(TypeDescription instrumentedType,
8169
                                MethodDescription instrumentedMethod,
8170
                                JavaConstant.MethodHandle methodHandle,
8171
                                JavaConstant.MethodType methodType,
8172
                                String name,
8173
                                List<JavaConstant> constants) {
8174
                for (Replacement replacement : replacements) {
1✔
8175
                    Binding binding = replacement.bind(instrumentedType,
1✔
8176
                            instrumentedMethod,
8177
                            methodHandle,
8178
                            methodType,
8179
                            name,
8180
                            constants);
8181
                    if (binding.isBound()) {
1✔
8182
                        return binding;
1✔
8183
                    }
8184
                }
×
8185
                return Binding.Unresolved.INSTANCE;
×
8186
            }
8187
        }
8188
    }
8189

8190
    /**
8191
     * A method visitor that applies a substitution for matched methods.
8192
     */
8193
    protected static class SubstitutingMethodVisitor extends LocalVariableAwareMethodVisitor {
8194

8195
        /**
8196
         * The instrumented type.
8197
         */
8198
        private final TypeDescription instrumentedType;
8199

8200
        /**
8201
         * The instrumented method.
8202
         */
8203
        private final MethodDescription instrumentedMethod;
8204

8205
        /**
8206
         * The method graph compiler to use.
8207
         */
8208
        private final MethodGraph.Compiler methodGraphCompiler;
8209

8210
        /**
8211
         * {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
8212
         */
8213
        private final boolean strict;
8214

8215
        /**
8216
         * {@code true} if the instrumentation should fail if applied to a method without match.
8217
         */
8218
        private final boolean failIfNoMatch;
8219

8220
        /**
8221
         * The replacement to use for creating substitutions.
8222
         */
8223
        private final Replacement replacement;
8224

8225
        /**
8226
         * The implementation context to use.
8227
         */
8228
        private final Implementation.Context implementationContext;
8229

8230
        /**
8231
         * The type pool to use.
8232
         */
8233
        private final TypePool typePool;
8234

8235
        /**
8236
         * If {@code true}, virtual method calls might target private methods in accordance to the nest mate specification.
8237
         */
8238
        private final boolean virtualPrivateCalls;
8239

8240
        /**
8241
         * An additional buffer for the operand stack that is required.
8242
         */
8243
        private int stackSizeBuffer;
8244

8245
        /**
8246
         * The minimum amount of local variable array slots that are required to apply substitutions.
8247
         */
8248
        private int localVariableExtension;
8249

8250
        /**
8251
         * {@code true} if at least one member was substituted during the application of this visitor.
8252
         */
8253
        private boolean matched;
8254

8255
        /**
8256
         * Creates a new substituting method visitor.
8257
         *
8258
         * @param methodVisitor         The method visitor to delegate to.
8259
         * @param instrumentedType      The instrumented type.
8260
         * @param instrumentedMethod    The instrumented method.
8261
         * @param methodGraphCompiler   The method graph compiler to use.
8262
         * @param strict                {@code true} if the method processing should be strict where an exception is raised if a member cannot be found.
8263
         * @param failIfNoMatch         {@code true} if the instrumentation should fail if applied to a method without match.
8264
         * @param replacement           The replacement to use for creating substitutions.
8265
         * @param implementationContext The implementation context to use.
8266
         * @param typePool              The type pool to use.
8267
         * @param virtualPrivateCalls   {@code true}, virtual method calls might target private methods in accordance to the nest mate specification.
8268
         */
8269
        protected SubstitutingMethodVisitor(MethodVisitor methodVisitor,
8270
                                            TypeDescription instrumentedType,
8271
                                            MethodDescription instrumentedMethod,
8272
                                            MethodGraph.Compiler methodGraphCompiler,
8273
                                            boolean strict,
8274
                                            boolean failIfNoMatch,
8275
                                            Replacement replacement,
8276
                                            Implementation.Context implementationContext,
8277
                                            TypePool typePool,
8278
                                            boolean virtualPrivateCalls) {
8279
            super(methodVisitor, instrumentedMethod);
1✔
8280
            this.instrumentedType = instrumentedType;
1✔
8281
            this.instrumentedMethod = instrumentedMethod;
1✔
8282
            this.methodGraphCompiler = methodGraphCompiler;
1✔
8283
            this.strict = strict;
1✔
8284
            this.failIfNoMatch = failIfNoMatch;
1✔
8285
            this.replacement = replacement;
1✔
8286
            this.implementationContext = implementationContext;
1✔
8287
            this.typePool = typePool;
1✔
8288
            this.virtualPrivateCalls = virtualPrivateCalls;
1✔
8289
            stackSizeBuffer = 0;
1✔
8290
            localVariableExtension = 0;
1✔
8291
        }
1✔
8292

8293
        @Override
8294
        public void visitFieldInsn(int opcode, String owner, String internalName, String descriptor) {
8295
            TypePool.Resolution resolution = typePool.describe(owner.replace('/', '.'));
1✔
8296
            if (resolution.isResolved()) {
1✔
8297
                FieldList<?> candidates;
8298
                Iterator<TypeDefinition> iterator = resolution.resolve().iterator();
1✔
8299
                do {
8300
                    candidates = iterator.next().getDeclaredFields().filter(strict
1✔
8301
                            ? ElementMatchers.<FieldDescription>named(internalName).and(hasDescriptor(descriptor))
1✔
8302
                            : ElementMatchers.<FieldDescription>failSafe(named(internalName).and(hasDescriptor(descriptor))));
×
8303
                } while (iterator.hasNext() && candidates.isEmpty());
1✔
8304
                if (!candidates.isEmpty()) {
1✔
8305
                    Replacement.Binding binding = replacement.bind(instrumentedType,
1✔
8306
                            instrumentedMethod,
8307
                            resolution.resolve(),
1✔
8308
                            candidates.getOnly(),
1✔
8309
                            opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC);
8310
                    if (binding.isBound()) {
1✔
8311
                        TypeList.Generic parameters;
8312
                        TypeDescription.Generic result;
8313
                        boolean read;
8314
                        switch (opcode) {
1✔
8315
                            case Opcodes.PUTFIELD:
8316
                                parameters = new TypeList.Generic.Explicit(candidates.getOnly().getDeclaringType(), candidates.getOnly().getType());
1✔
8317
                                result = TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(void.class);
1✔
8318
                                read = false;
1✔
8319
                                break;
1✔
8320
                            case Opcodes.PUTSTATIC:
8321
                                parameters = new TypeList.Generic.Explicit(candidates.getOnly().getType());
1✔
8322
                                result = TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(void.class);
1✔
8323
                                read = false;
1✔
8324
                                break;
1✔
8325
                            case Opcodes.GETFIELD:
8326
                                parameters = new TypeList.Generic.Explicit(candidates.getOnly().getDeclaringType());
1✔
8327
                                result = candidates.getOnly().getType();
1✔
8328
                                read = true;
1✔
8329
                                break;
1✔
8330
                            case Opcodes.GETSTATIC:
8331
                                parameters = new TypeList.Generic.Empty();
1✔
8332
                                result = candidates.getOnly().getType();
1✔
8333
                                read = true;
1✔
8334
                                break;
1✔
8335
                            default:
8336
                                throw new IllegalStateException("Unexpected opcode: " + opcode);
×
8337
                        }
8338
                        stackSizeBuffer = Math.max(stackSizeBuffer, binding.make(parameters,
1✔
8339
                                result,
8340
                                read
8341
                                        ? JavaConstant.MethodHandle.ofGetter(candidates.getOnly().asDefined())
1✔
8342
                                        : JavaConstant.MethodHandle.ofSetter(candidates.getOnly().asDefined()),
1✔
8343
                                read
8344
                                        ? FieldAccess.forField(candidates.getOnly()).read()
1✔
8345
                                        : FieldAccess.forField(candidates.getOnly()).write(),
1✔
8346
                                getFreeOffset()).apply(new LocalVariableTracingMethodVisitor(mv), implementationContext).getMaximalSize());
1✔
8347
                        matched = true;
1✔
8348
                        return;
1✔
8349
                    }
8350
                } else if (strict) {
1✔
8351
                    throw new IllegalStateException("Could not resolve " + owner.replace('/', '.') + "." + internalName + descriptor + " using " + typePool);
×
8352
                }
8353
            } else if (strict) {
1✔
8354
                throw new IllegalStateException("Could not resolve " + owner.replace('/', '.') + " using " + typePool);
1✔
8355
            }
8356
            super.visitFieldInsn(opcode, owner, internalName, descriptor);
1✔
8357
        }
1✔
8358

8359
        @Override
8360
        public void visitMethodInsn(int opcode, String owner, String internalName, String descriptor, boolean isInterface) {
8361
            TypePool.Resolution resolution = typePool.describe(owner.replace('/', '.'));
1✔
8362
            if (resolution.isResolved()) {
1✔
8363
                MethodList<?> candidates;
8364
                if (opcode == Opcodes.INVOKESPECIAL && internalName.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME)) {
1✔
8365
                    candidates = resolution.resolve().getDeclaredMethods().filter(strict
1✔
8366
                            ? ElementMatchers.<MethodDescription>isConstructor().and(hasDescriptor(descriptor))
1✔
8367
                            : ElementMatchers.<MethodDescription>failSafe(isConstructor().and(hasDescriptor(descriptor))));
×
8368
                } else if (opcode == Opcodes.INVOKESTATIC) {
1✔
8369
                    Iterator<TypeDefinition> iterator = resolution.resolve().iterator();
1✔
8370
                    do {
8371
                        candidates = iterator.next().getDeclaredMethods().filter(strict
1✔
8372
                                ? ElementMatchers.<MethodDescription>named(internalName).and(hasDescriptor(descriptor))
1✔
8373
                                : ElementMatchers.<MethodDescription>failSafe(named(internalName).and(hasDescriptor(descriptor))));
×
8374
                    } while (iterator.hasNext() && candidates.isEmpty());
1✔
8375
                } else if (opcode == Opcodes.INVOKESPECIAL) {
1✔
8376
                    candidates = resolution.resolve().getDeclaredMethods().filter(strict
1✔
8377
                            ? ElementMatchers.<MethodDescription>named(internalName).and(hasDescriptor(descriptor))
1✔
8378
                            : ElementMatchers.<MethodDescription>failSafe(named(internalName).and(hasDescriptor(descriptor))));
×
8379
                } else if (virtualPrivateCalls) {
1✔
8380
                    candidates = resolution.resolve().getDeclaredMethods().filter(strict
×
8381
                            ? ElementMatchers.<MethodDescription>isPrivate().and(not(isStatic())).and(named(internalName).and(hasDescriptor(descriptor)))
×
8382
                            : ElementMatchers.<MethodDescription>failSafe(isPrivate().<MethodDescription>and(not(isStatic())).and(named(internalName).and(hasDescriptor(descriptor)))));
×
8383
                    if (candidates.isEmpty()) {
×
8384
                        candidates = methodGraphCompiler.compile((TypeDefinition) resolution.resolve(), instrumentedType).listNodes().asMethodList().filter(strict
×
8385
                                ? ElementMatchers.<MethodDescription>named(internalName).and(hasDescriptor(descriptor))
×
8386
                                : ElementMatchers.<MethodDescription>failSafe(named(internalName).and(hasDescriptor(descriptor))));
×
8387
                    }
8388
                } else {
8389
                    candidates = methodGraphCompiler.compile((TypeDefinition) resolution.resolve(), instrumentedType).listNodes().asMethodList().filter(strict
1✔
8390
                            ? ElementMatchers.<MethodDescription>named(internalName).and(hasDescriptor(descriptor))
1✔
8391
                            : ElementMatchers.<MethodDescription>failSafe(named(internalName).and(hasDescriptor(descriptor))));
×
8392
                }
8393
                if (!candidates.isEmpty()) {
1✔
8394
                    Replacement.Binding binding = replacement.bind(instrumentedType,
1✔
8395
                            instrumentedMethod,
8396
                            resolution.resolve(),
1✔
8397
                            candidates.getOnly(),
1✔
8398
                            Replacement.InvocationType.of(opcode, candidates.getOnly()));
1✔
8399
                    if (binding.isBound()) {
1✔
8400
                        StackManipulation.Size size = binding.make(
1✔
8401
                                candidates.getOnly().isStatic() || candidates.getOnly().isConstructor()
1✔
8402
                                        ? candidates.getOnly().getParameters().asTypeList()
1✔
8403
                                        : new TypeList.Generic.Explicit(CompoundList.of(resolution.resolve(), candidates.getOnly().getParameters().asTypeList())),
1✔
8404
                                candidates.getOnly().isConstructor()
1✔
8405
                                        ? candidates.getOnly().getDeclaringType().asGenericType()
1✔
8406
                                        : candidates.getOnly().getReturnType(),
1✔
8407
                                opcode == Opcodes.INVOKESPECIAL && candidates.getOnly().isMethod() && !candidates.getOnly().isPrivate()
1✔
8408
                                        ? JavaConstant.MethodHandle.ofSpecial(candidates.getOnly().asDefined(), resolution.resolve())
1✔
8409
                                        : JavaConstant.MethodHandle.of(candidates.getOnly().asDefined()),
1✔
8410
                                opcode == Opcodes.INVOKESPECIAL && candidates.getOnly().isMethod() && !candidates.getOnly().isPrivate()
1✔
8411
                                        ? MethodInvocation.invoke(candidates.getOnly()).special(resolution.resolve())
1✔
8412
                                        : MethodInvocation.invoke(candidates.getOnly()), getFreeOffset()).apply(new LocalVariableTracingMethodVisitor(mv), implementationContext);
1✔
8413
                        if (candidates.getOnly().isConstructor()) {
1✔
8414
                            stackSizeBuffer = Math.max(stackSizeBuffer, size.getMaximalSize() + 2);
1✔
8415
                            stackSizeBuffer = Math.max(stackSizeBuffer, new StackManipulation.Compound(Duplication.SINGLE.flipOver(TypeDescription.ForLoadedType.of(Object.class)),
1✔
8416
                                    Removal.SINGLE,
8417
                                    Removal.SINGLE,
8418
                                    Duplication.SINGLE.flipOver(TypeDescription.ForLoadedType.of(Object.class)),
1✔
8419
                                    Removal.SINGLE,
8420
                                    Removal.SINGLE).apply(mv, implementationContext).getMaximalSize() + StackSize.SINGLE.getSize());
1✔
8421
                        } else {
8422
                            stackSizeBuffer = Math.max(stackSizeBuffer, size.getMaximalSize());
1✔
8423
                        }
8424
                        matched = true;
1✔
8425
                        return;
1✔
8426
                    }
8427
                } else if (strict) {
1✔
8428
                    throw new IllegalStateException("Could not resolve " + owner.replace('/', '.') + "." + internalName + descriptor + " using " + typePool);
×
8429
                }
8430
            } else if (strict) {
1✔
8431
                throw new IllegalStateException("Could not resolve " + owner.replace('/', '.') + " using " + typePool);
×
8432
            }
8433
            super.visitMethodInsn(opcode, owner, internalName, descriptor, isInterface);
1✔
8434
        }
1✔
8435

8436
        @Override
8437
        public void visitInvokeDynamicInsn(String name, String descriptor, org.objectweb.asm.Handle handle, Object... argument) {
8438
            JavaConstant.MethodHandle methodHandle;
8439
            JavaConstant.MethodType methodType;
8440
            List<JavaConstant> constants = new ArrayList<JavaConstant>(argument.length);
1✔
8441
            try {
8442
                methodHandle = JavaConstant.MethodHandle.ofAsm(typePool, handle);
1✔
8443
                methodType = JavaConstant.MethodType.ofAsm(typePool, org.objectweb.asm.Type.getMethodType(descriptor));
1✔
8444
                for (Object anArgument : argument) {
1✔
8445
                    constants.add(JavaConstant.Simple.ofAsm(typePool, anArgument));
1✔
8446
                }
8447
            } catch (TypePool.Resolution.NoSuchTypeException exception) {
×
8448
                if (strict) {
×
8449
                    throw new IllegalStateException("Could not resolve " + exception.getName() + " using " + typePool);
×
8450
                }
8451
                methodHandle = null;
×
8452
                methodType = null;
×
8453
            }
1✔
8454
            if (methodHandle != null && methodType != null && constants.size() == argument.length) {
1✔
8455
                Replacement.Binding binding = replacement.bind(instrumentedType,
1✔
8456
                        instrumentedMethod,
8457
                        methodHandle,
8458
                        methodType,
8459
                        name,
8460
                        constants);
8461
                if (binding.isBound()) {
1✔
8462
                    StackManipulation.Size size = binding.make(methodType.getParameterTypes().asGenericTypes(),
1✔
8463
                            methodType.getReturnType().asGenericType(),
1✔
8464
                            methodHandle,
8465
                            new Invokedynamic(name, methodType, methodHandle, constants),
8466
                            getFreeOffset()).apply(new LocalVariableTracingMethodVisitor(mv), implementationContext);
1✔
8467
                    stackSizeBuffer = Math.max(stackSizeBuffer, size.getMaximalSize());
1✔
8468
                    matched = true;
1✔
8469
                    return;
1✔
8470
                }
8471
            }
8472
            super.visitInvokeDynamicInsn(name, descriptor, handle, argument);
×
8473
        }
×
8474

8475
        @Override
8476
        public void visitMaxs(int stackSize, int localVariableLength) {
8477
            if (failIfNoMatch && !matched) {
1✔
8478
                throw new IllegalStateException("No substitution found within " + instrumentedMethod + " of " + instrumentedType);
1✔
8479
            }
8480
            super.visitMaxs(stackSize + stackSizeBuffer, Math.max(localVariableExtension, localVariableLength));
1✔
8481
        }
1✔
8482

8483
        /**
8484
         * A method visitor that traces offsets of the local variable array being used.
8485
         */
8486
        private class LocalVariableTracingMethodVisitor extends MethodVisitor {
8487

8488
            /**
8489
             * Creates a new local variable tracing method visitor.
8490
             *
8491
             * @param methodVisitor The method visitor to delegate to.
8492
             */
8493
            private LocalVariableTracingMethodVisitor(MethodVisitor methodVisitor) {
1✔
8494
                super(OpenedClassReader.ASM_API, methodVisitor);
1✔
8495
            }
1✔
8496

8497
            @Override
8498
            @SuppressFBWarnings(value = "SF_SWITCH_NO_DEFAULT", justification = "No action required on default option.")
8499
            public void visitVarInsn(int opcode, int offset) {
8500
                switch (opcode) {
1✔
8501
                    case Opcodes.ISTORE:
8502
                    case Opcodes.FSTORE:
8503
                    case Opcodes.ASTORE:
8504
                        localVariableExtension = Math.max(localVariableExtension, offset + 1);
1✔
8505
                        break;
1✔
8506
                    case Opcodes.LSTORE:
8507
                    case Opcodes.DSTORE:
8508
                        localVariableExtension = Math.max(localVariableExtension, offset + 2);
1✔
8509
                        break;
8510
                }
8511
                super.visitVarInsn(opcode, offset);
1✔
8512
            }
1✔
8513
        }
8514
    }
8515

8516
    /**
8517
     * <p>
8518
     * Indicates that the annotated parameter should be mapped to the {@code this} reference of the substituted field,
8519
     * method, constructor or of the instrumented method.
8520
     * </p>
8521
     * <p>
8522
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.implementation.bind.annotation.This} or
8523
     * {@link net.bytebuddy.asm.Advice.This}. This annotation should be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8524
     * </p>
8525
     *
8526
     * @see Substitution.Chain.Step.ForDelegation
8527
     */
8528
    @Documented
8529
    @Retention(RetentionPolicy.RUNTIME)
8530
    @java.lang.annotation.Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.CONSTRUCTOR})
8531
    public @interface This {
8532

8533
        /**
8534
         * The typing that should be applied when assigning the {@code this} value.
8535
         *
8536
         * @return The typing to apply upon assignment.
8537
         */
8538
        Assigner.Typing typing() default Assigner.Typing.STATIC;
8539

8540
        /**
8541
         * Determines the source that is considered for this annotation which can be either the substituted method,
8542
         * constructor or field, or the instrumented method.
8543
         *
8544
         * @return The source that is considered for this annotation.
8545
         */
8546
        Source source() default Source.SUBSTITUTED_ELEMENT;
8547

8548
        /**
8549
         * Determines if the parameter should be assigned {@code null} if no {@code this} parameter is available.
8550
         *
8551
         * @return {@code true} if the value assignment is optional.
8552
         */
8553
        boolean optional() default false;
8554
    }
8555

8556
    /**
8557
     * <p>
8558
     * Indicates that the annotated parameter should be mapped to the parameter with index {@link Argument#value()}.
8559
     * </p>
8560
     * <p>
8561
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.implementation.bind.annotation.Argument} or
8562
     * {@link net.bytebuddy.asm.Advice.Argument}. This annotation should be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8563
     * </p>
8564
     *
8565
     * @see Substitution.Chain.Step.ForDelegation
8566
     */
8567
    @Documented
8568
    @Retention(RetentionPolicy.RUNTIME)
8569
    @java.lang.annotation.Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.CONSTRUCTOR})
8570
    public @interface Argument {
8571

8572
        /**
8573
         * Determines the index of the parameter that is being assigned.
8574
         *
8575
         * @return The index of the parameter that is being assigned.
8576
         */
8577
        int value();
8578

8579
        /**
8580
         * The typing that should be applied when assigning the argument.
8581
         *
8582
         * @return The typing to apply upon assignment.
8583
         */
8584
        Assigner.Typing typing() default Assigner.Typing.STATIC;
8585

8586
        /**
8587
         * Determines the source that is considered for this annotation which can be either the substituted method,
8588
         * constructor or field, or the instrumented method.
8589
         *
8590
         * @return The source that is considered for this annotation.
8591
         */
8592
        Source source() default Source.SUBSTITUTED_ELEMENT;
8593

8594
        /**
8595
         * Determines if the parameter should be assigned {@code null} if no argument with the specified index is available.
8596
         *
8597
         * @return {@code true} if the value assignment is optional.
8598
         */
8599
        boolean optional() default false;
8600
    }
8601

8602
    /**
8603
     * <p>
8604
     * Assigns an array containing all arguments of the targeted element to the annotated parameter. The annotated parameter must
8605
     * be an array type.
8606
     * </p>
8607
     * <p>
8608
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.implementation.bind.annotation.AllArguments} or
8609
     * {@link net.bytebuddy.asm.Advice.AllArguments}. This annotation should be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8610
     * </p>
8611
     *
8612
     * @see Substitution.Chain.Step.ForDelegation
8613
     */
8614
    @Documented
8615
    @Retention(RetentionPolicy.RUNTIME)
8616
    @java.lang.annotation.Target(ElementType.PARAMETER)
8617
    public @interface AllArguments {
8618

8619
        /**
8620
         * The typing that should be applied when assigning the arguments to an array element.
8621
         *
8622
         * @return The typing to apply upon assignment.
8623
         */
8624
        Assigner.Typing typing() default Assigner.Typing.STATIC;
8625

8626
        /**
8627
         * Determines the source that is considered for this annotation which can be either the substituted method,
8628
         * constructor or field, or the instrumented method.
8629
         *
8630
         * @return The source that is considered for this annotation.
8631
         */
8632
        Source source() default Source.SUBSTITUTED_ELEMENT;
8633

8634
        /**
8635
         * Determines if the produced array should include the instrumented method's target reference within the array, if
8636
         * the targeted element is non-static.
8637
         *
8638
         * @return {@code true} if a possible {@code this} reference should be included in the assigned array.
8639
         */
8640
        boolean includeSelf() default false;
8641

8642
        /**
8643
         * Determines if {@code null} should be assigned to the annotated parameter to the annotated parameter.
8644
         *
8645
         * @return {@code true} if {@code null} should be assigned to the annotated parameter to the annotated parameter.
8646
         */
8647
        boolean nullIfEmpty() default false;
8648
    }
8649

8650
    /**
8651
     * <p>
8652
     * Indicates that the annotated parameter should load a {@code java.lang.invoke.MethodHandle} that represents an invocation of
8653
     * the substituted expression or instrumented method. If the current method is virtual, it is bound to the current instance such
8654
     * that the virtual hierarchy is avoided. This annotation cannot be used to acquire a handle on enclosing constructors.
8655
     * </p>
8656
     * <p>
8657
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.asm.Advice.SelfCallHandle}. This annotation should
8658
     * be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8659
     * </p>
8660
     *
8661
     * @see Substitution.Chain.Step.ForDelegation
8662
     */
8663
    @Documented
8664
    @Retention(RetentionPolicy.RUNTIME)
8665
    @java.lang.annotation.Target(ElementType.PARAMETER)
8666
    public @interface SelfCallHandle {
8667

8668
        /**
8669
         * Determines the source that is considered for this annotation which can be either the substituted method,
8670
         * constructor or field, or the instrumented method.
8671
         *
8672
         * @return The source that is considered for this annotation.
8673
         */
8674
        Source source() default Source.SUBSTITUTED_ELEMENT;
8675

8676
        /**
8677
         * Determines if the method is bound to the arguments and instance of the represented invocation.
8678
         *
8679
         * @return {@code true} if the handle should be bound to the current arguments.
8680
         */
8681
        boolean bound() default true;
8682
    }
8683

8684
    /**
8685
     * <p>
8686
     * Indicates that the annotated parameter should load a {@code java.lang.invoke.MethodHandle} that represents an invocation of
8687
     * the specified expression.
8688
     * </p>
8689
     * <p>
8690
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.asm.Advice.Handle} or
8691
     * {@link net.bytebuddy.implementation.bind.annotation.Handle}. This annotation should be used only in combination
8692
     * with {@link Substitution.Chain.Step.ForDelegation}.
8693
     * </p>
8694
     *
8695
     * @see Substitution.Chain.Step.ForDelegation
8696
     */
8697
    @Documented
8698
    @Retention(RetentionPolicy.RUNTIME)
8699
    @java.lang.annotation.Target(ElementType.PARAMETER)
8700
    public @interface Handle {
8701

8702
        /**
8703
         * Returns the type of the method handle to resolve.
8704
         *
8705
         * @return The type of the method handle to resolve.
8706
         */
8707
        JavaConstant.MethodHandle.HandleType type();
8708

8709
        /**
8710
         * Returns the owner type of the method handle, or {@code void}, to represent the instrumented type.
8711
         *
8712
         * @return The owner type of the method handle, or {@code void}, to represent the instrumented type.
8713
         */
8714
        Class<?> owner() default void.class;
8715

8716
        /**
8717
         * Returns the name of the method handle.
8718
         *
8719
         * @return The name of the method handle.
8720
         */
8721
        String name();
8722

8723
        /**
8724
         * Returns the return type of the method handle.
8725
         *
8726
         * @return The return type of the method handle.
8727
         */
8728
        Class<?> returnType();
8729

8730
        /**
8731
         * Returns the parameter types of the method handle.
8732
         *
8733
         * @return The parameter types of the method handle.
8734
         */
8735
        Class<?>[] parameterTypes();
8736
    }
8737

8738
    /**
8739
     * <p>
8740
     * Indicates that the annotated parameter should load a dynamic constant using the specificied bootstrap method.
8741
     * The constant can be bound using constantdynamic or invokedynamic.
8742
     * </p>
8743
     * <p>
8744
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.asm.Advice.DynamicConstant} or
8745
     * {@link net.bytebuddy.implementation.bind.annotation.DynamicConstant}. This annotation should be used only in
8746
     * combination with {@link Substitution.Chain.Step.ForDelegation}.
8747
     * </p>
8748
     *
8749
     * @see Substitution.Chain.Step.ForDelegation
8750
     */
8751
    @Documented
8752
    @Retention(RetentionPolicy.RUNTIME)
8753
    @java.lang.annotation.Target(ElementType.PARAMETER)
8754
    public @interface DynamicConstant {
8755

8756
        /**
8757
         * Returns the name of the dynamic constant that is supplied to the bootstrap method.
8758
         *
8759
         * @return The name of the dynamic constant that is supplied to the bootstrap method.
8760
         */
8761
        String name() default JavaConstant.Dynamic.DEFAULT_NAME;
8762

8763
        /**
8764
         * Returns the type of the bootstrap method handle to resolve.
8765
         *
8766
         * @return The type of the bootstrap method handle to resolve.
8767
         */
8768
        JavaConstant.MethodHandle.HandleType bootstrapType();
8769

8770
        /**
8771
         * Returns the owner type of the bootstrap method handle, or {@code void}, to represent the instrumented type.
8772
         *
8773
         * @return The owner type of the bootstrap method handle, or {@code void}, to represent the instrumented type.
8774
         */
8775
        Class<?> bootstrapOwner() default void.class;
8776

8777
        /**
8778
         * Returns the name of the bootstrap method handle.
8779
         *
8780
         * @return The name of the bootstrap method handle.
8781
         */
8782
        String bootstrapName();
8783

8784
        /**
8785
         * Returns the return type of the bootstrap method handle.
8786
         *
8787
         * @return The return type of the bootstrap method handle.
8788
         */
8789
        Class<?> bootstrapReturnType();
8790

8791
        /**
8792
         * Returns the parameter types of the bootstrap method handle.
8793
         *
8794
         * @return The parameter types of the bootstrap method handle.
8795
         */
8796
        Class<?>[] bootstrapParameterTypes();
8797

8798
        /**
8799
         * Returns {@code true} if invokedynamic should be used to bind the annotated parameter.
8800
         *
8801
         * @return {@code true} if invokedynamic should be used to bind the annotated parameter.
8802
         */
8803
        boolean invokedynamic() default false;
8804
    }
8805

8806
    /**
8807
     * <p>
8808
     * Indicates that the annotated parameter should be mapped to a field in the scope of the instrumented type.
8809
     * </p>
8810
     * <p>
8811
     * Setting {@link FieldValue#value()} is optional. If the value is not set, the field value attempts to bind a setter's
8812
     * or getter's field if the intercepted method is an accessor method. Otherwise, the binding renders the target method
8813
     * to be an illegal candidate for binding.
8814
     * </p>
8815
     * <p>
8816
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.implementation.bind.annotation.FieldValue} or
8817
     * {@link net.bytebuddy.asm.Advice.FieldValue}. This annotation should be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8818
     * </p>
8819
     *
8820
     * @see Substitution.Chain.Step.ForDelegation
8821
     */
8822
    @Documented
8823
    @Retention(RetentionPolicy.RUNTIME)
8824
    @java.lang.annotation.Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.CONSTRUCTOR})
8825
    public @interface FieldValue {
8826

8827
        /**
8828
         * Returns the name of the field.
8829
         *
8830
         * @return The name of the field.
8831
         */
8832
        String value() default Substitution.Chain.Step.ForDelegation.OffsetMapping.ForField.Unresolved.BEAN_PROPERTY;
8833

8834
        /**
8835
         * Returns the type that declares the field that should be mapped to the annotated parameter. If this property
8836
         * is set to {@code void}, the field is looked up implicitly within the instrumented class's class hierarchy.
8837
         * The value can also be set to {@link TargetType} in order to look up the type on the instrumented type.
8838
         *
8839
         * @return The type that declares the field, {@code void} if this type should be determined implicitly or
8840
         * {@link TargetType} for the instrumented type.
8841
         */
8842
        Class<?> declaringType() default void.class;
8843

8844
        /**
8845
         * The typing that should be applied when assigning the field value.
8846
         *
8847
         * @return The typing to apply upon assignment.
8848
         */
8849
        Assigner.Typing typing() default Assigner.Typing.STATIC;
8850
    }
8851

8852
    /**
8853
     * <p>
8854
     * Indicates that the annotated parameter should be mapped to a {@code java.lang.invoke.MethodHandle} representing a field getter.
8855
     * </p>
8856
     * <p>
8857
     * Setting {@link FieldValue#value()} is optional. If the value is not set, the field value attempts to bind a setter's
8858
     * or getter's field if the intercepted method is an accessor method. Otherwise, the binding renders the target method
8859
     * to be an illegal candidate for binding.
8860
     * </p>
8861
     * <p>
8862
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.implementation.bind.annotation.FieldGetterHandle} or
8863
     * {@link net.bytebuddy.asm.Advice.FieldGetterHandle}. This annotation should be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8864
     * </p>
8865
     *
8866
     * @see Substitution.Chain.Step.ForDelegation
8867
     */
8868
    @Documented
8869
    @Retention(RetentionPolicy.RUNTIME)
8870
    @java.lang.annotation.Target(ElementType.PARAMETER)
8871
    public @interface FieldGetterHandle {
8872

8873
        /**
8874
         * Returns the name of the field.
8875
         *
8876
         * @return The name of the field.
8877
         */
8878
        String value() default Substitution.Chain.Step.ForDelegation.OffsetMapping.ForFieldHandle.Unresolved.BEAN_PROPERTY;
8879

8880
        /**
8881
         * Returns the type that declares the field that should be mapped to the annotated parameter. If this property
8882
         * is set to {@code void}, the field is looked up implicitly within the instrumented class's class hierarchy.
8883
         * The value can also be set to {@link TargetType} in order to look up the type on the instrumented type.
8884
         *
8885
         * @return The type that declares the field, {@code void} if this type should be determined implicitly or
8886
         * {@link TargetType} for the instrumented type.
8887
         */
8888
        Class<?> declaringType() default void.class;
8889
    }
8890

8891
    /**
8892
     * <p>
8893
     * Indicates that the annotated parameter should be mapped to a {@code java.lang.invoke.MethodHandle} representing a field setter.
8894
     * </p>
8895
     * <p>
8896
     * Setting {@link FieldValue#value()} is optional. If the value is not set, the field value attempts to bind a setter's
8897
     * or getter's field if the intercepted method is an accessor method. Otherwise, the binding renders the target method
8898
     * to be an illegal candidate for binding.
8899
     * </p>
8900
     * <p>
8901
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.implementation.bind.annotation.FieldSetterHandle} or
8902
     * {@link net.bytebuddy.asm.Advice.FieldSetterHandle}. This annotation should be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8903
     * </p>
8904
     *
8905
     * @see Substitution.Chain.Step.ForDelegation
8906
     */
8907
    @Documented
8908
    @Retention(RetentionPolicy.RUNTIME)
8909
    @java.lang.annotation.Target(ElementType.PARAMETER)
8910
    public @interface FieldSetterHandle {
8911

8912
        /**
8913
         * Returns the name of the field.
8914
         *
8915
         * @return The name of the field.
8916
         */
8917
        String value() default Substitution.Chain.Step.ForDelegation.OffsetMapping.ForFieldHandle.Unresolved.BEAN_PROPERTY;
8918

8919
        /**
8920
         * Returns the type that declares the field that should be mapped to the annotated parameter. If this property
8921
         * is set to {@code void}, the field is looked up implicitly within the instrumented class's class hierarchy.
8922
         * The value can also be set to {@link TargetType} in order to look up the type on the instrumented type.
8923
         *
8924
         * @return The type that declares the field, {@code void} if this type should be determined implicitly or
8925
         * {@link TargetType} for the instrumented type.
8926
         */
8927
        Class<?> declaringType() default void.class;
8928
    }
8929

8930
    /**
8931
     * <p>
8932
     * Indicates that the annotated parameter should be mapped to a representation of the substituted element or
8933
     * instrumented method. This representation can be a string representation, a constant representing
8934
     * the {@link Class}, a {@link Method}, {@link Constructor} or {@code java.lang.reflect.Executable}. It can also load
8935
     * a {@code java.lang.invoke.MethodType}, a {@code java.lang.invoke.MethodHandle} or a {@code java.lang.invoke.MethodHandles$Lookup}.
8936
     * Finally, it can represent the origin's modifiers if the parameter is a primitive integer type.
8937
     * </p>
8938
     * <p>
8939
     * <b>Note</b>: A constant representing a {@link Method} or {@link Constructor} is not cached but is recreated for
8940
     * every delegation.
8941
     * </p>
8942
     * <p>
8943
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.implementation.bind.annotation.Origin} or
8944
     * {@link Advice.Origin}. This annotation should be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8945
     * </p>
8946
     *
8947
     * @see Substitution.Chain.Step.ForDelegation
8948
     */
8949
    @Documented
8950
    @Retention(RetentionPolicy.RUNTIME)
8951
    @java.lang.annotation.Target(ElementType.PARAMETER)
8952
    public @interface Origin {
8953

8954
        /**
8955
         * Determines the source that is considered for this annotation which can be either the substituted method,
8956
         * constructor or field, or the instrumented method.
8957
         *
8958
         * @return The source that is considered for this annotation.
8959
         */
8960
        Source source() default Source.SUBSTITUTED_ELEMENT;
8961
    }
8962

8963
    /**
8964
     * <p>
8965
     * Indicates that the annotated parameter should always return a default value (i.e. {@code 0} for numeric values, {@code false}
8966
     * for {@code boolean} types and {@code null} for reference types).
8967
     * </p>
8968
     * <p>
8969
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.implementation.bind.annotation.Empty} or
8970
     * {@link Advice.Unused}. This annotation should be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8971
     * </p>
8972
     *
8973
     * @see Substitution.Chain.Step.ForDelegation
8974
     */
8975
    @Documented
8976
    @Retention(RetentionPolicy.RUNTIME)
8977
    @java.lang.annotation.Target(ElementType.PARAMETER)
8978
    public @interface Unused {
8979
        /* empty */
8980
    }
8981

8982
    /**
8983
     * <p>
8984
     * Indicates that the annotated parameter should always return a boxed version of the instrumented method's return value
8985
     * (i.e. {@code 0} for numeric values, {@code false} for {@code boolean} types and {@code null} for reference types). The annotated
8986
     * parameter must be of type {@link Object}.
8987
     * </p>
8988
     * <p>
8989
     * <b>Important</b>: Don't confuse this annotation with {@link net.bytebuddy.implementation.bind.annotation.StubValue} or
8990
     * {@link Advice.StubValue}. This annotation should be used only in combination with {@link Substitution.Chain.Step.ForDelegation}.
8991
     * </p>
8992
     *
8993
     * @see Substitution.Chain.Step.ForDelegation
8994
     */
8995
    @Documented
8996
    @Retention(RetentionPolicy.RUNTIME)
8997
    @java.lang.annotation.Target(ElementType.PARAMETER)
8998
    public @interface StubValue {
8999

9000
        /**
9001
         * Determines the source that is considered for this annotation which can be either the substituted method,
9002
         * constructor or field, or the instrumented method.
9003
         *
9004
         * @return The source that is considered for this annotation.
9005
         */
9006
        Source source() default Source.SUBSTITUTED_ELEMENT;
9007
    }
9008

9009
    /**
9010
     * Indicates that the annotated parameter should be assigned the value of the result that was
9011
     * yielded by the previous chain expression.
9012
     *
9013
     * @see Substitution.Chain.Step.ForDelegation
9014
     */
9015
    @Documented
9016
    @Retention(RetentionPolicy.RUNTIME)
9017
    @java.lang.annotation.Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.CONSTRUCTOR})
9018
    public @interface Current {
9019

9020
        /**
9021
         * The typing that should be applied when assigning the latest stack value.
9022
         *
9023
         * @return The typing to apply upon assignment.
9024
         */
9025
        Assigner.Typing typing() default Assigner.Typing.STATIC;
9026
    }
9027

9028
    /**
9029
     * Identifies the source of an instruction that might describe a value of the substituted element
9030
     * or the instrumented method.
9031
     */
9032
    public enum Source {
1✔
9033

9034
        /**
9035
         * Indicates that an element should be loaded in context of the substituted method, constructor or field.
9036
         */
9037
        SUBSTITUTED_ELEMENT {
1✔
9038
            @Override
9039
            @MaybeNull
9040
            protected Source.Value self(TypeList.Generic parameters,
9041
                                        Map<Integer, Integer> offsets,
9042
                                        Target target,
9043
                                        MethodDescription instrumentedMethod) {
9044
                return target.isStaticDispatch()
1✔
9045
                        ? null
9046
                        : new Source.Value(parameters.get(THIS_REFERENCE), offsets.get(THIS_REFERENCE));
1✔
9047
            }
9048

9049
            @Override
9050
            @MaybeNull
9051
            protected Source.Value argument(int index,
9052
                                            TypeList.Generic parameters,
9053
                                            Map<Integer, Integer> offsets,
9054
                                            Target target,
9055
                                            MethodDescription instrumentedMethod) {
9056
                return index < parameters.size() - (target.isStaticDispatch() ? 0 : 1)
1✔
9057
                        ? new Source.Value(parameters.get(index + (target.isStaticDispatch() ? 0 : 1)), offsets.get(index + (target.isStaticDispatch() ? 0 : 1)))
1✔
9058
                        : null;
9059
            }
9060

9061
            @Override
9062
            protected List<Source.Value> arguments(boolean includesSelf,
9063
                                                   TypeList.Generic parameters,
9064
                                                   Map<Integer, Integer> offsets,
9065
                                                   Target target,
9066
                                                   MethodDescription instrumentedMethod) {
9067
                List<Source.Value> values = new ArrayList<Source.Value>(parameters.size() - (!includesSelf && target.isStaticDispatch() ? 1 : 0));
1✔
9068
                for (int index = target.isStaticDispatch() || includesSelf ? 0 : 1; index < parameters.size(); index++) {
1✔
9069
                    values.add(new Source.Value(parameters.get(index), offsets.get(index)));
1✔
9070
                }
9071
                return values;
1✔
9072
            }
9073

9074
            @Override
9075
            protected JavaConstant.MethodHandle handle(JavaConstant.MethodHandle methodHandle, MethodDescription instrumentedMethod) {
9076
                return methodHandle;
1✔
9077
            }
9078

9079
            @Override
9080
            protected boolean isRepresentable(Substitution.Chain.Step.ForDelegation.OffsetMapping.ForOrigin.Sort sort,
9081
                                              Target target,
9082
                                              MethodDescription instrumentedMethod) {
9083
                return target instanceof Target.ForMember && sort.isRepresentable(((Target.ForMember) target).getMember());
1✔
9084
            }
9085

9086
            @Override
9087
            protected StackManipulation resolve(Substitution.Chain.Step.ForDelegation.OffsetMapping.ForOrigin.Sort sort,
9088
                                                Target target,
9089
                                                TypeList.Generic parameters,
9090
                                                TypeDescription.Generic result,
9091
                                                MethodDescription instrumentedMethod) {
9092
                ByteCodeElement.Member member = ((Target.ForMember) target).getMember();
1✔
9093
                return sort.resolve(member, parameters.asErasures(), result.asErasure());
1✔
9094
            }
9095
        },
9096

9097
        /**
9098
         * Indicates that an element should be loaded in context of the instrumented method.
9099
         */
9100
        ENCLOSING_METHOD {
1✔
9101
            @Override
9102
            @MaybeNull
9103
            protected Source.Value self(TypeList.Generic parameters,
9104
                                        Map<Integer, Integer> offsets,
9105
                                        Target target,
9106
                                        MethodDescription instrumentedMethod) {
9107
                return instrumentedMethod.isStatic()
1✔
9108
                        ? null
9109
                        : new Source.Value(instrumentedMethod.getDeclaringType().asGenericType(), THIS_REFERENCE);
1✔
9110
            }
9111

9112
            @Override
9113
            @MaybeNull
9114
            protected Source.Value argument(int index,
9115
                                            TypeList.Generic parameters,
9116
                                            Map<Integer, Integer> offsets,
9117
                                            Target target,
9118
                                            MethodDescription instrumentedMethod) {
9119
                if (index < instrumentedMethod.getParameters().size()) {
1✔
9120
                    ParameterDescription parameterDescription = instrumentedMethod.getParameters().get(index);
1✔
9121
                    return new Source.Value(parameterDescription.getType(), parameterDescription.getOffset());
1✔
9122
                } else {
9123
                    return null;
×
9124
                }
9125
            }
9126

9127
            @Override
9128
            protected List<Source.Value> arguments(boolean includesSelf,
9129
                                                   TypeList.Generic parameters,
9130
                                                   Map<Integer, Integer> offsets,
9131
                                                   Target target,
9132
                                                   MethodDescription instrumentedMethod) {
9133
                List<Source.Value> values;
9134
                if (includesSelf && !instrumentedMethod.isStatic()) {
1✔
9135
                    values = new ArrayList<Source.Value>(instrumentedMethod.getParameters().size() + 1);
×
9136
                    values.add(new Source.Value(instrumentedMethod.getDeclaringType().asGenericType(), THIS_REFERENCE));
×
9137
                } else {
9138
                    values = new ArrayList<Source.Value>(instrumentedMethod.getParameters().size());
1✔
9139
                }
9140
                for (ParameterDescription parameterDescription : instrumentedMethod.getParameters()) {
1✔
9141
                    values.add(new Source.Value(parameterDescription.getType(), parameterDescription.getOffset()));
1✔
9142
                }
1✔
9143
                return values;
1✔
9144
            }
9145

9146
            @Override
9147
            protected JavaConstant.MethodHandle handle(JavaConstant.MethodHandle methodHandle,
9148
                                                       MethodDescription instrumentedMethod) {
9149
                return JavaConstant.MethodHandle.of(instrumentedMethod.asDefined());
×
9150
            }
9151

9152
            @Override
9153
            protected boolean isRepresentable(Substitution.Chain.Step.ForDelegation.OffsetMapping.ForOrigin.Sort sort,
9154
                                              Target target,
9155
                                              MethodDescription instrumentedMethod) {
9156
                return sort.isRepresentable(instrumentedMethod);
1✔
9157
            }
9158

9159
            @Override
9160
            protected StackManipulation resolve(Substitution.Chain.Step.ForDelegation.OffsetMapping.ForOrigin.Sort sort,
9161
                                                Target target,
9162
                                                TypeList.Generic parameters,
9163
                                                TypeDescription.Generic result,
9164
                                                MethodDescription instrumentedMethod) {
9165
                return sort.resolve(instrumentedMethod,
1✔
9166
                        instrumentedMethod.isStatic() || instrumentedMethod.isConstructor()
1✔
9167
                                ? instrumentedMethod.getParameters().asTypeList().asErasures()
1✔
9168
                                : CompoundList.of(instrumentedMethod.getDeclaringType().asErasure(), instrumentedMethod.getParameters().asTypeList().asErasures()),
1✔
9169
                        instrumentedMethod.isConstructor()
1✔
9170
                                ? instrumentedMethod.getDeclaringType().asErasure()
1✔
9171
                                : instrumentedMethod.getReturnType().asErasure());
1✔
9172
            }
9173
        };
9174

9175
        /**
9176
         * Resolves a value representation of the {@code this} reference or {@code null} if no such reference is available.
9177
         *
9178
         * @param parameters         The list of parameters of the substituted element.
9179
         * @param offsets            A mapping of offsets of parameter indices to offsets.
9180
         * @param target             The target member of invokedynamic invocation.
9181
         * @param instrumentedMethod The instrumented method.
9182
         * @return A representation of the {@code this} reference or {@code null} if no such reference is available.
9183
         */
9184
        @MaybeNull
9185
        protected abstract Source.Value self(TypeList.Generic parameters,
9186
                                             Map<Integer, Integer> offsets,
9187
                                             Target target,
9188
                                             MethodDescription instrumentedMethod);
9189

9190
        /**
9191
         * Resolves a value representation of the parameter of the specified index or {@code null} if no such parameter is available.
9192
         *
9193
         * @param index              The index of the targeted parameter.
9194
         * @param parameters         The list of parameters of the substituted element.
9195
         * @param offsets            A mapping of offsets of parameter indices to offsets.
9196
         * @param target             The target member of invokedynamic invocation.
9197
         * @param instrumentedMethod The instrumented method.
9198
         * @return A representation of the parameter of the specified index or {@code null} if no such parameter is available.
9199
         */
9200
        @MaybeNull
9201
        protected abstract Source.Value argument(int index,
9202
                                                 TypeList.Generic parameters,
9203
                                                 Map<Integer, Integer> offsets,
9204
                                                 Target target,
9205
                                                 MethodDescription instrumentedMethod);
9206

9207
        /**
9208
         * Resolves a list of value representation of all parameters.
9209
         *
9210
         * @param includesSelf       {@code true} if the {@code this} reference should be included if available.
9211
         * @param parameters         The list of parameters of the substituted element.
9212
         * @param offsets            A mapping of offsets of parameter indices to offsets.
9213
         * @param target             The target member of invokedynamic invocation.
9214
         * @param instrumentedMethod The instrumented method.
9215
         * @return A list of representation of all values of all parameters.
9216
         */
9217
        protected abstract List<Source.Value> arguments(boolean includesSelf,
9218
                                                        TypeList.Generic parameters,
9219
                                                        Map<Integer, Integer> offsets,
9220
                                                        Target target,
9221
                                                        MethodDescription instrumentedMethod);
9222

9223
        /**
9224
         * Resolves a method handle.
9225
         *
9226
         * @param methodHandle       A method handle of the substituted element.
9227
         * @param instrumentedMethod The instrumented method.
9228
         * @return An appropriate method handle.
9229
         */
9230
        protected abstract JavaConstant.MethodHandle handle(JavaConstant.MethodHandle methodHandle,
9231
                                                            MethodDescription instrumentedMethod);
9232

9233
        /**
9234
         * Validates if the supplied origin sort is representable.
9235
         *
9236
         * @param sort               The sort of origin.
9237
         * @param target             The target member of invokedynamic invocation.
9238
         * @param instrumentedMethod The instrumented method.
9239
         * @return {@code true} if the supplied sort of origin is representable.
9240
         */
9241
        protected abstract boolean isRepresentable(Substitution.Chain.Step.ForDelegation.OffsetMapping.ForOrigin.Sort sort,
9242
                                                   Target target,
9243
                                                   MethodDescription instrumentedMethod);
9244

9245
        /**
9246
         * Resolves a stack manipulation that loads the supplied sort of origin onto the operand stack.
9247
         *
9248
         * @param sort               The sort of origin.
9249
         * @param target             The target member of invokedynamic invocation.
9250
         * @param parameters         The parameters to the substituted element.
9251
         * @param result             The type upon which the substituted element is invoked.
9252
         * @param instrumentedMethod The instrumented method.
9253
         * @return A stack manipulation loading the supplied sort of origin onto the operand stack.
9254
         */
9255
        protected abstract StackManipulation resolve(Substitution.Chain.Step.ForDelegation.OffsetMapping.ForOrigin.Sort sort,
9256
                                                     Target target,
9257
                                                     TypeList.Generic parameters,
9258
                                                     TypeDescription.Generic result,
9259
                                                     MethodDescription instrumentedMethod);
9260

9261
        /**
9262
         * Represents a value that can be loaded from a given offset.
9263
         */
9264
        @HashCodeAndEqualsPlugin.Enhance
9265
        protected static class Value {
9266

9267
            /**
9268
             * The type of the loaded value.
9269
             */
9270
            private final TypeDescription.Generic typeDescription;
9271

9272
            /**
9273
             * The offset of the loaded value.
9274
             */
9275
            private final int offset;
9276

9277
            /**
9278
             * Creates a value representation.
9279
             *
9280
             * @param typeDescription The type of the loaded value.
9281
             * @param offset          The offset of the loaded value.
9282
             */
9283
            protected Value(TypeDescription.Generic typeDescription, int offset) {
1✔
9284
                this.typeDescription = typeDescription;
1✔
9285
                this.offset = offset;
1✔
9286
            }
1✔
9287

9288
            /**
9289
             * Returns the type of the loaded value.
9290
             *
9291
             * @return The type of the loaded value.
9292
             */
9293
            protected TypeDescription.Generic getTypeDescription() {
9294
                return typeDescription;
1✔
9295
            }
9296

9297
            /**
9298
             * Returns the offset of the loaded value.
9299
             *
9300
             * @return The offset of the loaded value.
9301
             */
9302
            protected int getOffset() {
9303
                return offset;
1✔
9304
            }
9305
        }
9306
    }
9307

9308
    /**
9309
     * A matcher for method handles of the {@code java.lang.invoke.LambdaMetafactory}.
9310
     */
9311
    protected static class LambdaMetaFactoryMatcher implements ElementMatcher<JavaConstant.MethodHandle> {
1✔
9312

9313
        /**
9314
         * {@inheritDoc}
9315
         */
9316
        public boolean matches(@MaybeNull JavaConstant.MethodHandle target) {
9317
            return target != null && target.getOwnerType().getName().equals("java.lang.invoke.LambdaMetafactory");
1✔
9318
        }
9319
    }
9320
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc