• 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

94.76
/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/MethodCall.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.implementation;
17

18
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20
import net.bytebuddy.description.enumeration.EnumerationDescription;
21
import net.bytebuddy.description.field.FieldDescription;
22
import net.bytebuddy.description.field.FieldList;
23
import net.bytebuddy.description.method.MethodDescription;
24
import net.bytebuddy.description.method.ParameterDescription;
25
import net.bytebuddy.description.method.ParameterList;
26
import net.bytebuddy.description.type.TypeDefinition;
27
import net.bytebuddy.description.type.TypeDescription;
28
import net.bytebuddy.dynamic.scaffold.FieldLocator;
29
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
30
import net.bytebuddy.dynamic.scaffold.MethodGraph;
31
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
32
import net.bytebuddy.implementation.bytecode.Duplication;
33
import net.bytebuddy.implementation.bytecode.Removal;
34
import net.bytebuddy.implementation.bytecode.StackManipulation;
35
import net.bytebuddy.implementation.bytecode.TypeCreation;
36
import net.bytebuddy.implementation.bytecode.assign.Assigner;
37
import net.bytebuddy.implementation.bytecode.collection.ArrayAccess;
38
import net.bytebuddy.implementation.bytecode.collection.ArrayFactory;
39
import net.bytebuddy.implementation.bytecode.constant.ClassConstant;
40
import net.bytebuddy.implementation.bytecode.constant.IntegerConstant;
41
import net.bytebuddy.implementation.bytecode.constant.NullConstant;
42
import net.bytebuddy.implementation.bytecode.member.FieldAccess;
43
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
44
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
45
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
46
import net.bytebuddy.matcher.ElementMatcher;
47
import net.bytebuddy.matcher.ElementMatchers;
48
import net.bytebuddy.utility.CompoundList;
49
import net.bytebuddy.utility.ConstantValue;
50
import net.bytebuddy.utility.JavaConstant;
51
import net.bytebuddy.utility.RandomString;
52
import net.bytebuddy.utility.nullability.MaybeNull;
53
import org.objectweb.asm.MethodVisitor;
54
import org.objectweb.asm.Opcodes;
55

56
import java.lang.reflect.Constructor;
57
import java.lang.reflect.Field;
58
import java.lang.reflect.Method;
59
import java.lang.reflect.Type;
60
import java.util.ArrayList;
61
import java.util.Arrays;
62
import java.util.Collections;
63
import java.util.Iterator;
64
import java.util.List;
65
import java.util.concurrent.Callable;
66

67
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
68
import static net.bytebuddy.matcher.ElementMatchers.isVisibleTo;
69
import static net.bytebuddy.matcher.ElementMatchers.named;
70
import static net.bytebuddy.matcher.ElementMatchers.not;
71

72
/**
73
 * This {@link Implementation} allows the invocation of a specified method while
74
 * providing explicit arguments to this method.
75
 */
76
@HashCodeAndEqualsPlugin.Enhance
77
public class MethodCall implements Implementation.Composable {
78

79
    /**
80
     * The method locator to use.
81
     */
82
    protected final MethodLocator.Factory methodLocator;
83

84
    /**
85
     * The target handler to use.
86
     */
87
    protected final TargetHandler.Factory targetHandler;
88

89
    /**
90
     * The argument loader to load arguments onto the operand stack in their application order.
91
     */
92
    protected final List<ArgumentLoader.Factory> argumentLoaders;
93

94
    /**
95
     * The method invoker to use.
96
     */
97
    protected final MethodInvoker.Factory methodInvoker;
98

99
    /**
100
     * The termination handler to use.
101
     */
102
    protected final TerminationHandler.Factory terminationHandler;
103

104
    /**
105
     * The assigner to use.
106
     */
107
    protected final Assigner assigner;
108

109
    /**
110
     * Indicates if dynamic type castings should be attempted for incompatible assignments.
111
     */
112
    protected final Assigner.Typing typing;
113

114
    /**
115
     * Creates a new method call implementation.
116
     *
117
     * @param methodLocator      The method locator to use.
118
     * @param targetHandler      The target handler to use.
119
     * @param argumentLoaders    The argument loader to load arguments onto the operand stack in their application order.
120
     * @param methodInvoker      The method invoker to use.
121
     * @param terminationHandler The termination handler to use.
122
     * @param assigner           The assigner to use.
123
     * @param typing             Indicates if dynamic type castings should be attempted for incompatible assignments.
124
     */
125
    protected MethodCall(MethodLocator.Factory methodLocator,
126
                         TargetHandler.Factory targetHandler,
127
                         List<ArgumentLoader.Factory> argumentLoaders,
128
                         MethodInvoker.Factory methodInvoker,
129
                         TerminationHandler.Factory terminationHandler,
130
                         Assigner assigner,
131
                         Assigner.Typing typing) {
1✔
132
        this.methodLocator = methodLocator;
1✔
133
        this.targetHandler = targetHandler;
1✔
134
        this.argumentLoaders = argumentLoaders;
1✔
135
        this.methodInvoker = methodInvoker;
1✔
136
        this.terminationHandler = terminationHandler;
1✔
137
        this.assigner = assigner;
1✔
138
        this.typing = typing;
1✔
139
    }
1✔
140

141
    /**
142
     * Invokes the given method. Without further specification, the method is invoked without any arguments on
143
     * the instance of the instrumented class or statically, if the given method is {@code static}.
144
     *
145
     * @param method The method to invoke.
146
     * @return A method call implementation that invokes the given method without providing any arguments.
147
     */
148
    public static WithoutSpecifiedTarget invoke(Method method) {
149
        return invoke(new MethodDescription.ForLoadedMethod(method));
1✔
150
    }
151

152
    /**
153
     * <p>
154
     * Invokes the given constructor on the instance of the instrumented type.
155
     * </p>
156
     * <p>
157
     * <b>Important</b>: A constructor invocation can only be applied within another constructor to invoke the super constructor or an auxiliary
158
     * constructor. To construct a new instance, use {@link MethodCall#construct(Constructor)}.
159
     * </p>
160
     *
161
     * @param constructor The constructor to invoke.
162
     * @return A method call implementation that invokes the given constructor without providing any arguments.
163
     */
164
    public static WithoutSpecifiedTarget invoke(Constructor<?> constructor) {
165
        return invoke(new MethodDescription.ForLoadedConstructor(constructor));
1✔
166
    }
167

168
    /**
169
     * <p>
170
     * Invokes the given method. If the method description describes a constructor, it is automatically invoked as
171
     * a special method invocation on the instance of the instrumented type. The same is true for {@code private}
172
     * methods. Finally, {@code static} methods are invoked statically.
173
     * </p>
174
     * <p>
175
     * <b>Important</b>: A constructor invocation can only be applied within another constructor to invoke the super constructor or an auxiliary
176
     * constructor. To construct a new instance, use {@link MethodCall#construct(MethodDescription)}.
177
     * </p>
178
     *
179
     * @param methodDescription The method to invoke.
180
     * @return A method call implementation that invokes the given method without providing any arguments.
181
     */
182
    public static WithoutSpecifiedTarget invoke(MethodDescription methodDescription) {
183
        return invoke(new MethodLocator.ForExplicitMethod(methodDescription));
1✔
184
    }
185

186
    /**
187
     * Invokes a unique virtual method or constructor of the instrumented type that is matched by the specified matcher.
188
     *
189
     * @param matcher The matcher to identify the method to invoke.
190
     * @return A method call for the uniquely identified method.
191
     */
192
    @SuppressWarnings("overloads")
193
    public static WithoutSpecifiedTarget invoke(ElementMatcher<? super MethodDescription> matcher) {
194
        return invoke(matcher, MethodGraph.Compiler.DEFAULT);
1✔
195
    }
196

197
    /**
198
     * Invokes a unique virtual method or constructor of the instrumented type that is matched by the specified matcher.
199
     *
200
     * @param matcher             The matcher to identify the method to invoke.
201
     * @param methodGraphCompiler The method graph compiler to use.
202
     * @return A method call for the uniquely identified method.
203
     */
204
    public static WithoutSpecifiedTarget invoke(ElementMatcher<? super MethodDescription> matcher, MethodGraph.Compiler methodGraphCompiler) {
205
        return invoke(new MethodLocator.ForElementMatcher.Factory(matcher, methodGraphCompiler));
1✔
206
    }
207

208
    /**
209
     * Invokes a method using the provided method locator.
210
     *
211
     * @param methodLocator The method locator to apply for locating the method to invoke given the instrumented
212
     *                      method.
213
     * @return A method call implementation that uses the provided method locator for resolving the method
214
     * to be invoked.
215
     */
216
    @SuppressWarnings("overloads")
217
    public static WithoutSpecifiedTarget invoke(MethodLocator.Factory methodLocator) {
218
        return new WithoutSpecifiedTarget(methodLocator);
1✔
219
    }
220

221
    /**
222
     * Invokes the instrumented method recursively. Invoking this method on the same instance causes a {@link StackOverflowError} due to
223
     * infinite recursion.
224
     *
225
     * @return A method call that invokes the method being instrumented.
226
     */
227
    public static WithoutSpecifiedTarget invokeSelf() {
228
        return new WithoutSpecifiedTarget(MethodLocator.ForInstrumentedMethod.INSTANCE);
1✔
229
    }
230

231
    /**
232
     * Invokes the instrumented method as a super method call on the instance itself. This is a shortcut for {@code invokeSelf().onSuper()}.
233
     *
234
     * @return A method call that invokes the method being instrumented as a super method call.
235
     */
236
    public static MethodCall invokeSuper() {
237
        return invokeSelf().onSuper();
1✔
238
    }
239

240
    /**
241
     * Implements a method by invoking the provided {@link Callable}. The return value of the provided object is casted to the implemented method's
242
     * return type, if necessary.
243
     *
244
     * @param callable The callable to invoke when a method is intercepted.
245
     * @return A composable method implementation that invokes the given callable.
246
     */
247
    public static Composable call(Callable<?> callable) {
248
        try {
249
            return invoke(Callable.class.getMethod("call")).on(callable, Callable.class).withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC);
1✔
250
        } catch (NoSuchMethodException exception) {
×
251
            throw new IllegalStateException("Could not locate Callable::call method", exception);
×
252
        }
253
    }
254

255
    /**
256
     * Implements a method by invoking the provided {@link Runnable}. If the instrumented method returns a value, {@code null} is returned.
257
     *
258
     * @param runnable The runnable to invoke when a method is intercepted.
259
     * @return A composable method implementation that invokes the given runnable.
260
     */
261
    public static Composable run(Runnable runnable) {
262
        try {
263
            return invoke(Runnable.class.getMethod("run")).on(runnable, Runnable.class).withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC);
1✔
264
        } catch (NoSuchMethodException exception) {
×
265
            throw new IllegalStateException("Could not locate Runnable::run method", exception);
×
266
        }
267
    }
268

269
    /**
270
     * Invokes the given constructor in order to create an instance.
271
     *
272
     * @param constructor The constructor to invoke.
273
     * @return A method call that invokes the given constructor without providing any arguments.
274
     */
275
    public static MethodCall construct(Constructor<?> constructor) {
276
        return construct(new MethodDescription.ForLoadedConstructor(constructor));
1✔
277
    }
278

279
    /**
280
     * Invokes the given constructor in order to create an instance.
281
     *
282
     * @param methodDescription A description of the constructor to invoke.
283
     * @return A method call that invokes the given constructor without providing any arguments.
284
     */
285
    public static MethodCall construct(MethodDescription methodDescription) {
286
        if (!methodDescription.isConstructor()) {
1✔
287
            throw new IllegalArgumentException("Not a constructor: " + methodDescription);
1✔
288
        }
289
        return new MethodCall(new MethodLocator.ForExplicitMethod(methodDescription),
1✔
290
                TargetHandler.ForConstructingInvocation.Factory.INSTANCE,
291
                Collections.<ArgumentLoader.Factory>emptyList(),
1✔
292
                MethodInvoker.ForContextualInvocation.Factory.INSTANCE,
293
                TerminationHandler.Simple.RETURNING,
294
                Assigner.DEFAULT,
295
                Assigner.Typing.STATIC);
296
    }
297

298
    /**
299
     * Defines a number of arguments to be handed to the method that is being invoked by this implementation. Any
300
     * wrapper type instances for primitive values, instances of {@link java.lang.String}, method handles, types,
301
     * method types as well as instances of {@link TypeDescription} or {@link JavaConstant} or {@code null} are loaded
302
     * directly onto the operand stack. This might corrupt referential identity for these values. Any other values
303
     * are stored within a {@code static} field that is added to the instrumented type.
304
     *
305
     * @param argument The arguments to provide to the method that is being called in their order.
306
     * @return A method call that hands the provided arguments to the invoked method.
307
     */
308
    public MethodCall with(Object... argument) {
309
        List<ArgumentLoader.Factory> argumentLoaders = new ArrayList<ArgumentLoader.Factory>(argument.length);
1✔
310
        for (Object anArgument : argument) {
1✔
311
            argumentLoaders.add(ArgumentLoader.ForStackManipulation.of(anArgument));
1✔
312
        }
313
        return with(argumentLoaders);
1✔
314
    }
315

316
    /**
317
     * Defines the given types to be provided as arguments to the invoked method where the represented types
318
     * are stored in the generated class's constant pool.
319
     *
320
     * @param typeDescription The type descriptions to provide as arguments.
321
     * @return A method call that hands the provided arguments to the invoked method.
322
     */
323
    public MethodCall with(TypeDescription... typeDescription) {
324
        List<ArgumentLoader.Factory> argumentLoaders = new ArrayList<ArgumentLoader.Factory>(typeDescription.length);
1✔
325
        for (TypeDescription aTypeDescription : typeDescription) {
1✔
326
            argumentLoaders.add(new ArgumentLoader.ForStackManipulation(ClassConstant.of(aTypeDescription), Class.class));
1✔
327
        }
328
        return with(argumentLoaders);
1✔
329
    }
330

331
    /**
332
     * Defines the given enumeration values to be provided as arguments to the invoked method where the values
333
     * are read from the enumeration class on demand.
334
     *
335
     * @param enumerationDescription The enumeration descriptions to provide as arguments.
336
     * @return A method call that hands the provided arguments to the invoked method.
337
     */
338
    public MethodCall with(EnumerationDescription... enumerationDescription) {
339
        List<ArgumentLoader.Factory> argumentLoaders = new ArrayList<ArgumentLoader.Factory>(enumerationDescription.length);
×
340
        for (EnumerationDescription anEnumerationDescription : enumerationDescription) {
×
341
            argumentLoaders.add(new ArgumentLoader.ForStackManipulation(FieldAccess.forEnumeration(anEnumerationDescription), anEnumerationDescription.getEnumerationType()));
×
342
        }
343
        return with(argumentLoaders);
×
344
    }
345

346
    /**
347
     * Defines the given Java instances to be provided as arguments to the invoked method where the given
348
     * instances are stored in the generated class's constant pool.
349
     *
350
     * @param constant The constants to provide as arguments.
351
     * @return A method call that hands the provided arguments to the invoked method.
352
     */
353
    public MethodCall with(ConstantValue... constant) {
354
        List<ArgumentLoader.Factory> argumentLoaders = new ArrayList<ArgumentLoader.Factory>(constant.length);
×
355
        for (ConstantValue aConstant : constant) {
×
356
            argumentLoaders.add(new ArgumentLoader.ForStackManipulation(aConstant.toStackManipulation(), aConstant.getTypeDescription()));
×
357
        }
358
        return with(argumentLoaders);
×
359
    }
360

361
    /**
362
     * Defines the given Java instances to be provided as arguments to the invoked method where the given
363
     * instances are stored in the generated class's constant pool.
364
     *
365
     * @param constant The constants to provide as arguments.
366
     * @return A method call that hands the provided arguments to the invoked method.
367
     */
368
    public MethodCall with(JavaConstant... constant) {
369
        return with((ConstantValue[]) constant);
×
370
    }
371

372
    /**
373
     * Defines a number of arguments to be handed to the method that is being invoked by this implementation. Any
374
     * value is stored within a field in order to preserve referential identity. As an exception, the {@code null}
375
     * value is not stored within a field.
376
     *
377
     * @param argument The arguments to provide to the method that is being called in their order.
378
     * @return A method call that hands the provided arguments to the invoked method.
379
     */
380
    public MethodCall withReference(Object... argument) {
381
        List<ArgumentLoader.Factory> argumentLoaders = new ArrayList<ArgumentLoader.Factory>(argument.length);
1✔
382
        for (Object anArgument : argument) {
1✔
383
            argumentLoaders.add(anArgument == null
1✔
384
                    ? ArgumentLoader.ForNullConstant.INSTANCE
385
                    : new ArgumentLoader.ForInstance.Factory(anArgument));
386
        }
387
        return with(argumentLoaders);
1✔
388
    }
389

390
    /**
391
     * Defines a number of arguments of the instrumented method by their parameter indices to be handed
392
     * to the invoked method as an argument.
393
     *
394
     * @param index The parameter indices of the instrumented method to be handed to the invoked method as an
395
     *              argument in their order. The indices are zero-based.
396
     * @return A method call that hands the provided arguments to the invoked method.
397
     */
398
    public MethodCall withArgument(int... index) {
399
        List<ArgumentLoader.Factory> argumentLoaders = new ArrayList<ArgumentLoader.Factory>(index.length);
1✔
400
        for (int anIndex : index) {
1✔
401
            if (anIndex < 0) {
1✔
402
                throw new IllegalArgumentException("Negative index: " + anIndex);
1✔
403
            }
404
            argumentLoaders.add(new ArgumentLoader.ForMethodParameter.Factory(anIndex));
1✔
405
        }
406
        return with(argumentLoaders);
1✔
407
    }
408

409
    /**
410
     * Adds all arguments of the instrumented method as arguments to the invoked method to this method call.
411
     *
412
     * @return A method call that hands all arguments of the instrumented method to the invoked method.
413
     */
414
    public MethodCall withAllArguments() {
415
        return with(ArgumentLoader.ForMethodParameter.OfInstrumentedMethod.INSTANCE);
1✔
416
    }
417

418
    /**
419
     * Adds an array containing all arguments of the instrumented method to this method call.
420
     *
421
     * @return A method call that adds an array containing all arguments of the instrumented method to the invoked method.
422
     */
423
    public MethodCall withArgumentArray() {
424
        return with(ArgumentLoader.ForMethodParameterArray.ForInstrumentedMethod.INSTANCE);
1✔
425
    }
426

427
    /**
428
     * <p>
429
     * Creates a method call where the parameter with {@code index} is expected to be an array and where each element of the array
430
     * is expected to represent an argument for the method being invoked.
431
     * </p>
432
     * <p>
433
     * <b>Note</b>: This is typically used in combination with dynamic type assignments which is activated via
434
     * {@link MethodCall#withAssigner(Assigner, Assigner.Typing)} using a {@link Assigner.Typing#DYNAMIC}.
435
     * </p>
436
     *
437
     * @param index The index of the parameter.
438
     * @return A method call that loads {@code size} elements from the array handed to the instrumented method as argument {@code index}.
439
     */
440
    public MethodCall withArgumentArrayElements(int index) {
441
        if (index < 0) {
1✔
442
            throw new IllegalArgumentException("A parameter index cannot be negative: " + index);
1✔
443
        }
444
        return with(new ArgumentLoader.ForMethodParameterArrayElement.OfInvokedMethod(index));
1✔
445
    }
446

447
    /**
448
     * <p>
449
     * Creates a method call where the parameter with {@code index} is expected to be an array and where {@code size} elements are loaded
450
     * from the array as arguments for the invoked method.
451
     * </p>
452
     * <p>
453
     * <b>Note</b>: This is typically used in combination with dynamic type assignments which is activated via
454
     * {@link MethodCall#withAssigner(Assigner, Assigner.Typing)} using a {@link Assigner.Typing#DYNAMIC}.
455
     * </p>
456
     *
457
     * @param index The index of the parameter.
458
     * @param size  The amount of elements to load from the array.
459
     * @return A method call that loads {@code size} elements from the array handed to the instrumented method as argument {@code index}.
460
     */
461
    public MethodCall withArgumentArrayElements(int index, int size) {
462
        return withArgumentArrayElements(index, 0, size);
1✔
463
    }
464

465
    /**
466
     * <p>
467
     * Creates a method call where the parameter with {@code index} is expected to be an array and where {@code size} elements are loaded
468
     * from the array as arguments for the invoked method. The first element is loaded from index {@code start}.
469
     * </p>
470
     * <p>
471
     * <b>Note</b>: This is typically used in combination with dynamic type assignments which is activated via
472
     * {@link MethodCall#withAssigner(Assigner, Assigner.Typing)} using a {@link Assigner.Typing#DYNAMIC}.
473
     * </p>
474
     *
475
     * @param index The index of the parameter.
476
     * @param start The first array index to consider.
477
     * @param size  The amount of elements to load from the array with increasing index from {@code start}.
478
     * @return A method call that loads {@code size} elements from the array handed to the instrumented method as argument {@code index}.
479
     */
480
    public MethodCall withArgumentArrayElements(int index, int start, int size) {
481
        if (index < 0) {
1✔
482
            throw new IllegalArgumentException("A parameter index cannot be negative: " + index);
1✔
483
        } else if (start < 0) {
1✔
484
            throw new IllegalArgumentException("An array index cannot be negative: " + start);
1✔
485
        } else if (size == 0) {
1✔
486
            return this;
1✔
487
        } else if (size < 0) {
1✔
488
            throw new IllegalArgumentException("Size cannot be negative: " + size);
1✔
489
        }
490
        List<ArgumentLoader.Factory> argumentLoaders = new ArrayList<ArgumentLoader.Factory>(size);
1✔
491
        for (int position = 0; position < size; position++) {
1✔
492
            argumentLoaders.add(new ArgumentLoader.ForMethodParameterArrayElement.OfParameter(index, start + position));
1✔
493
        }
494
        return with(argumentLoaders);
1✔
495
    }
496

497
    /**
498
     * Assigns the {@code this} reference to the next parameter.
499
     *
500
     * @return This method call where the next parameter is a assigned a reference to the {@code this} reference
501
     * of the instance of the intercepted method.
502
     */
503
    public MethodCall withThis() {
504
        return with(ArgumentLoader.ForThisReference.Factory.INSTANCE);
1✔
505
    }
506

507
    /**
508
     * Assigns the {@link java.lang.Class} value of the instrumented type.
509
     *
510
     * @return This method call where the next parameter is a assigned a reference to the {@link java.lang.Class}
511
     * value of the instrumented type.
512
     */
513
    public MethodCall withOwnType() {
514
        return with(ArgumentLoader.ForInstrumentedType.Factory.INSTANCE);
1✔
515
    }
516

517
    /**
518
     * Defines a method call which fetches a value from a list of existing fields.
519
     *
520
     * @param name The names of the fields.
521
     * @return A method call which assigns the next parameters to the values of the given fields.
522
     */
523
    public MethodCall withField(String... name) {
524
        return withField(FieldLocator.ForClassHierarchy.Factory.INSTANCE, name);
1✔
525
    }
526

527
    /**
528
     * Defines a method call which fetches a value from a list of existing fields.
529
     *
530
     * @param fieldLocatorFactory The field locator factory to use.
531
     * @param name                The names of the fields.
532
     * @return A method call which assigns the next parameters to the values of the given fields.
533
     */
534
    public MethodCall withField(FieldLocator.Factory fieldLocatorFactory, String... name) {
535
        List<ArgumentLoader.Factory> argumentLoaders = new ArrayList<ArgumentLoader.Factory>(name.length);
1✔
536
        for (String aName : name) {
1✔
537
            argumentLoaders.add(new ArgumentLoader.ForField.Factory(aName, fieldLocatorFactory));
1✔
538
        }
539
        return with(argumentLoaders);
1✔
540
    }
541

542
    /**
543
     * Defines a method call which fetches a value from a method call.
544
     *
545
     * @param methodCall The method call to use.
546
     * @return A method call which assigns the parameter to the result of the given method call.
547
     */
548
    public MethodCall withMethodCall(MethodCall methodCall) {
549
        return with(new ArgumentLoader.ForMethodCall.Factory(methodCall));
1✔
550
    }
551

552
    /**
553
     * Adds a stack manipulation as an assignment to the next parameter.
554
     *
555
     * @param stackManipulation The stack manipulation loading the value.
556
     * @param type              The type of the argument being loaded.
557
     * @return A method call that adds the stack manipulation as the next argument to the invoked method.
558
     */
559
    public MethodCall with(StackManipulation stackManipulation, Type type) {
560
        return with(stackManipulation, TypeDefinition.Sort.describe(type));
1✔
561
    }
562

563
    /**
564
     * Adds a stack manipulation as an assignment to the next parameter.
565
     *
566
     * @param stackManipulation The stack manipulation loading the value.
567
     * @param typeDefinition    The type of the argument being loaded.
568
     * @return A method call that adds the stack manipulation as the next argument to the invoked method.
569
     */
570
    public MethodCall with(StackManipulation stackManipulation, TypeDefinition typeDefinition) {
571
        return with(new ArgumentLoader.ForStackManipulation(stackManipulation, typeDefinition));
1✔
572
    }
573

574
    /**
575
     * Defines a method call that resolves arguments by the supplied argument loader factories.
576
     *
577
     * @param argumentLoader The argument loaders to apply to the subsequent arguments of the
578
     * @return A method call that adds the arguments of the supplied argument loaders to the invoked method.
579
     */
580
    public MethodCall with(ArgumentLoader.Factory... argumentLoader) {
581
        return with(Arrays.asList(argumentLoader));
1✔
582
    }
583

584
    /**
585
     * Defines a method call that resolves arguments by the supplied argument loader factories.
586
     *
587
     * @param argumentLoaders The argument loaders to apply to the subsequent arguments of the
588
     * @return A method call that adds the arguments of the supplied argument loaders to the invoked method.
589
     */
590
    public MethodCall with(List<? extends ArgumentLoader.Factory> argumentLoaders) {
591
        return new MethodCall(methodLocator,
1✔
592
                targetHandler,
593
                CompoundList.of(this.argumentLoaders, argumentLoaders),
1✔
594
                methodInvoker,
595
                terminationHandler,
596
                assigner,
597
                typing);
598
    }
599

600
    /**
601
     * Sets the result of the method call as a value of the specified field. If the instrumented method does not
602
     * return {@code void}, this instrumentation must be chained with another instrumentation.
603
     *
604
     * @param field The field to set.
605
     * @return A new instance of this method call that sets the resulting value as the specified field's value.
606
     */
607
    public FieldSetting setsField(Field field) {
608
        return setsField(new FieldDescription.ForLoadedField(field));
1✔
609
    }
610

611
    /**
612
     * Sets the result of the method call as a value of the specified field. If the instrumented method does not
613
     * return {@code void}, this instrumentation must be chained with another instrumentation.
614
     *
615
     * @param fieldDescription The field to set.
616
     * @return A new instance of this method call that sets the resulting value as the specified field's value.
617
     */
618
    public FieldSetting setsField(FieldDescription fieldDescription) {
619
        return new FieldSetting(new MethodCall(methodLocator,
1✔
620
                targetHandler,
621
                argumentLoaders,
622
                methodInvoker,
623
                new TerminationHandler.FieldSetting.Explicit(fieldDescription),
624
                assigner,
625
                typing));
626
    }
627

628
    /**
629
     * Sets the result of the method call as a value of the specified field. If the instrumented method does not
630
     * return {@code void}, this instrumentation must be chained with another instrumentation.
631
     *
632
     * @param matcher A matcher that locates a field in the instrumented type's hierarchy.
633
     * @return A new instance of this method call that sets the resulting value as the specified field's value.
634
     */
635
    public FieldSetting setsField(ElementMatcher<? super FieldDescription> matcher) {
636
        return new FieldSetting(new MethodCall(methodLocator,
1✔
637
                targetHandler,
638
                argumentLoaders,
639
                methodInvoker,
640
                new TerminationHandler.FieldSetting.Implicit(matcher),
641
                assigner,
642
                typing));
643
    }
644

645
    /**
646
     * Defines an assigner to be used for assigning values to the parameters of the invoked method. This assigner
647
     * is also used for assigning the invoked method's return value to the return type of the instrumented method,
648
     * if this method is not chained with
649
     * {@link net.bytebuddy.implementation.MethodCall#andThen(Implementation)} such
650
     * that a return value of this method call is discarded.
651
     *
652
     * @param assigner The assigner to use.
653
     * @param typing   Indicates if dynamic type castings should be attempted for incompatible assignments.
654
     * @return This method call using the provided assigner.
655
     */
656
    public Composable withAssigner(Assigner assigner, Assigner.Typing typing) {
657
        return new MethodCall(methodLocator,
1✔
658
                targetHandler,
659
                argumentLoaders,
660
                methodInvoker,
661
                terminationHandler,
662
                assigner,
663
                typing);
664
    }
665

666
    /**
667
     * {@inheritDoc}
668
     */
669
    public Implementation andThen(Implementation implementation) {
670
        return new Implementation.Compound(new MethodCall(methodLocator,
1✔
671
                targetHandler,
672
                argumentLoaders,
673
                methodInvoker,
674
                TerminationHandler.Simple.DROPPING,
675
                assigner,
676
                typing), implementation);
677
    }
678

679
    /**
680
     * {@inheritDoc}
681
     */
682
    public Composable andThen(Composable implementation) {
683
        return new Implementation.Compound.Composable(new MethodCall(methodLocator,
1✔
684
                targetHandler,
685
                argumentLoaders,
686
                methodInvoker,
687
                TerminationHandler.Simple.DROPPING,
688
                assigner,
689
                typing), implementation);
690
    }
691

692
    /**
693
     * {@inheritDoc}
694
     */
695
    public InstrumentedType prepare(InstrumentedType instrumentedType) {
696
        for (InstrumentedType.Prepareable prepareable : argumentLoaders) {
1✔
697
            instrumentedType = prepareable.prepare(instrumentedType);
1✔
698
        }
1✔
699
        return targetHandler.prepare(instrumentedType);
1✔
700
    }
701

702
    /**
703
     * {@inheritDoc}
704
     */
705
    public ByteCodeAppender appender(Target implementationTarget) {
706
        return new Appender(implementationTarget, terminationHandler.make(implementationTarget.getInstrumentedType()));
1✔
707
    }
708

709
    /**
710
     * A method locator is responsible for identifying the method that is to be invoked
711
     * by a {@link net.bytebuddy.implementation.MethodCall}.
712
     */
713
    public interface MethodLocator {
714

715
        /**
716
         * Resolves the method to be invoked.
717
         *
718
         * @param targetType         The type the method is called on.
719
         * @param instrumentedMethod The method being instrumented.
720
         * @return The method to invoke.
721
         */
722
        MethodDescription resolve(TypeDescription targetType, MethodDescription instrumentedMethod);
723

724
        /**
725
         * A factory for creating a method locator.
726
         */
727
        interface Factory {
728

729
            /**
730
             * Creates a method locator for a given instrumented type.
731
             *
732
             * @param instrumentedType The instrumented type.
733
             * @return A suitable method locator.
734
             */
735
            MethodLocator make(TypeDescription instrumentedType);
736
        }
737

738
        /**
739
         * A method locator that simply returns the intercepted method.
740
         */
741
        enum ForInstrumentedMethod implements MethodLocator, Factory {
1✔
742

743
            /**
744
             * The singleton instance.
745
             */
746
            INSTANCE;
1✔
747

748
            /**
749
             * {@inheritDoc}
750
             */
751
            public MethodLocator make(TypeDescription instrumentedType) {
752
                return this;
1✔
753
            }
754

755
            /**
756
             * {@inheritDoc}
757
             */
758
            public MethodDescription resolve(TypeDescription targetType, MethodDescription instrumentedMethod) {
759
                return instrumentedMethod;
1✔
760
            }
761
        }
762

763
        /**
764
         * Invokes a given method.
765
         */
766
        @HashCodeAndEqualsPlugin.Enhance
767
        class ForExplicitMethod implements MethodLocator, Factory {
768

769
            /**
770
             * The method to be invoked.
771
             */
772
            private final MethodDescription methodDescription;
773

774
            /**
775
             * Creates a new method locator for a given method.
776
             *
777
             * @param methodDescription The method to be invoked.
778
             */
779
            protected ForExplicitMethod(MethodDescription methodDescription) {
1✔
780
                this.methodDescription = methodDescription;
1✔
781
            }
1✔
782

783
            /**
784
             * {@inheritDoc}
785
             */
786
            public MethodLocator make(TypeDescription instrumentedType) {
787
                return this;
1✔
788
            }
789

790
            /**
791
             * {@inheritDoc}
792
             */
793
            public MethodDescription resolve(TypeDescription targetType, MethodDescription instrumentedMethod) {
794
                return methodDescription;
1✔
795
            }
796
        }
797

798
        /**
799
         * A method locator that identifies a unique virtual method.
800
         */
801
        @HashCodeAndEqualsPlugin.Enhance
802
        class ForElementMatcher implements MethodLocator {
803

804
            /**
805
             * The instrumented type.
806
             */
807
            private final TypeDescription instrumentedType;
808

809
            /**
810
             * The matcher to use.
811
             */
812
            private final ElementMatcher<? super MethodDescription> matcher;
813

814
            /**
815
             * The method graph compiler to use.
816
             */
817
            private final MethodGraph.Compiler methodGraphCompiler;
818

819
            /**
820
             * Creates a new method locator for an element matcher.
821
             *
822
             * @param instrumentedType    The instrumented type.
823
             * @param matcher             The matcher to use.
824
             * @param methodGraphCompiler The method graph compiler to use.
825
             */
826
            protected ForElementMatcher(TypeDescription instrumentedType, ElementMatcher<? super MethodDescription> matcher, MethodGraph.Compiler methodGraphCompiler) {
1✔
827
                this.instrumentedType = instrumentedType;
1✔
828
                this.matcher = matcher;
1✔
829
                this.methodGraphCompiler = methodGraphCompiler;
1✔
830
            }
1✔
831

832
            /**
833
             * {@inheritDoc}
834
             */
835
            public MethodDescription resolve(TypeDescription targetType, MethodDescription instrumentedMethod) {
836
                TypeDescription.Generic superClass = instrumentedType.getSuperClass();
1✔
837
                List<MethodDescription> candidates = CompoundList.<MethodDescription>of(
1✔
838
                        superClass == null
839
                                ? Collections.<MethodDescription>emptyList()
1✔
840
                                : superClass.getDeclaredMethods().filter(isConstructor().and(matcher)),
1✔
841
                        instrumentedType.getDeclaredMethods().filter(not(ElementMatchers.isVirtual()).and(matcher)),
1✔
842
                        methodGraphCompiler.compile((TypeDefinition) targetType, instrumentedType).listNodes().asMethodList().filter(matcher));
1✔
843
                if (candidates.size() == 1) {
1✔
844
                    return candidates.get(0);
1✔
845
                } else {
846
                    throw new IllegalStateException(instrumentedType + " does not define exactly one virtual method or constructor for " + matcher
1✔
847
                            + " but contained " + candidates.size()
1✔
848
                            + " candidates: " + candidates);
849
                }
850
            }
851

852
            /**
853
             * A factory for a method locator that uses a matcher on the instrumented type's available methods for identifing a target method.
854
             */
855
            @HashCodeAndEqualsPlugin.Enhance
856
            public static class Factory implements MethodLocator.Factory {
857

858
                /**
859
                 * The matcher to use.
860
                 */
861
                private final ElementMatcher<? super MethodDescription> matcher;
862

863
                /**
864
                 * The method graph compiler to use.
865
                 */
866
                private final MethodGraph.Compiler methodGraphCompiler;
867

868
                /**
869
                 * Creates a factory for a method locator that identifies a method using a matcher.
870
                 *
871
                 * @param matcher             The matcher to use.
872
                 * @param methodGraphCompiler The method graph compiler to use.
873
                 */
874
                public Factory(ElementMatcher<? super MethodDescription> matcher, MethodGraph.Compiler methodGraphCompiler) {
1✔
875
                    this.matcher = matcher;
1✔
876
                    this.methodGraphCompiler = methodGraphCompiler;
1✔
877
                }
1✔
878

879
                /**
880
                 * {@inheritDoc}
881
                 */
882
                public MethodLocator make(TypeDescription instrumentedType) {
883
                    return new ForElementMatcher(instrumentedType, matcher, methodGraphCompiler);
1✔
884
                }
885
            }
886
        }
887
    }
888

889
    /**
890
     * An argument loader is responsible for loading an argument for an invoked method
891
     * onto the operand stack.
892
     */
893
    public interface ArgumentLoader {
894

895
        /**
896
         * Loads the argument that is represented by this instance onto the operand stack.
897
         *
898
         * @param target   The target parameter.
899
         * @param assigner The assigner to be used.
900
         * @param typing   Indicates if dynamic type castings should be attempted for incompatible assignments.
901
         * @return The stack manipulation that loads the represented argument onto the stack.
902
         */
903
        StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing);
904

905
        /**
906
         * An argument provider is responsible for providing an argument loader for each argument to supply to a method.
907
         */
908
        interface ArgumentProvider {
909

910
            /**
911
             * Resolves this provider to an argument loader for each provided argument.
912
             *
913
             * @param instrumentedMethod The instrumented method.
914
             * @param invokedMethod      The invoked method.
915
             * @return A list of provided argument loaders.
916
             */
917
            List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod);
918
        }
919

920
        /**
921
         * A factory that produces {@link ArgumentLoader}s for a given instrumented method.
922
         */
923
        interface Factory extends InstrumentedType.Prepareable {
924

925
            /**
926
             * Creates an argument provider for the supplied implementation target.
927
             *
928
             * @param implementationTarget The implementation target to use.
929
             * @return An appropriate argument provider.
930
             */
931
            ArgumentProvider make(Implementation.Target implementationTarget);
932
        }
933

934
        /**
935
         * An argument loader that loads the {@code null} value onto the operand stack.
936
         */
937
        enum ForNullConstant implements ArgumentLoader, ArgumentProvider, Factory {
1✔
938

939
            /**
940
             * The singleton instance.
941
             */
942
            INSTANCE;
1✔
943

944
            /**
945
             * {@inheritDoc}
946
             */
947
            public InstrumentedType prepare(InstrumentedType instrumentedType) {
948
                return instrumentedType;
1✔
949
            }
950

951
            /**
952
             * {@inheritDoc}
953
             */
954
            public ArgumentProvider make(Implementation.Target implementationTarget) {
955
                return this;
1✔
956
            }
957

958
            /**
959
             * {@inheritDoc}
960
             */
961
            public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
962
                return Collections.<ArgumentLoader>singletonList(this);
1✔
963
            }
964

965
            /**
966
             * {@inheritDoc}
967
             */
968
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
969
                if (target.getType().isPrimitive()) {
1✔
970
                    throw new IllegalStateException("Cannot assign null to " + target);
×
971
                }
972
                return NullConstant.INSTANCE;
1✔
973
            }
974
        }
975

976

977
        /**
978
         * An argument loader that assigns the {@code this} reference to a parameter.
979
         */
980
        @HashCodeAndEqualsPlugin.Enhance
981
        class ForThisReference implements ArgumentLoader, ArgumentProvider {
982

983
            /**
984
             * The instrumented type.
985
             */
986
            private final TypeDescription instrumentedType;
987

988
            /**
989
             * Creates an argument loader that supplies the {@code this} instance as an argument.
990
             *
991
             * @param instrumentedType The instrumented type.
992
             */
993
            public ForThisReference(TypeDescription instrumentedType) {
1✔
994
                this.instrumentedType = instrumentedType;
1✔
995
            }
1✔
996

997
            /**
998
             * {@inheritDoc}
999
             */
1000
            public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1001
                if (instrumentedMethod.isStatic()) {
1✔
1002
                    throw new IllegalStateException(instrumentedMethod + " is static and cannot supply an invoker instance");
×
1003
                }
1004
                return Collections.<ArgumentLoader>singletonList(this);
1✔
1005
            }
1006

1007
            /**
1008
             * {@inheritDoc}
1009
             */
1010
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
1011
                StackManipulation stackManipulation = new StackManipulation.Compound(
1✔
1012
                        MethodVariableAccess.loadThis(),
1✔
1013
                        assigner.assign(instrumentedType.asGenericType(), target.getType(), typing));
1✔
1014
                if (!stackManipulation.isValid()) {
1✔
1015
                    throw new IllegalStateException("Cannot assign " + instrumentedType + " to " + target);
×
1016
                }
1017
                return stackManipulation;
1✔
1018
            }
1019

1020
            /**
1021
             * A factory for an argument loader that supplies the {@code this} value as an argument.
1022
             */
1023
            public enum Factory implements ArgumentLoader.Factory {
1✔
1024

1025
                /**
1026
                 * The singleton instance.
1027
                 */
1028
                INSTANCE;
1✔
1029

1030
                /**
1031
                 * {@inheritDoc}
1032
                 */
1033
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1034
                    return instrumentedType;
1✔
1035
                }
1036

1037
                /**
1038
                 * {@inheritDoc}
1039
                 */
1040
                public ArgumentProvider make(Implementation.Target implementationTarget) {
1041
                    return new ForThisReference(implementationTarget.getInstrumentedType());
1✔
1042
                }
1043
            }
1044
        }
1045

1046
        /**
1047
         * Loads the instrumented type onto the operand stack.
1048
         */
1049
        @HashCodeAndEqualsPlugin.Enhance
1050
        class ForInstrumentedType implements ArgumentLoader, ArgumentProvider {
1051

1052
            /**
1053
             * The instrumented type.
1054
             */
1055
            private final TypeDescription instrumentedType;
1056

1057
            /**
1058
             * Creates an argument loader for supporting the instrumented type as a type constant as an argument.
1059
             *
1060
             * @param instrumentedType The instrumented type.
1061
             */
1062
            public ForInstrumentedType(TypeDescription instrumentedType) {
1✔
1063
                this.instrumentedType = instrumentedType;
1✔
1064
            }
1✔
1065

1066
            /**
1067
             * {@inheritDoc}
1068
             */
1069
            public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1070
                return Collections.<ArgumentLoader>singletonList(this);
1✔
1071
            }
1072

1073
            /**
1074
             * {@inheritDoc}
1075
             */
1076
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
1077
                StackManipulation stackManipulation = new StackManipulation.Compound(
1✔
1078
                        ClassConstant.of(instrumentedType),
1✔
1079
                        assigner.assign(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Class.class), target.getType(), typing));
1✔
1080
                if (!stackManipulation.isValid()) {
1✔
1081
                    throw new IllegalStateException("Cannot assign Class value to " + target);
×
1082
                }
1083
                return stackManipulation;
1✔
1084
            }
1085

1086
            /**
1087
             * A factory for an argument loader that supplies the instrumented type as an argument.
1088
             */
1089
            public enum Factory implements ArgumentLoader.Factory {
1✔
1090

1091
                /**
1092
                 * The singleton instance.
1093
                 */
1094
                INSTANCE;
1✔
1095

1096
                /**
1097
                 * {@inheritDoc}
1098
                 */
1099
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1100
                    return instrumentedType;
1✔
1101
                }
1102

1103
                /**
1104
                 * {@inheritDoc}
1105
                 */
1106
                public ArgumentProvider make(Implementation.Target implementationTarget) {
1107
                    return new ForInstrumentedType(implementationTarget.getInstrumentedType());
1✔
1108
                }
1109
            }
1110
        }
1111

1112
        /**
1113
         * Loads a parameter of the instrumented method onto the operand stack.
1114
         */
1115
        @HashCodeAndEqualsPlugin.Enhance
1116
        class ForMethodParameter implements ArgumentLoader {
1117

1118
            /**
1119
             * The index of the parameter to be loaded onto the operand stack.
1120
             */
1121
            private final int index;
1122

1123
            /**
1124
             * The instrumented method.
1125
             */
1126
            private final MethodDescription instrumentedMethod;
1127

1128
            /**
1129
             * Creates an argument loader for a parameter of the instrumented method.
1130
             *
1131
             * @param index              The index of the parameter to be loaded onto the operand stack.
1132
             * @param instrumentedMethod The instrumented method.
1133
             */
1134
            public ForMethodParameter(int index, MethodDescription instrumentedMethod) {
1✔
1135
                this.index = index;
1✔
1136
                this.instrumentedMethod = instrumentedMethod;
1✔
1137
            }
1✔
1138

1139
            /**
1140
             * {@inheritDoc}
1141
             */
1142
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
1143
                ParameterDescription parameterDescription = instrumentedMethod.getParameters().get(index);
1✔
1144
                StackManipulation stackManipulation = new StackManipulation.Compound(
1✔
1145
                        MethodVariableAccess.load(parameterDescription),
1✔
1146
                        assigner.assign(parameterDescription.getType(), target.getType(), typing));
1✔
1147
                if (!stackManipulation.isValid()) {
1✔
1148
                    throw new IllegalStateException("Cannot assign " + parameterDescription + " to " + target + " for " + instrumentedMethod);
1✔
1149
                }
1150
                return stackManipulation;
1✔
1151
            }
1152

1153
            /**
1154
             * A factory for argument loaders that supplies all arguments of the instrumented method as arguments.
1155
             */
1156
            protected enum OfInstrumentedMethod implements ArgumentLoader.Factory, ArgumentProvider {
1✔
1157

1158
                /**
1159
                 * The singleton instance.
1160
                 */
1161
                INSTANCE;
1✔
1162

1163
                /**
1164
                 * {@inheritDoc}
1165
                 */
1166
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1167
                    return instrumentedType;
1✔
1168
                }
1169

1170
                /**
1171
                 * {@inheritDoc}
1172
                 */
1173
                public ArgumentProvider make(Implementation.Target implementationTarget) {
1174
                    return this;
1✔
1175
                }
1176

1177
                /**
1178
                 * {@inheritDoc}
1179
                 */
1180
                public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1181
                    List<ArgumentLoader> argumentLoaders = new ArrayList<ArgumentLoader>(instrumentedMethod.getParameters().size());
1✔
1182
                    for (ParameterDescription parameterDescription : instrumentedMethod.getParameters()) {
1✔
1183
                        argumentLoaders.add(new ForMethodParameter(parameterDescription.getIndex(), instrumentedMethod));
1✔
1184
                    }
1✔
1185
                    return argumentLoaders;
1✔
1186
                }
1187
            }
1188

1189
            /**
1190
             * A factory for an argument loader that supplies a method parameter as an argument.
1191
             */
1192
            @HashCodeAndEqualsPlugin.Enhance
1193
            public static class Factory implements ArgumentLoader.Factory, ArgumentProvider {
1194

1195
                /**
1196
                 * The index of the parameter to be loaded onto the operand stack.
1197
                 */
1198
                private final int index;
1199

1200
                /**
1201
                 * Creates a factory for an argument loader that supplies a method parameter as an argument.
1202
                 *
1203
                 * @param index The index of the parameter to supply.
1204
                 */
1205
                public Factory(int index) {
1✔
1206
                    this.index = index;
1✔
1207
                }
1✔
1208

1209
                /**
1210
                 * {@inheritDoc}
1211
                 */
1212
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1213
                    return instrumentedType;
1✔
1214
                }
1215

1216
                /**
1217
                 * {@inheritDoc}
1218
                 */
1219
                public ArgumentProvider make(Implementation.Target implementationTarget) {
1220
                    return this;
1✔
1221
                }
1222

1223
                /**
1224
                 * {@inheritDoc}
1225
                 */
1226
                public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1227
                    if (index >= instrumentedMethod.getParameters().size()) {
1✔
1228
                        throw new IllegalStateException(instrumentedMethod + " does not have a parameter with index " + index +
1✔
1229
                                ", " + instrumentedMethod.getParameters().size() + " defined");
1✔
1230
                    }
1231
                    return Collections.<ArgumentLoader>singletonList(new ForMethodParameter(index, instrumentedMethod));
1✔
1232
                }
1233
            }
1234
        }
1235

1236
        /**
1237
         * Loads an array containing all arguments of a method.
1238
         */
1239
        @HashCodeAndEqualsPlugin.Enhance
1240
        class ForMethodParameterArray implements ArgumentLoader {
1241

1242
            /**
1243
             * The parameters to load.
1244
             */
1245
            private final ParameterList<?> parameters;
1246

1247
            /**
1248
             * Creates an argument loader that loads the supplied parameters onto the operand stack.
1249
             *
1250
             * @param parameters The parameters to load.
1251
             */
1252
            public ForMethodParameterArray(ParameterList<?> parameters) {
1✔
1253
                this.parameters = parameters;
1✔
1254
            }
1✔
1255

1256
            /**
1257
             * {@inheritDoc}
1258
             */
1259
            @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.")
1260
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
1261
                TypeDescription.Generic componentType;
1262
                if (target.getType().represents(Object.class)) {
1✔
1263
                    componentType = TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class);
×
1264
                } else if (target.getType().isArray()) {
1✔
1265
                    componentType = target.getType().getComponentType();
1✔
1266
                } else {
1267
                    throw new IllegalStateException("Cannot set method parameter array for non-array type: " + target);
×
1268
                }
1269
                List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(parameters.size());
1✔
1270
                for (ParameterDescription parameter : parameters) {
1✔
1271
                    StackManipulation stackManipulation = new StackManipulation.Compound(
1✔
1272
                            MethodVariableAccess.load(parameter),
1✔
1273
                            assigner.assign(parameter.getType(), componentType, typing)
1✔
1274
                    );
1275
                    if (stackManipulation.isValid()) {
1✔
1276
                        stackManipulations.add(stackManipulation);
1✔
1277
                    } else {
1278
                        throw new IllegalStateException("Cannot assign " + parameter + " to " + componentType);
×
1279
                    }
1280
                }
1✔
1281
                return new StackManipulation.Compound(ArrayFactory.forType(componentType).withValues(stackManipulations));
1✔
1282
            }
1283

1284
            /**
1285
             * A factory that creates an arguments loader that loads all parameters of the instrumented method contained in an array.
1286
             */
1287
            public enum ForInstrumentedMethod implements Factory, ArgumentProvider {
1✔
1288

1289
                /**
1290
                 * The singleton instance.
1291
                 */
1292
                INSTANCE;
1✔
1293

1294
                /**
1295
                 * {@inheritDoc}
1296
                 */
1297
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1298
                    return instrumentedType;
1✔
1299
                }
1300

1301
                /**
1302
                 * {@inheritDoc}
1303
                 */
1304
                public ArgumentProvider make(Implementation.Target implementationTarget) {
1305
                    return this;
1✔
1306
                }
1307

1308
                /**
1309
                 * {@inheritDoc}
1310
                 */
1311
                public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1312
                    return Collections.<ArgumentLoader>singletonList(new ForMethodParameterArray(instrumentedMethod.getParameters()));
1✔
1313
                }
1314
            }
1315
        }
1316

1317
        /**
1318
         * An argument loader that loads an element of a parameter of an array type.
1319
         */
1320
        @HashCodeAndEqualsPlugin.Enhance
1321
        class ForMethodParameterArrayElement implements ArgumentLoader {
1322

1323
            /**
1324
             * The parameter to load the array from.
1325
             */
1326
            private final ParameterDescription parameterDescription;
1327

1328
            /**
1329
             * The array index to load.
1330
             */
1331
            private final int index;
1332

1333
            /**
1334
             * Creates an argument loader for a parameter of the instrumented method where an array element is assigned to the invoked method.
1335
             *
1336
             * @param parameterDescription The parameter from which to load an array element.
1337
             * @param index                The array index to load.
1338
             */
1339
            public ForMethodParameterArrayElement(ParameterDescription parameterDescription, int index) {
1✔
1340
                this.parameterDescription = parameterDescription;
1✔
1341
                this.index = index;
1✔
1342
            }
1✔
1343

1344
            /**
1345
             * {@inheritDoc}
1346
             */
1347
            @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.")
1348
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
1349
                StackManipulation stackManipulation = new StackManipulation.Compound(
1✔
1350
                        MethodVariableAccess.load(parameterDescription),
1✔
1351
                        IntegerConstant.forValue(index),
1✔
1352
                        ArrayAccess.of(parameterDescription.getType().getComponentType()).load(),
1✔
1353
                        assigner.assign(parameterDescription.getType().getComponentType(), target.getType(), typing)
1✔
1354
                );
1355
                if (!stackManipulation.isValid()) {
1✔
1356
                    throw new IllegalStateException("Cannot assign " + parameterDescription.getType().getComponentType() + " to " + target);
×
1357
                }
1358
                return stackManipulation;
1✔
1359
            }
1360

1361
            /**
1362
             * Creates an argument loader for an array element that of a specific parameter.
1363
             */
1364
            @HashCodeAndEqualsPlugin.Enhance
1365
            public static class OfParameter implements ArgumentLoader.Factory, ArgumentProvider {
1366

1367
                /**
1368
                 * The parameter index.
1369
                 */
1370
                private final int index;
1371

1372
                /**
1373
                 * The array index to load.
1374
                 */
1375
                private final int arrayIndex;
1376

1377
                /**
1378
                 * Creates a factory for an argument loader that loads a given parameter's array value.
1379
                 *
1380
                 * @param index      The index of the parameter.
1381
                 * @param arrayIndex The array index to load.
1382
                 */
1383
                public OfParameter(int index, int arrayIndex) {
1✔
1384
                    this.index = index;
1✔
1385
                    this.arrayIndex = arrayIndex;
1✔
1386
                }
1✔
1387

1388
                /**
1389
                 * {@inheritDoc}
1390
                 */
1391
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1392
                    return instrumentedType;
1✔
1393
                }
1394

1395
                /**
1396
                 * {@inheritDoc}
1397
                 */
1398
                public ArgumentProvider make(Implementation.Target implementationTarget) {
1399
                    return this;
1✔
1400
                }
1401

1402
                /**
1403
                 * {@inheritDoc}
1404
                 */
1405
                public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1406
                    if (instrumentedMethod.getParameters().size() <= index) {
1✔
1407
                        throw new IllegalStateException(instrumentedMethod + " does not declare a parameter with index " + index +
1✔
1408
                                ", " + instrumentedMethod.getParameters().size() + " defined");
1✔
1409
                    } else if (!instrumentedMethod.getParameters().get(index).getType().isArray()) {
1✔
1410
                        throw new IllegalStateException("Cannot access an item from non-array parameter " + instrumentedMethod.getParameters().get(index) +
1✔
1411
                                " at index " + index);
1412
                    }
1413
                    return Collections.<ArgumentLoader>singletonList(new ForMethodParameterArrayElement(instrumentedMethod.getParameters().get(index), arrayIndex));
1✔
1414
                }
1415
            }
1416

1417
            /**
1418
             * An argument loader factory that loads an array element from a parameter for each argument of the invoked method.
1419
             */
1420
            @HashCodeAndEqualsPlugin.Enhance
1421
            public static class OfInvokedMethod implements ArgumentLoader.Factory, ArgumentProvider {
1422

1423
                /**
1424
                 * The parameter index.
1425
                 */
1426
                private final int index;
1427

1428
                /**
1429
                 * Creates an argument loader factory for an invoked method.
1430
                 *
1431
                 * @param index The parameter index.
1432
                 */
1433
                public OfInvokedMethod(int index) {
1✔
1434
                    this.index = index;
1✔
1435
                }
1✔
1436

1437
                /**
1438
                 * {@inheritDoc}
1439
                 */
1440
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1441
                    return instrumentedType;
1✔
1442
                }
1443

1444
                /**
1445
                 * {@inheritDoc}
1446
                 */
1447
                public ArgumentProvider make(Implementation.Target implementationTarget) {
1448
                    return this;
1✔
1449
                }
1450

1451
                /**
1452
                 * {@inheritDoc}
1453
                 */
1454
                public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1455
                    if (instrumentedMethod.getParameters().size() <= index) {
1✔
1456
                        throw new IllegalStateException(instrumentedMethod + " does not declare a parameter with index " + index +
1✔
1457
                                ", " + instrumentedMethod.getParameters().size() + " defined");
1✔
1458
                    } else if (!instrumentedMethod.getParameters().get(index).getType().isArray()) {
1✔
1459
                        throw new IllegalStateException("Cannot access an item from non-array parameter " + instrumentedMethod.getParameters().get(index) +
1✔
1460
                                " at index " + index);
1461
                    }
1462
                    List<ArgumentLoader> argumentLoaders = new ArrayList<ArgumentLoader>(invokedMethod.getParameters().size());
1✔
1463
                    for (int index = 0; index < invokedMethod.getParameters().size(); index++) {
1✔
1464
                        argumentLoaders.add(new ForMethodParameterArrayElement(instrumentedMethod.getParameters().get(this.index), index));
1✔
1465
                    }
1466
                    return argumentLoaders;
1✔
1467
                }
1468
            }
1469
        }
1470

1471
        /**
1472
         * Loads a value onto the operand stack that is stored in a static field.
1473
         */
1474
        @HashCodeAndEqualsPlugin.Enhance
1475
        class ForInstance implements ArgumentLoader, ArgumentProvider {
1476

1477
            /**
1478
             * The description of the field.
1479
             */
1480
            private final FieldDescription fieldDescription;
1481

1482
            /**
1483
             * Creates an argument loader that supplies the value of a static field as an argument.
1484
             *
1485
             * @param fieldDescription The description of the field.
1486
             */
1487
            public ForInstance(FieldDescription fieldDescription) {
1✔
1488
                this.fieldDescription = fieldDescription;
1✔
1489
            }
1✔
1490

1491
            /**
1492
             * {@inheritDoc}
1493
             */
1494
            public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1495
                return Collections.<ArgumentLoader>singletonList(this);
1✔
1496
            }
1497

1498
            /**
1499
             * {@inheritDoc}
1500
             */
1501
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
1502
                StackManipulation stackManipulation = new StackManipulation.Compound(
1✔
1503
                        FieldAccess.forField(fieldDescription).read(),
1✔
1504
                        assigner.assign(fieldDescription.getType(), target.getType(), typing));
1✔
1505
                if (!stackManipulation.isValid()) {
1✔
1506
                    throw new IllegalStateException("Cannot assign " + fieldDescription.getType() + " to " + target);
1✔
1507
                }
1508
                return stackManipulation;
1✔
1509
            }
1510

1511
            /**
1512
             * A factory that supplies the value of a static field as an argument.
1513
             */
1514
            @HashCodeAndEqualsPlugin.Enhance
1515
            protected static class Factory implements ArgumentLoader.Factory {
1516

1517
                /**
1518
                 * The name prefix of the field to store the argument.
1519
                 */
1520
                private static final String FIELD_PREFIX = "methodCall";
1521

1522
                /**
1523
                 * The value to be stored in the field.
1524
                 */
1525
                private final Object value;
1526

1527
                /**
1528
                 * The name of the field.
1529
                 */
1530
                @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.IGNORE)
1531
                private final String name;
1532

1533
                /**
1534
                 * Creates a factory that loads the value of a static field as an argument.
1535
                 *
1536
                 * @param value The value to supply as an argument.
1537
                 */
1538
                public Factory(Object value) {
1✔
1539
                    this.value = value;
1✔
1540
                    name = FIELD_PREFIX + "$" + RandomString.hashOf(value);
1✔
1541
                }
1✔
1542

1543
                /**
1544
                 * {@inheritDoc}
1545
                 */
1546
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1547
                    return instrumentedType.withAuxiliaryField(new FieldDescription.Token(name,
1✔
1548
                            Opcodes.ACC_SYNTHETIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
1549
                            TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(value.getClass())), value);
1✔
1550
                }
1551

1552
                /**
1553
                 * {@inheritDoc}
1554
                 */
1555
                public ArgumentProvider make(Implementation.Target implementationTarget) {
1556
                    return new ForInstance(implementationTarget.getInstrumentedType().getDeclaredFields().filter(named(name)).getOnly());
1✔
1557
                }
1558
            }
1559
        }
1560

1561
        /**
1562
         * Loads the value of an existing field onto the operand stack.
1563
         */
1564
        @HashCodeAndEqualsPlugin.Enhance
1565
        class ForField implements ArgumentLoader {
1566

1567
            /**
1568
             * The field containing the loaded value.
1569
             */
1570
            private final FieldDescription fieldDescription;
1571

1572
            /**
1573
             * The instrumented method.
1574
             */
1575
            private final MethodDescription instrumentedMethod;
1576

1577
            /**
1578
             * Creates a new argument loader for loading an existing field.
1579
             *
1580
             * @param fieldDescription   The field containing the loaded value.
1581
             * @param instrumentedMethod The instrumented method.
1582
             */
1583
            public ForField(FieldDescription fieldDescription, MethodDescription instrumentedMethod) {
1✔
1584
                this.fieldDescription = fieldDescription;
1✔
1585
                this.instrumentedMethod = instrumentedMethod;
1✔
1586
            }
1✔
1587

1588
            /**
1589
             * {@inheritDoc}
1590
             */
1591
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
1592
                if (!fieldDescription.isStatic() && instrumentedMethod.isStatic()) {
1✔
1593
                    throw new IllegalStateException("Cannot access non-static " + fieldDescription + " from " + instrumentedMethod);
×
1594
                }
1595
                StackManipulation stackManipulation = new StackManipulation.Compound(
1✔
1596
                        fieldDescription.isStatic()
1✔
1597
                                ? StackManipulation.Trivial.INSTANCE
1598
                                : MethodVariableAccess.loadThis(),
1✔
1599
                        FieldAccess.forField(fieldDescription).read(),
1✔
1600
                        assigner.assign(fieldDescription.getType(), target.getType(), typing)
1✔
1601
                );
1602
                if (!stackManipulation.isValid()) {
1✔
1603
                    throw new IllegalStateException("Cannot assign " + fieldDescription + " to " + target);
1✔
1604
                }
1605
                return stackManipulation;
1✔
1606
            }
1607

1608
            /**
1609
             * An argument provider for a field access.
1610
             */
1611
            @HashCodeAndEqualsPlugin.Enhance
1612
            protected static class ArgumentProvider implements ArgumentLoader.ArgumentProvider {
1613

1614
                /**
1615
                 * The field being accessed.
1616
                 */
1617
                private final FieldDescription fieldDescription;
1618

1619
                /**
1620
                 * Creates a new argument provider for a field access.
1621
                 *
1622
                 * @param fieldDescription The field being accessed.
1623
                 */
1624
                protected ArgumentProvider(FieldDescription fieldDescription) {
1✔
1625
                    this.fieldDescription = fieldDescription;
1✔
1626
                }
1✔
1627

1628
                /**
1629
                 * {@inheritDoc}
1630
                 */
1631
                public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1632
                    return Collections.<ArgumentLoader>singletonList(new ForField(fieldDescription, instrumentedMethod));
1✔
1633
                }
1634
            }
1635

1636
            /**
1637
             * A factory for an argument loaded that loads the value of an existing field as an argument.
1638
             */
1639
            @HashCodeAndEqualsPlugin.Enhance
1640
            protected static class Factory implements ArgumentLoader.Factory {
1641

1642
                /**
1643
                 * The name of the field.
1644
                 */
1645
                private final String name;
1646

1647
                /**
1648
                 * The field locator to use.
1649
                 */
1650
                private final FieldLocator.Factory fieldLocatorFactory;
1651

1652
                /**
1653
                 * Creates a new argument loader for an existing field.
1654
                 *
1655
                 * @param name                The name of the field.
1656
                 * @param fieldLocatorFactory The field locator to use.
1657
                 */
1658
                public Factory(String name, FieldLocator.Factory fieldLocatorFactory) {
1✔
1659
                    this.name = name;
1✔
1660
                    this.fieldLocatorFactory = fieldLocatorFactory;
1✔
1661
                }
1✔
1662

1663
                /**
1664
                 * {@inheritDoc}
1665
                 */
1666
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1667
                    return instrumentedType;
1✔
1668
                }
1669

1670
                /**
1671
                 * {@inheritDoc}
1672
                 */
1673
                public ArgumentLoader.ArgumentProvider make(Implementation.Target implementationTarget) {
1674
                    FieldLocator.Resolution resolution = fieldLocatorFactory.make(implementationTarget.getInstrumentedType()).locate(name);
1✔
1675
                    if (!resolution.isResolved()) {
1✔
1676
                        throw new IllegalStateException("Could not locate field '" + name + "' on " + implementationTarget.getInstrumentedType());
1✔
1677
                    }
1678
                    return new ArgumentProvider(resolution.getField());
1✔
1679
                }
1680
            }
1681
        }
1682

1683
        /**
1684
         * Loads the return value of a method call onto the operand stack.
1685
         */
1686
        @HashCodeAndEqualsPlugin.Enhance
1687
        class ForMethodCall implements ArgumentLoader {
1688

1689
            /**
1690
             * The method call's appender.
1691
             */
1692
            private final Appender appender;
1693

1694
            /**
1695
             * The invoked method.
1696
             */
1697
            private final MethodDescription methodDescription;
1698

1699
            /**
1700
             * The instrumented method.
1701
             */
1702
            private final MethodDescription instrumentedMethod;
1703

1704
            /**
1705
             * The resolved target handler to use.
1706
             */
1707
            private final TargetHandler.Resolved targetHandler;
1708

1709
            /**
1710
             * Creates a new argument loader for loading a method call's return value.
1711
             *
1712
             * @param appender           The method call's appender.
1713
             * @param methodDescription  The invoked method.
1714
             * @param instrumentedMethod The instrumented method.
1715
             * @param targetHandler      The resolved target handler to use.
1716
             */
1717
            public ForMethodCall(Appender appender, MethodDescription methodDescription, MethodDescription instrumentedMethod, TargetHandler.Resolved targetHandler) {
1✔
1718
                this.appender = appender;
1✔
1719
                this.methodDescription = methodDescription;
1✔
1720
                this.instrumentedMethod = instrumentedMethod;
1✔
1721
                this.targetHandler = targetHandler;
1✔
1722
            }
1✔
1723

1724
            /**
1725
             * {@inheritDoc}
1726
             */
1727
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
1728
                StackManipulation stackManipulation = new StackManipulation.Compound(
1✔
1729
                        appender.toStackManipulation(instrumentedMethod, methodDescription, targetHandler),
1✔
1730
                        assigner.assign(methodDescription.isConstructor()
1✔
1731
                                ? methodDescription.getDeclaringType().asGenericType()
1✔
1732
                                : methodDescription.getReturnType(), target.getType(), typing)
1✔
1733
                );
1734
                if (!stackManipulation.isValid()) {
1✔
1735
                    throw new IllegalStateException("Cannot assign return type of " + methodDescription + " to " + target);
1✔
1736
                }
1737
                return stackManipulation;
1✔
1738
            }
1739

1740
            /**
1741
             * An argument provider for a method call.
1742
             */
1743
            @HashCodeAndEqualsPlugin.Enhance
1744
            protected static class ArgumentProvider implements ArgumentLoader.ArgumentProvider {
1745

1746
                /**
1747
                 * The method call's appender.
1748
                 */
1749
                private final Appender appender;
1750

1751
                /**
1752
                 * Creates a new argument provider for a method call.
1753
                 *
1754
                 * @param appender The method call's appender.
1755
                 */
1756
                protected ArgumentProvider(Appender appender) {
1✔
1757
                    this.appender = appender;
1✔
1758
                }
1✔
1759

1760
                /**
1761
                 * {@inheritDoc}
1762
                 */
1763
                public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1764
                    TargetHandler.Resolved targetHandler = appender.targetHandler.resolve(instrumentedMethod);
1✔
1765
                    return Collections.<ArgumentLoader>singletonList(new ForMethodCall(appender,
1✔
1766
                            appender.toInvokedMethod(instrumentedMethod, targetHandler),
1✔
1767
                            instrumentedMethod,
1768
                            targetHandler));
1769
                }
1770
            }
1771

1772
            /**
1773
             * A factory for an argument loaded that loads the return value of a method call as an argument.
1774
             */
1775
            @HashCodeAndEqualsPlugin.Enhance
1776
            protected static class Factory implements ArgumentLoader.Factory {
1777

1778
                /**
1779
                 * The method call to use.
1780
                 */
1781
                private final MethodCall methodCall;
1782

1783
                /**
1784
                 * Creates a new argument loader for an existing method call.
1785
                 *
1786
                 * @param methodCall The method call to use.
1787
                 */
1788
                public Factory(MethodCall methodCall) {
1✔
1789
                    this.methodCall = methodCall;
1✔
1790
                }
1✔
1791

1792
                /**
1793
                 * {@inheritDoc}
1794
                 */
1795
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
1796
                    return methodCall.prepare(instrumentedType);
1✔
1797
                }
1798

1799
                /**
1800
                 * {@inheritDoc}
1801
                 */
1802
                public ArgumentLoader.ArgumentProvider make(Implementation.Target implementationTarget) {
1803
                    return new ArgumentProvider(methodCall.new Appender(implementationTarget, TerminationHandler.Simple.IGNORING));
1✔
1804
                }
1805
            }
1806
        }
1807

1808
        /**
1809
         * Loads a stack manipulation resulting in a specific type as an argument.
1810
         */
1811
        @HashCodeAndEqualsPlugin.Enhance
1812
        class ForStackManipulation implements ArgumentLoader, ArgumentProvider, Factory {
1813

1814
            /**
1815
             * The stack manipulation to load.
1816
             */
1817
            private final StackManipulation stackManipulation;
1818

1819
            /**
1820
             * The type of the resulting value.
1821
             */
1822
            private final TypeDefinition typeDefinition;
1823

1824
            /**
1825
             * Creates an argument loader that loads a stack manipulation as an argument.
1826
             *
1827
             * @param stackManipulation The stack manipulation to load.
1828
             * @param type              The type of the resulting value.
1829
             */
1830
            public ForStackManipulation(StackManipulation stackManipulation, Type type) {
1831
                this(stackManipulation, TypeDescription.Generic.Sort.describe(type));
1✔
1832
            }
1✔
1833

1834
            /**
1835
             * Creates an argument loader that loads a stack manipulation as an argument.
1836
             *
1837
             * @param stackManipulation The stack manipulation to load.
1838
             * @param typeDefinition    The type of the resulting value.
1839
             */
1840
            public ForStackManipulation(StackManipulation stackManipulation, TypeDefinition typeDefinition) {
1✔
1841
                this.stackManipulation = stackManipulation;
1✔
1842
                this.typeDefinition = typeDefinition;
1✔
1843
            }
1✔
1844

1845
            /**
1846
             * Creates an argument loader that loads the supplied value as a constant. If the value cannot be represented
1847
             * in the constant pool, a field is created to store the value.
1848
             *
1849
             * @param value The value to load as an argument or {@code null}.
1850
             * @return An appropriate argument loader.
1851
             */
1852
            public static ArgumentLoader.Factory of(@MaybeNull Object value) {
1853
                if (value == null) {
1✔
1854
                    return ForNullConstant.INSTANCE;
1✔
1855
                } else {
1856
                    ConstantValue constant = ConstantValue.Simple.wrapOrNull(value);
1✔
1857
                    return constant == null
1✔
1858
                            ? new ForInstance.Factory(value)
1859
                            : new ForStackManipulation(constant.toStackManipulation(), constant.getTypeDescription());
1✔
1860
                }
1861
            }
1862

1863
            /**
1864
             * {@inheritDoc}
1865
             */
1866
            public InstrumentedType prepare(InstrumentedType instrumentedType) {
1867
                return instrumentedType;
1✔
1868
            }
1869

1870
            /**
1871
             * {@inheritDoc}
1872
             */
1873
            public ArgumentProvider make(Implementation.Target implementationTarget) {
1874
                return this;
1✔
1875
            }
1876

1877
            /**
1878
             * {@inheritDoc}
1879
             */
1880
            public List<ArgumentLoader> resolve(MethodDescription instrumentedMethod, MethodDescription invokedMethod) {
1881
                return Collections.<ArgumentLoader>singletonList(this);
1✔
1882
            }
1883

1884
            /**
1885
             * {@inheritDoc}
1886
             */
1887
            public StackManipulation toStackManipulation(ParameterDescription target, Assigner assigner, Assigner.Typing typing) {
1888
                StackManipulation assignment = assigner.assign(typeDefinition.asGenericType(), target.getType(), typing);
1✔
1889
                if (!assignment.isValid()) {
1✔
1890
                    throw new IllegalStateException("Cannot assign " + target + " to " + typeDefinition);
1✔
1891
                }
1892
                return new StackManipulation.Compound(stackManipulation, assignment);
1✔
1893
            }
1894
        }
1895
    }
1896

1897
    /**
1898
     * A target handler is responsible for invoking a method for a
1899
     * {@link net.bytebuddy.implementation.MethodCall}.
1900
     */
1901
    protected interface TargetHandler {
1902

1903
        /**
1904
         * Resolves this target handler.
1905
         *
1906
         * @param instrumentedMethod The instrumented method.
1907
         * @return The resolved target handler.
1908
         */
1909
        Resolved resolve(MethodDescription instrumentedMethod);
1910

1911
        /**
1912
         * A resolved target handler.
1913
         */
1914
        interface Resolved {
1915

1916
            /**
1917
             * Returns the target's type description.
1918
             *
1919
             * @return The target's type description.
1920
             */
1921
            TypeDescription getTypeDescription();
1922

1923
            /**
1924
             * Creates a stack manipulation to represent this resolved target handler.
1925
             *
1926
             * @param invokedMethod The invoked method.
1927
             * @param assigner      The assigner to use.
1928
             * @param typing        The typing to apply.
1929
             * @return A stack manipulation that implements this target handler.
1930
             */
1931
            StackManipulation toStackManipulation(MethodDescription invokedMethod, Assigner assigner, Assigner.Typing typing);
1932
        }
1933

1934
        /**
1935
         * A factory for creating a target handler.
1936
         */
1937
        interface Factory extends InstrumentedType.Prepareable {
1938

1939
            /**
1940
             * Creates a target handler for a given implementation target.
1941
             *
1942
             * @param implementationTarget The implementation target to use.
1943
             * @return The target handler to use.
1944
             */
1945
            TargetHandler make(Implementation.Target implementationTarget);
1946
        }
1947

1948
        /**
1949
         * A simple target handler that applies a given stack manipulation.
1950
         */
1951
        @HashCodeAndEqualsPlugin.Enhance
1952
        class Simple implements TargetHandler, Factory, Resolved {
1953

1954
            /**
1955
             * The type resolved by the stack manipulation.
1956
             */
1957
            private final TypeDescription typeDescription;
1958

1959
            /**
1960
             * The stack manipulation that loads a target for the method call.
1961
             */
1962
            private final StackManipulation stackManipulation;
1963

1964
            /**
1965
             * Creates a simple target handler.
1966
             *
1967
             * @param typeDescription   The type resolved by the stack manipulation.
1968
             * @param stackManipulation The stack manipulation that loads a target for the method call.
1969
             */
1970
            protected Simple(TypeDescription typeDescription, StackManipulation stackManipulation) {
1✔
1971
                this.typeDescription = typeDescription;
1✔
1972
                this.stackManipulation = stackManipulation;
1✔
1973
            }
1✔
1974

1975
            /**
1976
             * {@inheritDoc}
1977
             */
1978
            public TargetHandler make(Target implementationTarget) {
1979
                return this;
1✔
1980
            }
1981

1982
            /**
1983
             * {@inheritDoc}
1984
             */
1985
            public InstrumentedType prepare(InstrumentedType instrumentedType) {
1986
                return instrumentedType;
1✔
1987
            }
1988

1989
            /**
1990
             * {@inheritDoc}
1991
             */
1992
            public Resolved resolve(MethodDescription instrumentedMethod) {
1993
                return this;
1✔
1994
            }
1995

1996
            /**
1997
             * {@inheritDoc}
1998
             */
1999
            public TypeDescription getTypeDescription() {
2000
                return typeDescription;
1✔
2001
            }
2002

2003
            /**
2004
             * {@inheritDoc}
2005
             */
2006
            public StackManipulation toStackManipulation(MethodDescription invokedMethod, Assigner assigner, Assigner.Typing typing) {
2007
                return stackManipulation;
1✔
2008
            }
2009
        }
2010

2011
        /**
2012
         * A target handler that invokes a method either on the instance of the instrumented
2013
         * type or as a static method.
2014
         */
2015
        @HashCodeAndEqualsPlugin.Enhance
2016
        class ForSelfOrStaticInvocation implements TargetHandler {
2017

2018
            /**
2019
             * The instrumented type.
2020
             */
2021
            private final TypeDescription instrumentedType;
2022

2023
            /**
2024
             * Creates a new target handler for a static or self-declared invocation.
2025
             *
2026
             * @param instrumentedType The instrumented type.
2027
             */
2028
            protected ForSelfOrStaticInvocation(TypeDescription instrumentedType) {
1✔
2029
                this.instrumentedType = instrumentedType;
1✔
2030
            }
1✔
2031

2032
            /**
2033
             * {@inheritDoc}
2034
             */
2035
            public TargetHandler.Resolved resolve(MethodDescription instrumentedMethod) {
2036
                return new Resolved(instrumentedType, instrumentedMethod);
1✔
2037
            }
2038

2039

2040
            /**
2041
             * A resolved target handler for a static or self-declared invocation.
2042
             */
2043
            @HashCodeAndEqualsPlugin.Enhance
2044
            protected static class Resolved implements TargetHandler.Resolved {
2045

2046
                /**
2047
                 * The instrumented type.
2048
                 */
2049
                private final TypeDescription instrumentedType;
2050

2051
                /**
2052
                 * The instrumented method.
2053
                 */
2054
                private final MethodDescription instrumentedMethod;
2055

2056
                /**
2057
                 * Creates a resolved target handler for a static or self-declared invocation.
2058
                 *
2059
                 * @param instrumentedType   The instrumented type.
2060
                 * @param instrumentedMethod The instrumented method.
2061
                 */
2062
                protected Resolved(TypeDescription instrumentedType,
2063
                                   MethodDescription instrumentedMethod) {
1✔
2064
                    this.instrumentedType = instrumentedType;
1✔
2065
                    this.instrumentedMethod = instrumentedMethod;
1✔
2066
                }
1✔
2067

2068
                /**
2069
                 * {@inheritDoc}
2070
                 */
2071
                public TypeDescription getTypeDescription() {
2072
                    return instrumentedType;
1✔
2073
                }
2074

2075
                /**
2076
                 * {@inheritDoc}
2077
                 */
2078
                @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
2079
                public StackManipulation toStackManipulation(MethodDescription invokedMethod, Assigner assigner, Assigner.Typing typing) {
2080
                    if (instrumentedMethod.isStatic() && !invokedMethod.isStatic() && !invokedMethod.isConstructor()) {
1✔
2081
                        throw new IllegalStateException("Cannot invoke " + invokedMethod + " from " + instrumentedMethod);
1✔
2082
                    } else if (invokedMethod.isConstructor() && (!instrumentedMethod.isConstructor()
1✔
2083
                            || !instrumentedType.equals(invokedMethod.getDeclaringType().asErasure())
1✔
2084
                            && (instrumentedType.getSuperClass() == null
1✔
2085
                            || !instrumentedType.getSuperClass().asErasure().equals(invokedMethod.getDeclaringType().asErasure())))) {
1✔
2086
                        throw new IllegalStateException("Cannot invoke " + invokedMethod + " from " + instrumentedMethod + " in " + instrumentedType);
1✔
2087
                    }
2088
                    return new StackManipulation.Compound(
1✔
2089
                            invokedMethod.isStatic()
1✔
2090
                                    ? StackManipulation.Trivial.INSTANCE
2091
                                    : MethodVariableAccess.loadThis(),
1✔
2092
                            invokedMethod.isConstructor()
1✔
2093
                                    ? Duplication.SINGLE
2094
                                    : StackManipulation.Trivial.INSTANCE
2095
                    );
2096
                }
2097
            }
2098

2099
            /**
2100
             * A factory for invoking a static method or a self-declared method.
2101
             */
2102
            protected enum Factory implements TargetHandler.Factory {
1✔
2103

2104
                /**
2105
                 * The singleton instance.
2106
                 */
2107
                INSTANCE;
1✔
2108

2109
                /**
2110
                 * {@inheritDoc}
2111
                 */
2112
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
2113
                    return instrumentedType;
1✔
2114
                }
2115

2116
                /**
2117
                 * {@inheritDoc}
2118
                 */
2119
                public TargetHandler make(Implementation.Target implementationTarget) {
2120
                    return new ForSelfOrStaticInvocation(implementationTarget.getInstrumentedType());
1✔
2121
                }
2122
            }
2123
        }
2124

2125
        /**
2126
         * Invokes a method in order to construct a new instance.
2127
         */
2128
        @HashCodeAndEqualsPlugin.Enhance
2129
        class ForConstructingInvocation implements TargetHandler, Resolved {
2130

2131
            /**
2132
             * The instrumented type.
2133
             */
2134
            private final TypeDescription instrumentedType;
2135

2136
            /**
2137
             * Creates a new target handle constructor invocation.
2138
             *
2139
             * @param instrumentedType The instrumented type.
2140
             */
2141
            protected ForConstructingInvocation(TypeDescription instrumentedType) {
1✔
2142
                this.instrumentedType = instrumentedType;
1✔
2143
            }
1✔
2144

2145
            /**
2146
             * {@inheritDoc}
2147
             */
2148
            public Resolved resolve(MethodDescription instrumentedMethod) {
2149
                return this;
1✔
2150
            }
2151

2152
            /**
2153
             * {@inheritDoc}
2154
             */
2155
            public TypeDescription getTypeDescription() {
2156
                return instrumentedType;
1✔
2157
            }
2158

2159
            /**
2160
             * {@inheritDoc}
2161
             */
2162
            public StackManipulation toStackManipulation(MethodDescription invokedMethod, Assigner assigner, Assigner.Typing typing) {
2163
                return new StackManipulation.Compound(TypeCreation.of(invokedMethod.getDeclaringType().asErasure()), Duplication.SINGLE);
1✔
2164
            }
2165

2166
            /**
2167
             * A target handler factory for a constructor invocation.
2168
             */
2169
            enum Factory implements TargetHandler.Factory {
1✔
2170

2171
                /**
2172
                 * The singleton instance.
2173
                 */
2174
                INSTANCE;
1✔
2175

2176
                /**
2177
                 * {@inheritDoc}
2178
                 */
2179
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
2180
                    return instrumentedType;
1✔
2181
                }
2182

2183
                /**
2184
                 * {@inheritDoc}
2185
                 */
2186
                public TargetHandler make(Implementation.Target implementationTarget) {
2187
                    return new ForConstructingInvocation(implementationTarget.getInstrumentedType());
1✔
2188
                }
2189
            }
2190
        }
2191

2192
        /**
2193
         * A target handler that invokes a method on an instance that is stored in a static field.
2194
         */
2195
        @HashCodeAndEqualsPlugin.Enhance
2196
        class ForValue implements TargetHandler, Resolved {
2197

2198
            /**
2199
             * A description of the field that contains the value.
2200
             */
2201
            private final FieldDescription.InDefinedShape fieldDescription;
2202

2203
            /**
2204
             * Creates a new target handler for a field value.
2205
             *
2206
             * @param fieldDescription A description of the field that contains the value.
2207
             */
2208
            protected ForValue(FieldDescription.InDefinedShape fieldDescription) {
1✔
2209
                this.fieldDescription = fieldDescription;
1✔
2210
            }
1✔
2211

2212
            /**
2213
             * {@inheritDoc}
2214
             */
2215
            public Resolved resolve(MethodDescription instrumentedMethod) {
2216
                return this;
1✔
2217
            }
2218

2219
            /**
2220
             * {@inheritDoc}
2221
             */
2222
            public TypeDescription getTypeDescription() {
2223
                return fieldDescription.getType().asErasure();
1✔
2224
            }
2225

2226
            /**
2227
             * {@inheritDoc}
2228
             */
2229
            public StackManipulation toStackManipulation(MethodDescription invokedMethod, Assigner assigner, Assigner.Typing typing) {
2230
                StackManipulation stackManipulation = assigner.assign(fieldDescription.getType(), invokedMethod.getDeclaringType().asGenericType(), typing);
1✔
2231
                if (!stackManipulation.isValid()) {
1✔
2232
                    throw new IllegalStateException("Cannot invoke " + invokedMethod + " on " + fieldDescription);
1✔
2233
                }
2234
                return new StackManipulation.Compound(
1✔
2235
                        FieldAccess.forField(fieldDescription).read(),
1✔
2236
                        stackManipulation
2237
                );
2238
            }
2239

2240
            /**
2241
             * A factory for a target handler that loads a specific value.
2242
             */
2243
            @HashCodeAndEqualsPlugin.Enhance
2244
            protected static class Factory implements TargetHandler.Factory {
2245

2246
                /**
2247
                 * The name prefix of the field to store the instance.
2248
                 */
2249
                private static final String FIELD_PREFIX = "invocationTarget";
2250

2251
                /**
2252
                 * The target on which the method is to be invoked.
2253
                 */
2254
                private final Object target;
2255

2256
                /**
2257
                 * The type of the field.
2258
                 */
2259
                private final TypeDescription.Generic fieldType;
2260

2261
                /**
2262
                 * The name of the field to store the target.
2263
                 */
2264
                @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.IGNORE)
2265
                private final String name;
2266

2267
                /**
2268
                 * Creates a new target handler for a static field.
2269
                 *
2270
                 * @param target    The target on which the method is to be invoked.
2271
                 * @param fieldType The type of the field.
2272
                 */
2273
                protected Factory(Object target, TypeDescription.Generic fieldType) {
1✔
2274
                    this.target = target;
1✔
2275
                    this.fieldType = fieldType;
1✔
2276
                    name = FIELD_PREFIX + "$" + RandomString.hashOf(target);
1✔
2277
                }
1✔
2278

2279
                /**
2280
                 * {@inheritDoc}
2281
                 */
2282
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
2283
                    return instrumentedType.withAuxiliaryField(new FieldDescription.Token(name,
1✔
2284
                            Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_VOLATILE | Opcodes.ACC_SYNTHETIC,
2285
                            fieldType), target);
2286
                }
2287

2288
                /**
2289
                 * {@inheritDoc}
2290
                 */
2291
                public TargetHandler make(Implementation.Target implementationTarget) {
2292
                    return new ForValue(implementationTarget.getInstrumentedType().getDeclaredFields().filter(named(name)).getOnly());
1✔
2293
                }
2294
            }
2295
        }
2296

2297
        /**
2298
         * Creates a target handler that stores the instance to invoke a method on in an instance field.
2299
         */
2300
        @HashCodeAndEqualsPlugin.Enhance
2301
        class ForField implements TargetHandler, Resolved {
2302

2303
            /**
2304
             * A description of the field that is the target.
2305
             */
2306
            private final FieldDescription fieldDescription;
2307

2308
            /**
2309
             * Creates a new target handler for a field description.
2310
             *
2311
             * @param fieldDescription A description of the field that is the target.
2312
             */
2313
            protected ForField(FieldDescription fieldDescription) {
1✔
2314
                this.fieldDescription = fieldDescription;
1✔
2315
            }
1✔
2316

2317
            /**
2318
             * {@inheritDoc}
2319
             */
2320
            public Resolved resolve(MethodDescription instrumentedMethod) {
2321
                return this;
1✔
2322
            }
2323

2324
            /**
2325
             * {@inheritDoc}
2326
             */
2327
            public TypeDescription getTypeDescription() {
2328
                return fieldDescription.getType().asErasure();
1✔
2329
            }
2330

2331
            /**
2332
             * {@inheritDoc}
2333
             */
2334
            public StackManipulation toStackManipulation(MethodDescription invokedMethod, Assigner assigner, Assigner.Typing typing) {
2335
                if (!invokedMethod.isMethod()
1✔
2336
                        || !invokedMethod.isVirtual()
1✔
2337
                        || !invokedMethod.isVisibleTo(fieldDescription.getType().asErasure())) {
1✔
2338
                    throw new IllegalStateException("Cannot invoke " + invokedMethod + " on " + fieldDescription);
×
2339
                }
2340
                StackManipulation stackManipulation = assigner.assign(fieldDescription.getType(), invokedMethod.getDeclaringType().asGenericType(), typing);
1✔
2341
                if (!stackManipulation.isValid()) {
1✔
2342
                    throw new IllegalStateException("Cannot invoke " + invokedMethod + " on " + fieldDescription);
×
2343
                }
2344
                return new StackManipulation.Compound(invokedMethod.isStatic() || fieldDescription.isStatic()
1✔
2345
                        ? StackManipulation.Trivial.INSTANCE
2346
                        : MethodVariableAccess.loadThis(),
1✔
2347
                        FieldAccess.forField(fieldDescription).read(), stackManipulation);
1✔
2348
            }
2349

2350
            /**
2351
             * A location of a field.
2352
             */
2353
            protected interface Location {
2354

2355
                /**
2356
                 * Resolves the field to invoke the method upon.
2357
                 *
2358
                 * @param instrumentedType The instrumented type.
2359
                 * @return The field to invoke the method upon.
2360
                 */
2361
                FieldDescription resolve(TypeDescription instrumentedType);
2362

2363
                /**
2364
                 * An implicit field location.
2365
                 */
2366
                @HashCodeAndEqualsPlugin.Enhance
2367
                class ForImplicitField implements Location {
2368

2369
                    /**
2370
                     * The name of the field.
2371
                     */
2372
                    private final String name;
2373

2374
                    /**
2375
                     * The field locator factory to use.
2376
                     */
2377
                    private final FieldLocator.Factory fieldLocatorFactory;
2378

2379
                    /**
2380
                     * Creates an implicit field location.
2381
                     *
2382
                     * @param name                The name of the field.
2383
                     * @param fieldLocatorFactory The field locator factory to use.
2384
                     */
2385
                    protected ForImplicitField(String name, FieldLocator.Factory fieldLocatorFactory) {
1✔
2386
                        this.name = name;
1✔
2387
                        this.fieldLocatorFactory = fieldLocatorFactory;
1✔
2388
                    }
1✔
2389

2390
                    /**
2391
                     * {@inheritDoc}
2392
                     */
2393
                    public FieldDescription resolve(TypeDescription instrumentedType) {
2394
                        FieldLocator.Resolution resolution = fieldLocatorFactory.make(instrumentedType).locate(name);
1✔
2395
                        if (!resolution.isResolved()) {
1✔
2396
                            throw new IllegalStateException("Could not locate field name " + name + " on " + instrumentedType);
1✔
2397
                        }
2398
                        return resolution.getField();
1✔
2399
                    }
2400
                }
2401

2402
                /**
2403
                 * An explicit field location.
2404
                 */
2405
                @HashCodeAndEqualsPlugin.Enhance
2406
                class ForExplicitField implements Location {
2407

2408
                    /**
2409
                     * The field to resolve.
2410
                     */
2411
                    private final FieldDescription fieldDescription;
2412

2413
                    /**
2414
                     * Creates an explicit field location.
2415
                     *
2416
                     * @param fieldDescription The field to resolve.
2417
                     */
2418
                    protected ForExplicitField(FieldDescription fieldDescription) {
1✔
2419
                        this.fieldDescription = fieldDescription;
1✔
2420
                    }
1✔
2421

2422
                    /**
2423
                     * {@inheritDoc}
2424
                     */
2425
                    public FieldDescription resolve(TypeDescription instrumentedType) {
2426
                        return fieldDescription;
1✔
2427
                    }
2428
                }
2429
            }
2430

2431
            /**
2432
             * A factory for a field access.
2433
             */
2434
            @HashCodeAndEqualsPlugin.Enhance
2435
            protected static class Factory implements TargetHandler.Factory {
2436

2437
                /**
2438
                 * The field's location.
2439
                 */
2440
                private final Location location;
2441

2442
                /**
2443
                 * Creates a new target handler factory for a field location.
2444
                 *
2445
                 * @param location The field's location.
2446
                 */
2447
                protected Factory(Location location) {
1✔
2448
                    this.location = location;
1✔
2449
                }
1✔
2450

2451
                /**
2452
                 * {@inheritDoc}
2453
                 */
2454
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
2455
                    return instrumentedType;
1✔
2456
                }
2457

2458
                /**
2459
                 * {@inheritDoc}
2460
                 */
2461
                @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
2462
                public TargetHandler make(Implementation.Target implementationTarget) {
2463
                    FieldDescription fieldDescription = location.resolve(implementationTarget.getInstrumentedType());
1✔
2464
                    if (!fieldDescription.isStatic() && !implementationTarget.getInstrumentedType().isAssignableTo(fieldDescription.getDeclaringType().asErasure())) {
1✔
2465
                        throw new IllegalStateException("Cannot access " + fieldDescription + " from " + implementationTarget.getInstrumentedType());
×
2466
                    }
2467
                    return new ForField(fieldDescription);
1✔
2468
                }
2469
            }
2470
        }
2471

2472
        /**
2473
         * A target handler that loads the parameter of the given index as the target object.
2474
         */
2475
        @HashCodeAndEqualsPlugin.Enhance
2476
        class ForMethodParameter implements TargetHandler, Factory {
2477

2478
            /**
2479
             * The index of the instrumented method's parameter that is the target of the method invocation.
2480
             */
2481
            private final int index;
2482

2483
            /**
2484
             * Creates a new target handler for the instrumented method's argument.
2485
             *
2486
             * @param index The index of the instrumented method's parameter that is the target of the method invocation.
2487
             */
2488
            protected ForMethodParameter(int index) {
1✔
2489
                this.index = index;
1✔
2490
            }
1✔
2491

2492
            /**
2493
             * {@inheritDoc}
2494
             */
2495
            public InstrumentedType prepare(InstrumentedType instrumentedType) {
2496
                return instrumentedType;
1✔
2497
            }
2498

2499
            /**
2500
             * {@inheritDoc}
2501
             */
2502
            public TargetHandler make(Implementation.Target implementationTarget) {
2503
                return this;
1✔
2504
            }
2505

2506
            /**
2507
             * {@inheritDoc}
2508
             */
2509
            public TargetHandler.Resolved resolve(MethodDescription instrumentedMethod) {
2510
                if (index >= instrumentedMethod.getParameters().size()) {
1✔
2511
                    throw new IllegalArgumentException(instrumentedMethod + " does not have a parameter with index " + index);
1✔
2512
                }
2513
                return new Resolved(instrumentedMethod.getParameters().get(index));
1✔
2514
            }
2515

2516
            /**
2517
             * A resolved target handler for a method parameter.
2518
             */
2519
            @HashCodeAndEqualsPlugin.Enhance
2520
            protected static class Resolved implements TargetHandler.Resolved {
2521

2522
                /**
2523
                 * The parameter that is the target of the method call.
2524
                 */
2525
                private final ParameterDescription parameterDescription;
2526

2527
                /**
2528
                 * Creates a new resolved target handler for a parameter.
2529
                 *
2530
                 * @param parameterDescription The parameter that is the target of the method call.
2531
                 */
2532
                protected Resolved(ParameterDescription parameterDescription) {
1✔
2533
                    this.parameterDescription = parameterDescription;
1✔
2534
                }
1✔
2535

2536
                /**
2537
                 * {@inheritDoc}
2538
                 */
2539
                public TypeDescription getTypeDescription() {
2540
                    return parameterDescription.getType().asErasure();
1✔
2541
                }
2542

2543
                /**
2544
                 * {@inheritDoc}
2545
                 */
2546
                public StackManipulation toStackManipulation(MethodDescription invokedMethod, Assigner assigner, Assigner.Typing typing) {
2547
                    StackManipulation stackManipulation = assigner.assign(parameterDescription.getType(), invokedMethod.getDeclaringType().asGenericType(), typing);
1✔
2548
                    if (!stackManipulation.isValid()) {
1✔
2549
                        throw new IllegalStateException("Cannot invoke " + invokedMethod + " on " + parameterDescription.getType());
1✔
2550
                    }
2551
                    return new StackManipulation.Compound(MethodVariableAccess.load(parameterDescription), stackManipulation);
1✔
2552
                }
2553
            }
2554
        }
2555

2556
        /**
2557
         * A target handler that executes the method and uses it's return value as the target object.
2558
         */
2559
        @HashCodeAndEqualsPlugin.Enhance
2560
        class ForMethodCall implements TargetHandler {
2561

2562
            /**
2563
             * The appender that is the target of the using method call.
2564
             */
2565
            private final Appender appender;
2566

2567
            /**
2568
             * Creates a new target handler for another method call.
2569
             *
2570
             * @param appender The appender that is the target of the using method call.
2571
             */
2572
            protected ForMethodCall(Appender appender) {
1✔
2573
                this.appender = appender;
1✔
2574
            }
1✔
2575

2576
            /**
2577
             * {@inheritDoc}
2578
             */
2579
            public TargetHandler.Resolved resolve(MethodDescription instrumentedMethod) {
2580
                TargetHandler.Resolved targetHandler = appender.targetHandler.resolve(instrumentedMethod);
1✔
2581
                return new Resolved(appender, appender.toInvokedMethod(instrumentedMethod, targetHandler), instrumentedMethod,
1✔
2582
                        targetHandler);
2583
            }
2584

2585
            /**
2586
             * A resolved target handler for a method call.
2587
             */
2588
            @HashCodeAndEqualsPlugin.Enhance
2589
            protected static class Resolved implements TargetHandler.Resolved {
2590

2591
                /**
2592
                 * The appender to use.
2593
                 */
2594
                private final Appender appender;
2595

2596
                /**
2597
                 * The invoked method.
2598
                 */
2599
                private final MethodDescription methodDescription;
2600

2601
                /**
2602
                 * The instrumented method.
2603
                 */
2604
                private final MethodDescription instrumentedMethod;
2605

2606
                /**
2607
                 * The target handler to use.
2608
                 */
2609
                private final TargetHandler.Resolved targetHandler;
2610

2611
                /**
2612
                 * Creates a resolved target handler for a method call.
2613
                 *
2614
                 * @param appender           The appender to use.
2615
                 * @param methodDescription  The invoked method.
2616
                 * @param instrumentedMethod The instrumented method.
2617
                 * @param targetHandler      The target handler to use.
2618
                 */
2619
                protected Resolved(Appender appender, MethodDescription methodDescription, MethodDescription instrumentedMethod, TargetHandler.Resolved targetHandler) {
1✔
2620
                    this.appender = appender;
1✔
2621
                    this.methodDescription = methodDescription;
1✔
2622
                    this.instrumentedMethod = instrumentedMethod;
1✔
2623
                    this.targetHandler = targetHandler;
1✔
2624
                }
1✔
2625

2626
                /**
2627
                 * {@inheritDoc}
2628
                 */
2629
                public TypeDescription getTypeDescription() {
2630
                    return methodDescription.isConstructor()
1✔
2631
                            ? methodDescription.getDeclaringType().asErasure()
1✔
2632
                            : methodDescription.getReturnType().asErasure();
1✔
2633
                }
2634

2635
                /**
2636
                 * {@inheritDoc}
2637
                 */
2638
                public StackManipulation toStackManipulation(MethodDescription invokedMethod, Assigner assigner, Assigner.Typing typing) {
2639
                    StackManipulation stackManipulation = assigner.assign(methodDescription.isConstructor()
1✔
2640
                            ? methodDescription.getDeclaringType().asGenericType()
1✔
2641
                            : methodDescription.getReturnType(), invokedMethod.getDeclaringType().asGenericType(), typing);
1✔
2642
                    if (!stackManipulation.isValid()) {
1✔
2643
                        throw new IllegalStateException("Cannot invoke " + invokedMethod + " on " + (methodDescription.isConstructor()
1✔
2644
                                ? methodDescription.getDeclaringType()
1✔
2645
                                : methodDescription.getReturnType()));
1✔
2646
                    }
2647
                    return new StackManipulation.Compound(appender.toStackManipulation(instrumentedMethod,
1✔
2648
                            methodDescription,
2649
                            targetHandler), stackManipulation);
2650
                }
2651
            }
2652

2653
            /**
2654
             * Creates a factory for invoking a method on the return type of another method.
2655
             */
2656
            @HashCodeAndEqualsPlugin.Enhance
2657
            protected static class Factory implements TargetHandler.Factory {
2658

2659
                /**
2660
                 * The method call to invoke.
2661
                 */
2662
                private final MethodCall methodCall;
2663

2664
                /**
2665
                 * Creates a new factory for invoking another method call as a method target.
2666
                 *
2667
                 * @param methodCall The method call to invoke.
2668
                 */
2669
                public Factory(MethodCall methodCall) {
1✔
2670
                    this.methodCall = methodCall;
1✔
2671
                }
1✔
2672

2673
                /**
2674
                 * {@inheritDoc}
2675
                 */
2676
                public InstrumentedType prepare(InstrumentedType instrumentedType) {
2677
                    return methodCall.prepare(instrumentedType);
1✔
2678
                }
2679

2680
                /**
2681
                 * {@inheritDoc}
2682
                 */
2683
                public TargetHandler make(Implementation.Target implementationTarget) {
2684
                    return new ForMethodCall(methodCall.new Appender(implementationTarget, TerminationHandler.Simple.IGNORING));
1✔
2685
                }
2686
            }
2687
        }
2688
    }
2689

2690
    /**
2691
     * A method invoker is responsible for creating a method invocation that is to be applied by a
2692
     * {@link net.bytebuddy.implementation.MethodCall}.
2693
     */
2694
    protected interface MethodInvoker {
2695

2696
        /**
2697
         * Invokes the method.
2698
         *
2699
         * @param invokedMethod        The method to be invoked.
2700
         * @param implementationTarget The implementation target of the instrumented instance.
2701
         * @return A stack manipulation that represents the method invocation.
2702
         */
2703
        StackManipulation toStackManipulation(MethodDescription invokedMethod, Implementation.Target implementationTarget);
2704

2705
        /**
2706
         * A factory for creating a method invoker.
2707
         */
2708
        interface Factory {
2709

2710
            /**
2711
             * Creates a method invoker.
2712
             *
2713
             * @param instrumentedType The instrumented type.
2714
             * @return The method invoker to use.
2715
             */
2716
            MethodInvoker make(TypeDescription instrumentedType);
2717
        }
2718

2719
        /**
2720
         * Applies a contextual invocation of the provided method, i.e. a static invocation for static methods,
2721
         * a special invocation for constructors and private methods and a virtual invocation for any other method.
2722
         */
2723
        @HashCodeAndEqualsPlugin.Enhance
2724
        class ForContextualInvocation implements MethodInvoker {
2725

2726
            /**
2727
             * The instrumented type.
2728
             */
2729
            private final TypeDescription instrumentedType;
2730

2731
            /**
2732
             * Creates a new method invoker for a contextual invocation.
2733
             *
2734
             * @param instrumentedType The instrumented type.
2735
             */
2736
            protected ForContextualInvocation(TypeDescription instrumentedType) {
1✔
2737
                this.instrumentedType = instrumentedType;
1✔
2738
            }
1✔
2739

2740
            /**
2741
             * {@inheritDoc}
2742
             */
2743
            public StackManipulation toStackManipulation(MethodDescription invokedMethod, Implementation.Target implementationTarget) {
2744
                if (invokedMethod.isVirtual() && !invokedMethod.isInvokableOn(instrumentedType)) {
1✔
2745
                    throw new IllegalStateException("Cannot invoke " + invokedMethod + " on " + instrumentedType);
1✔
2746
                }
2747
                return invokedMethod.isVirtual()
1✔
2748
                        ? MethodInvocation.invoke(invokedMethod).virtual(instrumentedType)
1✔
2749
                        : MethodInvocation.invoke(invokedMethod);
1✔
2750
            }
2751

2752
            /**
2753
             * A factory for creating a contextual method invoker.
2754
             */
2755
            enum Factory implements MethodInvoker.Factory {
1✔
2756

2757
                /**
2758
                 * The singleton instance.
2759
                 */
2760
                INSTANCE;
1✔
2761

2762
                /**
2763
                 * {@inheritDoc}
2764
                 */
2765
                public MethodInvoker make(TypeDescription instrumentedType) {
2766
                    return new ForContextualInvocation(instrumentedType);
1✔
2767
                }
2768
            }
2769
        }
2770

2771
        /**
2772
         * Applies a virtual invocation on a given type.
2773
         */
2774
        @HashCodeAndEqualsPlugin.Enhance
2775
        class ForVirtualInvocation implements MethodInvoker {
2776

2777
            /**
2778
             * The type description to virtually invoke the method upon.
2779
             */
2780
            private final TypeDescription typeDescription;
2781

2782
            /**
2783
             * Creates a new method invoking for a virtual method invocation.
2784
             *
2785
             * @param typeDescription The type description to virtually invoke the method upon.
2786
             */
2787
            protected ForVirtualInvocation(TypeDescription typeDescription) {
1✔
2788
                this.typeDescription = typeDescription;
1✔
2789
            }
1✔
2790

2791
            /**
2792
             * {@inheritDoc}
2793
             */
2794
            public StackManipulation toStackManipulation(MethodDescription invokedMethod, Implementation.Target implementationTarget) {
2795
                if (!invokedMethod.isInvokableOn(typeDescription)) {
1✔
2796
                    throw new IllegalStateException("Cannot invoke " + invokedMethod + " on " + typeDescription);
1✔
2797
                }
2798
                return MethodInvocation.invoke(invokedMethod).virtual(typeDescription);
1✔
2799
            }
2800

2801
            /**
2802
             * A method invoker for a virtual method that uses an implicit target type.
2803
             */
2804
            protected enum WithImplicitType implements MethodInvoker, MethodInvoker.Factory {
1✔
2805

2806
                /**
2807
                 * The singleton instance.
2808
                 */
2809
                INSTANCE;
1✔
2810

2811
                /**
2812
                 * {@inheritDoc}
2813
                 */
2814
                public MethodInvoker make(TypeDescription instrumentedType) {
2815
                    return this;
1✔
2816
                }
2817

2818
                /**
2819
                 * {@inheritDoc}
2820
                 */
2821
                public StackManipulation toStackManipulation(MethodDescription invokedMethod, Implementation.Target implementationTarget) {
2822
                    if (!invokedMethod.isAccessibleTo(implementationTarget.getInstrumentedType()) || !invokedMethod.isVirtual()) {
1✔
2823
                        throw new IllegalStateException("Cannot invoke " + invokedMethod + " virtually");
1✔
2824
                    }
2825
                    return MethodInvocation.invoke(invokedMethod);
1✔
2826
                }
2827
            }
2828

2829
            /**
2830
             * A method invoker factory for a virtual method invocation.
2831
             */
2832
            @HashCodeAndEqualsPlugin.Enhance
2833
            protected static class Factory implements MethodInvoker.Factory {
2834

2835
                /**
2836
                 * The type on which the virtual method is invoked.
2837
                 */
2838
                private final TypeDescription typeDescription;
2839

2840
                /**
2841
                 * Creates a new method invoker factory for a virtual method call.
2842
                 *
2843
                 * @param typeDescription The type on which the virtual method is invoked.
2844
                 */
2845
                protected Factory(TypeDescription typeDescription) {
1✔
2846
                    this.typeDescription = typeDescription;
1✔
2847
                }
1✔
2848

2849
                /**
2850
                 * {@inheritDoc}
2851
                 */
2852
                public MethodInvoker make(TypeDescription instrumentedType) {
2853
                    if (!typeDescription.asErasure().isAccessibleTo(instrumentedType)) {
1✔
2854
                        throw new IllegalStateException(typeDescription + " is not accessible to " + instrumentedType);
1✔
2855
                    }
2856
                    return new ForVirtualInvocation(typeDescription);
1✔
2857
                }
2858
            }
2859
        }
2860

2861
        /**
2862
         * Applies a super method invocation of the provided method.
2863
         */
2864
        @HashCodeAndEqualsPlugin.Enhance
2865
        class ForSuperMethodInvocation implements MethodInvoker {
2866

2867
            /**
2868
             * The instrumented type.
2869
             */
2870
            private final TypeDescription instrumentedType;
2871

2872
            /**
2873
             * Creates a method invoker for a super method invocation.
2874
             *
2875
             * @param instrumentedType The instrumented type.
2876
             */
2877
            protected ForSuperMethodInvocation(TypeDescription instrumentedType) {
1✔
2878
                this.instrumentedType = instrumentedType;
1✔
2879
            }
1✔
2880

2881
            /**
2882
             * {@inheritDoc}
2883
             */
2884
            public StackManipulation toStackManipulation(MethodDescription invokedMethod, Implementation.Target implementationTarget) {
2885
                if (!invokedMethod.isInvokableOn(implementationTarget.getOriginType().asErasure())) {
1✔
2886
                    throw new IllegalStateException("Cannot invoke " + invokedMethod + " as super method of " + instrumentedType);
1✔
2887
                }
2888
                StackManipulation stackManipulation = implementationTarget
1✔
2889
                        .invokeDominant(invokedMethod.asSignatureToken())
1✔
2890
                        .withCheckedCompatibilityTo(invokedMethod.asTypeToken());
1✔
2891
                if (!stackManipulation.isValid()) {
1✔
2892
                    throw new IllegalStateException("Cannot invoke " + invokedMethod + " as a super method");
×
2893
                }
2894
                return stackManipulation;
1✔
2895
            }
2896

2897
            /**
2898
             * A method invoker factory for a super method invocation.
2899
             */
2900
            enum Factory implements MethodInvoker.Factory {
1✔
2901

2902
                /**
2903
                 * The singleton instance.
2904
                 */
2905
                INSTANCE;
1✔
2906

2907
                /**
2908
                 * {@inheritDoc}
2909
                 */
2910
                public MethodInvoker make(TypeDescription instrumentedType) {
2911
                    if (instrumentedType.getSuperClass() == null) {
1✔
2912
                        throw new IllegalStateException("Cannot invoke super method for " + instrumentedType);
×
2913
                    }
2914
                    return new ForSuperMethodInvocation(instrumentedType);
1✔
2915
                }
2916
            }
2917
        }
2918

2919
        /**
2920
         * Invokes a method as a Java 8 default method.
2921
         */
2922
        @HashCodeAndEqualsPlugin.Enhance
2923
        class ForDefaultMethodInvocation implements MethodInvoker {
2924

2925
            /**
2926
             * The instrumented type.
2927
             */
2928
            private final TypeDescription instrumentedType;
2929

2930
            /**
2931
             * Creates a new method invoker for a default method invocation.
2932
             *
2933
             * @param instrumentedType The instrumented type.
2934
             */
2935
            protected ForDefaultMethodInvocation(TypeDescription instrumentedType) {
1✔
2936
                this.instrumentedType = instrumentedType;
1✔
2937
            }
1✔
2938

2939
            /**
2940
             * {@inheritDoc}
2941
             */
2942
            public StackManipulation toStackManipulation(MethodDescription invokedMethod, Implementation.Target implementationTarget) {
2943
                if (!invokedMethod.isInvokableOn(instrumentedType)) {
1✔
2944
                    throw new IllegalStateException("Cannot invoke " + invokedMethod + " as default method of " + instrumentedType);
1✔
2945
                }
2946
                StackManipulation stackManipulation = implementationTarget
1✔
2947
                        .invokeDefault(invokedMethod.asSignatureToken(), invokedMethod.getDeclaringType().asErasure())
1✔
2948
                        .withCheckedCompatibilityTo(invokedMethod.asTypeToken());
1✔
2949
                if (!stackManipulation.isValid()) {
1✔
2950
                    throw new IllegalStateException("Cannot invoke " + invokedMethod + " on " + instrumentedType);
×
2951
                }
2952
                return stackManipulation;
1✔
2953
            }
2954

2955
            /**
2956
             * A factory for creating a method invoker for a default method invocation.
2957
             */
2958
            enum Factory implements MethodInvoker.Factory {
1✔
2959

2960
                /**
2961
                 * The singleton instance.
2962
                 */
2963
                INSTANCE;
1✔
2964

2965
                /**
2966
                 * {@inheritDoc}
2967
                 */
2968
                public MethodInvoker make(TypeDescription instrumentedType) {
2969
                    return new ForDefaultMethodInvocation(instrumentedType);
1✔
2970
                }
2971
            }
2972
        }
2973
    }
2974

2975
    /**
2976
     * A termination handler is responsible to handle the return value of a method that is invoked via a
2977
     * {@link net.bytebuddy.implementation.MethodCall}.
2978
     */
2979
    protected interface TerminationHandler {
2980

2981
        /**
2982
         * Returns a preparing stack manipulation to apply prior to the method call.
2983
         *
2984
         * @return The stack manipulation to apply prior to the method call.
2985
         */
2986
        StackManipulation prepare();
2987

2988
        /**
2989
         * Returns a stack manipulation that handles the method return.
2990
         *
2991
         * @param invokedMethod      The method that was invoked by the method call.
2992
         * @param instrumentedMethod The method being intercepted.
2993
         * @param assigner           The assigner to be used.
2994
         * @param typing             Indicates if dynamic type castings should be attempted for incompatible assignments.
2995
         * @return A stack manipulation that handles the method return.
2996
         */
2997
        StackManipulation toStackManipulation(MethodDescription invokedMethod, MethodDescription instrumentedMethod, Assigner assigner, Assigner.Typing typing);
2998

2999
        /**
3000
         * A factory for creating a termination handler.
3001
         */
3002
        interface Factory {
3003

3004
            /**
3005
             * Creates a termination handler for a given instrumented type.
3006
             *
3007
             * @param instrumentedType The instrumented type.
3008
             * @return A termination handler to apply for the instrumented type.
3009
             */
3010
            TerminationHandler make(TypeDescription instrumentedType);
3011
        }
3012

3013
        /**
3014
         * Simple termination handler implementations.
3015
         */
3016
        enum Simple implements TerminationHandler, Factory {
1✔
3017

3018
            /**
3019
             * A termination handler that returns the invoked method's return value.
3020
             */
3021
            RETURNING {
1✔
3022
                /**
3023
                 * {@inheritDoc}
3024
                 */
3025
                public StackManipulation toStackManipulation(MethodDescription invokedMethod, MethodDescription instrumentedMethod, Assigner assigner, Assigner.Typing typing) {
3026
                    StackManipulation stackManipulation = assigner.assign(invokedMethod.isConstructor()
1✔
3027
                            ? invokedMethod.getDeclaringType().asGenericType()
1✔
3028
                            : invokedMethod.getReturnType(), instrumentedMethod.getReturnType(), typing);
1✔
3029
                    if (!stackManipulation.isValid()) {
1✔
3030
                        throw new IllegalStateException("Cannot return " + invokedMethod.getReturnType() + " from " + instrumentedMethod);
1✔
3031
                    }
3032
                    return new StackManipulation.Compound(stackManipulation, MethodReturn.of(instrumentedMethod.getReturnType()));
1✔
3033
                }
3034
            },
3035

3036
            /**
3037
             * A termination handler that drops the invoked method's return value.
3038
             */
3039
            DROPPING {
1✔
3040
                /**
3041
                 * {@inheritDoc}
3042
                 */
3043
                public StackManipulation toStackManipulation(MethodDescription invokedMethod, MethodDescription instrumentedMethod, Assigner assigner, Assigner.Typing typing) {
3044
                    return Removal.of(invokedMethod.isConstructor()
1✔
3045
                            ? invokedMethod.getDeclaringType()
1✔
3046
                            : invokedMethod.getReturnType());
1✔
3047
                }
3048
            },
3049

3050
            /**
3051
             * A termination handler that does not apply any change.
3052
             */
3053
            IGNORING {
1✔
3054
                /**
3055
                 * {@inheritDoc}
3056
                 */
3057
                public StackManipulation toStackManipulation(MethodDescription invokedMethod, MethodDescription instrumentedMethod, Assigner assigner, Assigner.Typing typing) {
3058
                    return StackManipulation.Trivial.INSTANCE;
1✔
3059
                }
3060
            };
3061

3062
            /**
3063
             * {@inheritDoc}
3064
             */
3065
            public TerminationHandler make(TypeDescription instrumentedType) {
3066
                return this;
1✔
3067
            }
3068

3069
            /**
3070
             * {@inheritDoc}
3071
             */
3072
            public StackManipulation prepare() {
3073
                return StackManipulation.Trivial.INSTANCE;
1✔
3074
            }
3075
        }
3076

3077

3078
        /**
3079
         * A termination handler that sets a field.
3080
         */
3081
        @HashCodeAndEqualsPlugin.Enhance
3082
        class FieldSetting implements TerminationHandler {
3083

3084
            /**
3085
             * The field to set.
3086
             */
3087
            private final FieldDescription fieldDescription;
3088

3089
            /**
3090
             * Creates a new field-setting termination handler.
3091
             *
3092
             * @param fieldDescription The field to set.
3093
             */
3094
            protected FieldSetting(FieldDescription fieldDescription) {
1✔
3095
                this.fieldDescription = fieldDescription;
1✔
3096
            }
1✔
3097

3098
            /**
3099
             * {@inheritDoc}
3100
             */
3101
            public StackManipulation prepare() {
3102
                return fieldDescription.isStatic()
1✔
3103
                        ? StackManipulation.Trivial.INSTANCE
3104
                        : MethodVariableAccess.loadThis();
1✔
3105
            }
3106

3107
            /**
3108
             * {@inheritDoc}
3109
             */
3110
            public StackManipulation toStackManipulation(MethodDescription invokedMethod, MethodDescription instrumentedMethod, Assigner assigner, Assigner.Typing typing) {
3111
                StackManipulation stackManipulation = assigner.assign(invokedMethod.isConstructor()
1✔
3112
                        ? invokedMethod.getDeclaringType().asGenericType()
1✔
3113
                        : invokedMethod.getReturnType(), fieldDescription.getType(), typing);
1✔
3114
                if (!stackManipulation.isValid()) {
1✔
3115
                    throw new IllegalStateException("Cannot assign result of " + invokedMethod + " to " + fieldDescription);
×
3116
                }
3117
                return new StackManipulation.Compound(stackManipulation, FieldAccess.forField(fieldDescription).write());
1✔
3118
            }
3119

3120
            /**
3121
             * A factory for a field-setting termination handler that locates a given field.
3122
             */
3123
            @HashCodeAndEqualsPlugin.Enhance
3124
            protected static class Explicit implements TerminationHandler.Factory {
3125

3126
                /**
3127
                 * The matcher being used for locating a field.
3128
                 */
3129
                private final FieldDescription fieldDescription;
3130

3131
                /**
3132
                 * Creates a factory for a field-setting termination handler.
3133
                 *
3134
                 * @param fieldDescription The field to set.
3135
                 */
3136
                protected Explicit(FieldDescription fieldDescription) {
1✔
3137
                    this.fieldDescription = fieldDescription;
1✔
3138
                }
1✔
3139

3140
                /**
3141
                 * {@inheritDoc}
3142
                 */
3143
                @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
3144
                public TerminationHandler make(TypeDescription instrumentedType) {
3145
                    if (!fieldDescription.isStatic() && !instrumentedType.isAssignableTo(fieldDescription.getDeclaringType().asErasure())) {
1✔
3146
                        throw new IllegalStateException("Cannot set " + fieldDescription + " from " + instrumentedType);
×
3147
                    } else if (!fieldDescription.isVisibleTo(instrumentedType)) {
1✔
3148
                        throw new IllegalStateException("Cannot access " + fieldDescription + " from " + instrumentedType);
×
3149
                    }
3150
                    return new FieldSetting(fieldDescription);
1✔
3151
                }
3152
            }
3153

3154
            /**
3155
             * A factory for a field-setting termination handler that uses a matcher to locate the target field on the insturmented type.
3156
             */
3157
            @HashCodeAndEqualsPlugin.Enhance
3158
            protected static class Implicit implements TerminationHandler.Factory {
3159

3160
                /**
3161
                 * The matcher being used for locating a field.
3162
                 */
3163
                private final ElementMatcher<? super FieldDescription> matcher;
3164

3165
                /**
3166
                 * Creates a factory for a field-setting termination handler.
3167
                 *
3168
                 * @param matcher The matcher being used for locating a field.
3169
                 */
3170
                protected Implicit(ElementMatcher<? super FieldDescription> matcher) {
1✔
3171
                    this.matcher = matcher;
1✔
3172
                }
1✔
3173

3174
                /**
3175
                 * {@inheritDoc}
3176
                 */
3177
                public TerminationHandler make(TypeDescription instrumentedType) {
3178
                    TypeDefinition current = instrumentedType;
1✔
3179
                    do {
3180
                        FieldList<?> candidates = current.getDeclaredFields().filter(isVisibleTo(instrumentedType).and(matcher));
1✔
3181
                        if (candidates.size() == 1) {
1✔
3182
                            return new FieldSetting(candidates.getOnly());
1✔
3183
                        } else if (candidates.size() == 2) {
1✔
3184
                            throw new IllegalStateException(matcher + " is ambiguous and resolved: " + candidates);
×
3185
                        }
3186
                        current = current.getSuperClass();
1✔
3187
                    } while (current != null);
1✔
3188
                    throw new IllegalStateException(matcher + " does not locate any accessible fields for " + instrumentedType);
×
3189
                }
3190
            }
3191
        }
3192
    }
3193

3194
    /**
3195
     * Represents a {@link net.bytebuddy.implementation.MethodCall} that invokes a method without specifying
3196
     * an invocation method. Some methods can for example be invoked both virtually or as a super method invocation.
3197
     * Similarly, interface methods can be invoked virtually or as an explicit invocation of a default method. If
3198
     * no explicit invocation type is set, a method is always invoked virtually unless the method
3199
     * represents a static methods or a constructor.
3200
     */
3201
    public static class WithoutSpecifiedTarget extends MethodCall {
3202

3203
        /**
3204
         * Creates a new method call without a specified target.
3205
         *
3206
         * @param methodLocator The method locator to use.
3207
         */
3208
        protected WithoutSpecifiedTarget(MethodLocator.Factory methodLocator) {
3209
            super(methodLocator,
1✔
3210
                    TargetHandler.ForSelfOrStaticInvocation.Factory.INSTANCE,
3211
                    Collections.<ArgumentLoader.Factory>emptyList(),
1✔
3212
                    MethodInvoker.ForContextualInvocation.Factory.INSTANCE,
3213
                    TerminationHandler.Simple.RETURNING,
3214
                    Assigner.DEFAULT,
3215
                    Assigner.Typing.STATIC);
3216
        }
1✔
3217

3218
        /**
3219
         * Invokes the specified method on the given instance.
3220
         *
3221
         * @param target The object on which the method is to be invoked upon.
3222
         * @return A method call that invokes the provided method on the given object.
3223
         */
3224
        @SuppressWarnings("unchecked")
3225
        public MethodCall on(Object target) {
3226
            return on(target, (Class) target.getClass());
1✔
3227
        }
3228

3229
        /**
3230
         * Invokes the specified method on the given instance.
3231
         *
3232
         * @param target The object on which the method is to be invoked upon.
3233
         * @param type   The object's type.
3234
         * @param <T>    The type of the object.
3235
         * @return A method call that invokes the provided method on the given object.
3236
         */
3237
        public <T> MethodCall on(T target, Class<? super T> type) {
3238
            return new MethodCall(methodLocator,
1✔
3239
                    new TargetHandler.ForValue.Factory(target, TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(type)),
1✔
3240
                    argumentLoaders,
3241
                    new MethodInvoker.ForVirtualInvocation.Factory(TypeDescription.ForLoadedType.of(type)),
1✔
3242
                    terminationHandler,
3243
                    assigner,
3244
                    typing);
3245
        }
3246

3247
        /**
3248
         * Invokes the specified method on an instance that is loaded by the provided stack manipulation.
3249
         *
3250
         * @param stackManipulation The stack manipulation that loads the instance that the method is invoked upon.
3251
         * @param type              The type of the loaded instance.
3252
         * @return A method call that invokes the provided method on the value of the provided stack manipulation.
3253
         */
3254
        public MethodCall on(StackManipulation stackManipulation, Class<?> type) {
3255
            return on(stackManipulation, TypeDescription.ForLoadedType.of(type));
1✔
3256
        }
3257

3258
        /**
3259
         * Invokes the specified method on an instance that is loaded by the provided stack manipulation.
3260
         *
3261
         * @param stackManipulation The stack manipulation that loads the instance that the method is invoked upon.
3262
         * @param typeDescription   The type of the loaded instance.
3263
         * @return A method call that invokes the provided method on the value of the provided stack manipulation.
3264
         */
3265
        public MethodCall on(StackManipulation stackManipulation, TypeDescription typeDescription) {
3266
            return new MethodCall(methodLocator,
1✔
3267
                    new TargetHandler.Simple(typeDescription, stackManipulation),
3268
                    argumentLoaders,
3269
                    new MethodInvoker.ForVirtualInvocation.Factory(typeDescription),
3270
                    terminationHandler,
3271
                    assigner,
3272
                    typing);
3273
        }
3274

3275
        /**
3276
         * Invokes the specified method on the instrumented method's argument of the given index.
3277
         *
3278
         * @param index The index of the method's argument on which the specified method should be invoked.
3279
         * @return A method call that invokes the provided method on the given method argument.
3280
         */
3281
        public MethodCall onArgument(int index) {
3282
            if (index < 0) {
1✔
3283
                throw new IllegalArgumentException("An argument index cannot be negative: " + index);
1✔
3284
            }
3285
            return new MethodCall(methodLocator,
1✔
3286
                    new TargetHandler.ForMethodParameter(index),
3287
                    argumentLoaders,
3288
                    MethodInvoker.ForVirtualInvocation.WithImplicitType.INSTANCE,
3289
                    terminationHandler,
3290
                    assigner,
3291
                    typing);
3292
        }
3293

3294
        /**
3295
         * Invokes a method on the object stored in the specified field.
3296
         *
3297
         * @param name The name of the field.
3298
         * @return A method call that invokes the given method on an instance that is read from a field.
3299
         */
3300
        public MethodCall onField(String name) {
3301
            return onField(name, FieldLocator.ForClassHierarchy.Factory.INSTANCE);
1✔
3302
        }
3303

3304
        /**
3305
         * Invokes a method on the object stored in the specified field.
3306
         *
3307
         * @param name                The name of the field.
3308
         * @param fieldLocatorFactory The field locator factory to use for locating the field.
3309
         * @return A method call that invokes the given method on an instance that is read from a field.
3310
         */
3311
        public MethodCall onField(String name, FieldLocator.Factory fieldLocatorFactory) {
3312
            return new MethodCall(methodLocator,
1✔
3313
                    new TargetHandler.ForField.Factory(new TargetHandler.ForField.Location.ForImplicitField(name, fieldLocatorFactory)),
3314
                    argumentLoaders,
3315
                    MethodInvoker.ForVirtualInvocation.WithImplicitType.INSTANCE,
3316
                    terminationHandler,
3317
                    assigner,
3318
                    typing);
3319
        }
3320

3321
        /**
3322
         * Invokes a method on the object stored in the specified field.
3323
         *
3324
         * @param field The field on which to invoke the method upon.
3325
         * @return A method call that invokes the given method on an instance that is read from a field.
3326
         */
3327
        public MethodCall onField(Field field) {
3328
            return onField(new FieldDescription.ForLoadedField(field));
1✔
3329
        }
3330

3331
        /**
3332
         * Invokes a method on the object stored in the specified field.
3333
         *
3334
         * @param fieldDescription The field on which to invoke the method upon.
3335
         * @return A method call that invokes the given method on an instance that is read from a field.
3336
         */
3337
        public MethodCall onField(FieldDescription fieldDescription) {
3338
            return new MethodCall(methodLocator,
1✔
3339
                    new TargetHandler.ForField.Factory(new TargetHandler.ForField.Location.ForExplicitField(fieldDescription)),
3340
                    argumentLoaders,
3341
                    MethodInvoker.ForVirtualInvocation.WithImplicitType.INSTANCE,
3342
                    terminationHandler,
3343
                    assigner,
3344
                    typing);
3345
        }
3346

3347
        /**
3348
         * Invokes a method on the method call's return value.
3349
         *
3350
         * @param methodCall The method call that return's value is to be used in this method call
3351
         * @return A method call that invokes the given method on an instance that is returned from a method call.
3352
         */
3353
        public MethodCall onMethodCall(MethodCall methodCall) {
3354
            return new MethodCall(methodLocator,
1✔
3355
                    new TargetHandler.ForMethodCall.Factory(methodCall),
3356
                    argumentLoaders,
3357
                    MethodInvoker.ForVirtualInvocation.WithImplicitType.INSTANCE,
3358
                    terminationHandler,
3359
                    assigner,
3360
                    typing);
3361
        }
3362

3363
        /**
3364
         * Invokes the given method by a super method invocation on the instance of the instrumented type.
3365
         * Note that the super method is resolved depending on the type of implementation when this method is called.
3366
         * In case that a subclass is created, the super type is invoked. If a type is rebased, the rebased method
3367
         * is invoked if such a method exists.
3368
         *
3369
         * @return A method call where the given method is invoked as a super method invocation.
3370
         */
3371
        public MethodCall onSuper() {
3372
            return new MethodCall(methodLocator,
1✔
3373
                    TargetHandler.ForSelfOrStaticInvocation.Factory.INSTANCE,
3374
                    argumentLoaders,
3375
                    MethodInvoker.ForSuperMethodInvocation.Factory.INSTANCE,
3376
                    terminationHandler,
3377
                    assigner,
3378
                    typing);
3379
        }
3380

3381
        /**
3382
         * Invokes the given method by a Java 8 default method invocation on the instance of the instrumented type.
3383
         *
3384
         * @return A method call where the given method is invoked as a super method invocation.
3385
         */
3386
        public MethodCall onDefault() {
3387
            return new MethodCall(methodLocator,
1✔
3388
                    TargetHandler.ForSelfOrStaticInvocation.Factory.INSTANCE,
3389
                    argumentLoaders,
3390
                    MethodInvoker.ForDefaultMethodInvocation.Factory.INSTANCE,
3391
                    terminationHandler,
3392
                    assigner,
3393
                    typing);
3394
        }
3395
    }
3396

3397
    /**
3398
     * A {@link MethodCall} that sets the call's result as the value of a field.
3399
     */
3400
    @HashCodeAndEqualsPlugin.Enhance
3401
    public static class FieldSetting implements Composable {
3402

3403
        /**
3404
         * The represented method call.
3405
         */
3406
        private final MethodCall methodCall;
3407

3408
        /**
3409
         * Creates a new field setting method call.
3410
         *
3411
         * @param methodCall The represented method call.
3412
         */
3413
        protected FieldSetting(MethodCall methodCall) {
1✔
3414
            this.methodCall = methodCall;
1✔
3415
        }
1✔
3416

3417
        /**
3418
         * Defines an assigner to be used for assigning values to the parameters of the invoked method. This assigner
3419
         * is also used for assigning the invoked method's return value to the field being set.
3420
         *
3421
         * @param assigner The assigner to use.
3422
         * @param typing   Indicates if dynamic type castings should be attempted for incompatible assignments.
3423
         * @return This field-setting method call using the provided assigner.
3424
         */
3425
        public Composable withAssigner(Assigner assigner, Assigner.Typing typing) {
3426
            return new FieldSetting((MethodCall) methodCall.withAssigner(assigner, typing));
×
3427
        }
3428

3429
        /**
3430
         * {@inheritDoc}
3431
         */
3432
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
3433
            return methodCall.prepare(instrumentedType);
1✔
3434
        }
3435

3436
        /**
3437
         * {@inheritDoc}
3438
         */
3439
        public ByteCodeAppender appender(Target implementationTarget) {
3440
            return new ByteCodeAppender.Compound(methodCall.appender(implementationTarget), Appender.INSTANCE);
1✔
3441
        }
3442

3443
        /**
3444
         * {@inheritDoc}
3445
         */
3446
        public Implementation andThen(Implementation implementation) {
3447
            return new Compound(methodCall, implementation);
1✔
3448
        }
3449

3450
        /**
3451
         * {@inheritDoc}
3452
         */
3453
        public Composable andThen(Composable implementation) {
3454
            return new Compound.Composable(methodCall, implementation);
1✔
3455
        }
3456

3457
        /**
3458
         * A byte code appender to implement a field-setting method call.
3459
         */
3460
        protected enum Appender implements ByteCodeAppender {
1✔
3461

3462
            /**
3463
             * The singleton instance.
3464
             */
3465
            INSTANCE;
1✔
3466

3467
            /**
3468
             * {@inheritDoc}
3469
             */
3470
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
3471
                if (!instrumentedMethod.getReturnType().represents(void.class)) {
1✔
3472
                    throw new IllegalStateException("Instrumented method " + instrumentedMethod + " does not return void for field setting method call");
1✔
3473
                }
3474
                return new Size(MethodReturn.VOID.apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize());
1✔
3475
            }
3476
        }
3477
    }
3478

3479
    /**
3480
     * The appender being used to implement a {@link net.bytebuddy.implementation.MethodCall}.
3481
     */
3482
    @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
3483
    protected class Appender implements ByteCodeAppender {
3484

3485
        /**
3486
         * The implementation target.
3487
         */
3488
        private final Implementation.Target implementationTarget;
3489

3490
        /**
3491
         * The method locator to use.
3492
         */
3493
        private final MethodLocator methodLocator;
3494

3495
        /**
3496
         * The argument providers to use.
3497
         */
3498
        private final List<ArgumentLoader.ArgumentProvider> argumentProviders;
3499

3500
        /**
3501
         * The method invoker to use.
3502
         */
3503
        private final MethodInvoker methodInvoker;
3504

3505
        /**
3506
         * The target handler to use.
3507
         */
3508
        private final TargetHandler targetHandler;
3509

3510
        /**
3511
         * The termination handler to use.
3512
         */
3513
        private final TerminationHandler terminationHandler;
3514

3515
        /**
3516
         * Creates a new appender.
3517
         *
3518
         * @param implementationTarget The implementation target.
3519
         * @param terminationHandler   The termination handler to use.
3520
         */
3521
        protected Appender(Target implementationTarget, TerminationHandler terminationHandler) {
1✔
3522
            this.implementationTarget = implementationTarget;
1✔
3523
            methodLocator = MethodCall.this.methodLocator.make(implementationTarget.getInstrumentedType());
1✔
3524
            argumentProviders = new ArrayList<ArgumentLoader.ArgumentProvider>(argumentLoaders.size());
1✔
3525
            for (ArgumentLoader.Factory factory : argumentLoaders) {
1✔
3526
                argumentProviders.add(factory.make(implementationTarget));
1✔
3527
            }
1✔
3528
            methodInvoker = MethodCall.this.methodInvoker.make(implementationTarget.getInstrumentedType());
1✔
3529
            targetHandler = MethodCall.this.targetHandler.make(implementationTarget);
1✔
3530
            this.terminationHandler = terminationHandler;
1✔
3531
        }
1✔
3532

3533
        /**
3534
         * {@inheritDoc}
3535
         */
3536
        public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
3537
            TargetHandler.Resolved targetHandler = this.targetHandler.resolve(instrumentedMethod);
1✔
3538
            return new Size(new StackManipulation.Compound(terminationHandler.prepare(), toStackManipulation(instrumentedMethod,
1✔
3539
                    toInvokedMethod(instrumentedMethod, targetHandler),
1✔
3540
                    targetHandler)).apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize());
1✔
3541
        }
3542

3543
        /**
3544
         * Resolves this appender to the method being invoked.
3545
         *
3546
         * @param instrumentedMethod The instrumented method.
3547
         * @param targetHandler      The resolved target handler to base the stack manipulation upon.
3548
         * @return The invoked method.
3549
         */
3550
        protected MethodDescription toInvokedMethod(MethodDescription instrumentedMethod, TargetHandler.Resolved targetHandler) {
3551
            return methodLocator.resolve(targetHandler.getTypeDescription(), instrumentedMethod);
1✔
3552
        }
3553

3554
        /**
3555
         * Resolves this appender to a stack manipulation.
3556
         *
3557
         * @param instrumentedMethod The instrumented method.
3558
         * @param invokedMethod      The invoked method.
3559
         * @param targetHandler      The resolved target handler to base the stack manipulation upon.
3560
         * @return A stack manipulation that represents this method call.
3561
         */
3562
        protected StackManipulation toStackManipulation(MethodDescription instrumentedMethod, MethodDescription invokedMethod, TargetHandler.Resolved targetHandler) {
3563
            List<ArgumentLoader> argumentLoaders = new ArrayList<ArgumentLoader>();
1✔
3564
            for (ArgumentLoader.ArgumentProvider argumentProvider : argumentProviders) {
1✔
3565
                argumentLoaders.addAll(argumentProvider.resolve(instrumentedMethod, invokedMethod));
1✔
3566
            }
1✔
3567
            ParameterList<?> parameters = invokedMethod.getParameters();
1✔
3568
            if (parameters.size() != argumentLoaders.size()) {
1✔
3569
                throw new IllegalStateException(invokedMethod + " does not accept " + argumentLoaders.size() + " arguments");
1✔
3570
            }
3571
            Iterator<? extends ParameterDescription> parameterIterator = parameters.iterator();
1✔
3572
            List<StackManipulation> argumentInstructions = new ArrayList<StackManipulation>(argumentLoaders.size());
1✔
3573
            for (ArgumentLoader argumentLoader : argumentLoaders) {
1✔
3574
                argumentInstructions.add(argumentLoader.toStackManipulation(parameterIterator.next(), assigner, typing));
1✔
3575
            }
1✔
3576
            return new StackManipulation.Compound(
1✔
3577
                    targetHandler.toStackManipulation(invokedMethod, assigner, typing),
1✔
3578
                    new StackManipulation.Compound(argumentInstructions),
3579
                    methodInvoker.toStackManipulation(invokedMethod, implementationTarget),
1✔
3580
                    terminationHandler.toStackManipulation(invokedMethod, instrumentedMethod, assigner, typing)
1✔
3581
            );
3582
        }
3583
    }
3584
}
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