• 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

93.19
/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Implementation.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 net.bytebuddy.ClassFileVersion;
19
import net.bytebuddy.build.CachedReturnPlugin;
20
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
21
import net.bytebuddy.description.annotation.AnnotationList;
22
import net.bytebuddy.description.annotation.AnnotationValue;
23
import net.bytebuddy.description.field.FieldDescription;
24
import net.bytebuddy.description.method.MethodDescription;
25
import net.bytebuddy.description.method.ParameterDescription;
26
import net.bytebuddy.description.method.ParameterList;
27
import net.bytebuddy.description.modifier.Visibility;
28
import net.bytebuddy.description.type.TypeDefinition;
29
import net.bytebuddy.description.type.TypeDescription;
30
import net.bytebuddy.description.type.TypeList;
31
import net.bytebuddy.dynamic.DynamicType;
32
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
33
import net.bytebuddy.dynamic.scaffold.MethodGraph;
34
import net.bytebuddy.dynamic.scaffold.TypeInitializer;
35
import net.bytebuddy.dynamic.scaffold.TypeWriter;
36
import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
37
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
38
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
39
import net.bytebuddy.implementation.bytecode.StackManipulation;
40
import net.bytebuddy.implementation.bytecode.member.FieldAccess;
41
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
42
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
43
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
44
import net.bytebuddy.utility.CompoundList;
45
import net.bytebuddy.utility.JavaConstant;
46
import net.bytebuddy.utility.RandomString;
47
import net.bytebuddy.utility.nullability.MaybeNull;
48
import org.objectweb.asm.ClassVisitor;
49
import org.objectweb.asm.FieldVisitor;
50
import org.objectweb.asm.MethodVisitor;
51
import org.objectweb.asm.Opcodes;
52

53
import javax.annotation.Nonnull;
54
import java.util.ArrayList;
55
import java.util.Arrays;
56
import java.util.Collections;
57
import java.util.HashMap;
58
import java.util.HashSet;
59
import java.util.List;
60
import java.util.Map;
61
import java.util.Set;
62

63
/**
64
 * An implementation is responsible for implementing methods of a dynamically created type as byte code. An
65
 * implementation is applied in two stages:
66
 * <ol>
67
 * <li>The implementation is able to prepare an instrumented type by adding fields and/or helper methods that are
68
 * required for the methods implemented by this implementation. Furthermore,
69
 * {@link LoadedTypeInitializer}s  and byte code for the type initializer can be registered for the instrumented
70
 * type.</li>
71
 * <li>Any implementation is required to supply a byte code appender that is responsible for providing the byte code
72
 * to the instrumented methods that were delegated to this implementation. This byte code appender is also
73
 * be responsible for providing implementations for the methods added in step <i>1</i>.</li>
74
 * </ol>
75
 * <p>&nbsp;</p>
76
 * An implementation should provide meaningful implementations of both {@link java.lang.Object#equals(Object)}
77
 * and {@link Object#hashCode()} if it wants to avoid to be used twice within the creation of a dynamic type. For two
78
 * equal implementations only one will be applied on the creation of a dynamic type.
79
 */
80
public interface Implementation extends InstrumentedType.Prepareable {
81

82
    /**
83
     * Creates a byte code appender that determines the implementation of the instrumented type's methods.
84
     *
85
     * @param implementationTarget The target of the current implementation.
86
     * @return A byte code appender for implementing methods delegated to this implementation. This byte code appender
87
     * is also responsible for handling methods that were added by this implementation on the call to
88
     * {@link Implementation#prepare(InstrumentedType)}.
89
     */
90
    ByteCodeAppender appender(Target implementationTarget);
91

92
    /**
93
     * Represents an implementation that can be chained together with another implementation.
94
     */
95
    interface Composable extends Implementation {
96

97
        /**
98
         * Appends the supplied implementation to this implementation.
99
         *
100
         * @param implementation The subsequent implementation.
101
         * @return An implementation that combines this implementation with the provided one.
102
         */
103
        Implementation andThen(Implementation implementation);
104

105
        /**
106
         * Appends the supplied composable implementation to this implementation.
107
         *
108
         * @param implementation The subsequent composable implementation.
109
         * @return A composable implementation that combines this implementation with the provided one.
110
         */
111
        Composable andThen(Composable implementation);
112
    }
113

114
    /**
115
     * Represents a type-specific method invocation on the current instrumented type which is not legal from outside
116
     * the type such as a super method or default method invocation. Legal instances of special method invocations must
117
     * be equal to one another if they represent the same invocation target.
118
     */
119
    interface SpecialMethodInvocation extends StackManipulation {
120

121
        /**
122
         * Returns the method that represents this special method invocation. This method can be different even for
123
         * equal special method invocations, dependent on the method that was used to request such an invocation by the
124
         * means of a {@link Implementation.Target}.
125
         *
126
         * @return The method description that describes this instances invocation target.
127
         */
128
        MethodDescription getMethodDescription();
129

130
        /**
131
         * Returns the target type the represented method is invoked on.
132
         *
133
         * @return The type the represented method is invoked on.
134
         */
135
        TypeDescription getTypeDescription();
136

137
        /**
138
         * Checks that this special method invocation is compatible with the supplied type representation.
139
         *
140
         * @param token The type token to check against.
141
         * @return This special method invocation or an illegal invocation if the method invocation is not applicable.
142
         */
143
        SpecialMethodInvocation withCheckedCompatibilityTo(MethodDescription.TypeToken token);
144

145
        /**
146
         * Returns a method handle representing this special method invocation.
147
         *
148
         * @return A method handle for this special method invocation.
149
         */
150
        JavaConstant.MethodHandle toMethodHandle();
151

152
        /**
153
         * A canonical implementation of an illegal {@link Implementation.SpecialMethodInvocation}.
154
         */
155
        enum Illegal implements SpecialMethodInvocation {
1✔
156

157
            /**
158
             * The singleton instance.
159
             */
160
            INSTANCE;
1✔
161

162
            /**
163
             * {@inheritDoc}
164
             */
165
            public boolean isValid() {
166
                return false;
1✔
167
            }
168

169
            /**
170
             * {@inheritDoc}
171
             */
172
            public Size apply(MethodVisitor methodVisitor, Context implementationContext) {
173
                throw new IllegalStateException("Cannot implement an undefined method");
1✔
174
            }
175

176
            /**
177
             * {@inheritDoc}
178
             */
179
            public MethodDescription getMethodDescription() {
180
                throw new IllegalStateException("An illegal special method invocation must not be applied");
1✔
181
            }
182

183
            /**
184
             * {@inheritDoc}
185
             */
186
            public TypeDescription getTypeDescription() {
187
                throw new IllegalStateException("An illegal special method invocation must not be applied");
1✔
188
            }
189

190
            /**
191
             * {@inheritDoc}
192
             */
193
            public SpecialMethodInvocation withCheckedCompatibilityTo(MethodDescription.TypeToken token) {
194
                return this;
1✔
195
            }
196

197
            @Override
198
            public JavaConstant.MethodHandle toMethodHandle() {
199
                throw new IllegalStateException("An illegal special method invocation must not be applied");
×
200
            }
201
        }
202

203
        /**
204
         * An abstract base implementation of a valid special method invocation.
205
         */
206
        abstract class AbstractBase extends StackManipulation.AbstractBase implements SpecialMethodInvocation {
1✔
207

208
            @Override
209
            @CachedReturnPlugin.Enhance("hashCode")
210
            public int hashCode() {
211
                return 31 * getMethodDescription().asSignatureToken().hashCode() + getTypeDescription().hashCode();
1✔
212
            }
213

214
            @Override
215
            public boolean equals(@MaybeNull Object other) {
216
                if (this == other) {
1✔
217
                    return true;
×
218
                } else if (!(other instanceof SpecialMethodInvocation)) {
1✔
219
                    return false;
×
220
                }
221
                SpecialMethodInvocation specialMethodInvocation = (SpecialMethodInvocation) other;
1✔
222
                return getMethodDescription().asSignatureToken().equals(specialMethodInvocation.getMethodDescription().asSignatureToken())
1✔
223
                        && getTypeDescription().equals(specialMethodInvocation.getTypeDescription());
1✔
224
            }
225
        }
226

227
        /**
228
         * A canonical implementation of a {@link SpecialMethodInvocation}.
229
         */
230
        class Simple extends SpecialMethodInvocation.AbstractBase {
231

232
            /**
233
             * The method description that is represented by this legal special method invocation.
234
             */
235
            private final MethodDescription methodDescription;
236

237
            /**
238
             * The type description that is represented by this legal special method invocation.
239
             */
240
            private final TypeDescription typeDescription;
241

242
            /**
243
             * A stack manipulation representing the method's invocation on the type description.
244
             */
245
            private final StackManipulation stackManipulation;
246

247
            /**
248
             * Creates a new legal special method invocation.
249
             *
250
             * @param methodDescription The method that represents the special method invocation.
251
             * @param typeDescription   The type on which the method should be invoked on by an {@code INVOKESPECIAL}
252
             *                          invocation.
253
             * @param stackManipulation The stack manipulation that represents this special method invocation.
254
             */
255
            protected Simple(MethodDescription methodDescription, TypeDescription typeDescription, StackManipulation stackManipulation) {
1✔
256
                this.methodDescription = methodDescription;
1✔
257
                this.typeDescription = typeDescription;
1✔
258
                this.stackManipulation = stackManipulation;
1✔
259
            }
1✔
260

261
            /**
262
             * Creates a special method invocation for a given invocation target.
263
             *
264
             * @param methodDescription The method that represents the special method invocation.
265
             * @param typeDescription   The type on which the method should be invoked on by an {@code INVOKESPECIAL}
266
             *                          invocation.
267
             * @return A special method invocation representing a legal invocation if the method can be invoked
268
             * specially on the target type or an illegal invocation if this is not possible.
269
             */
270
            public static SpecialMethodInvocation of(MethodDescription methodDescription, TypeDescription typeDescription) {
271
                StackManipulation stackManipulation = MethodInvocation.invoke(methodDescription).special(typeDescription);
1✔
272
                return stackManipulation.isValid()
1✔
273
                        ? new SpecialMethodInvocation.Simple(methodDescription, typeDescription, stackManipulation)
274
                        : SpecialMethodInvocation.Illegal.INSTANCE;
275
            }
276

277
            /**
278
             * {@inheritDoc}
279
             */
280
            public MethodDescription getMethodDescription() {
281
                return methodDescription;
1✔
282
            }
283

284
            /**
285
             * {@inheritDoc}
286
             */
287
            public TypeDescription getTypeDescription() {
288
                return typeDescription;
1✔
289
            }
290

291
            /**
292
             * {@inheritDoc}
293
             */
294
            public Size apply(MethodVisitor methodVisitor, Context implementationContext) {
295
                return stackManipulation.apply(methodVisitor, implementationContext);
1✔
296
            }
297

298
            /**
299
             * {@inheritDoc}
300
             */
301
            public SpecialMethodInvocation withCheckedCompatibilityTo(MethodDescription.TypeToken token) {
302
                if (methodDescription.asTypeToken().equals(token)) {
1✔
303
                    return this;
1✔
304
                } else {
305
                    return SpecialMethodInvocation.Illegal.INSTANCE;
1✔
306
                }
307
            }
308

309
            /**
310
             * {@inheritDoc}
311
             */
312
            public JavaConstant.MethodHandle toMethodHandle() {
313
                return JavaConstant.MethodHandle.ofSpecial(methodDescription.asDefined(), typeDescription);
1✔
314
            }
315
        }
316
    }
317

318
    /**
319
     * The target of an implementation. Implementation targets must be immutable and can be queried without altering
320
     * the implementation result. An implementation target provides information on the type that is to be created
321
     * where it is the implementation's responsibility to cache expensive computations, especially such computations
322
     * that require reflective look-up.
323
     */
324
    interface Target {
325

326
        /**
327
         * Returns a description of the instrumented type.
328
         *
329
         * @return A description of the instrumented type.
330
         */
331
        TypeDescription getInstrumentedType();
332

333
        /**
334
         * Identifies the origin type of an implementation. The origin type describes the type that is subject to
335
         * any form of enhancement. If a subclass of a given type is generated, the base type of this subclass
336
         * describes the origin type. If a given type is redefined or rebased, the origin type is described by the
337
         * instrumented type itself.
338
         *
339
         * @return The origin type of this implementation.
340
         */
341
        TypeDefinition getOriginType();
342

343
        /**
344
         * Creates a special method invocation for invoking the super method of the given method.
345
         *
346
         * @param token A token of the method that is to be invoked as a super method.
347
         * @return The corresponding special method invocation which might be illegal if the requested invocation is not legal.
348
         */
349
        SpecialMethodInvocation invokeSuper(MethodDescription.SignatureToken token);
350

351
        /**
352
         * Creates a special method invocation for invoking a default method with the given token. The default method call must
353
         * not be ambiguous or an illegal special method invocation is returned.
354
         *
355
         * @param token A token of the method that is to be invoked as a default method.
356
         * @return The corresponding default method invocation which might be illegal if the requested invocation is not legal or ambiguous.
357
         */
358
        SpecialMethodInvocation invokeDefault(MethodDescription.SignatureToken token);
359

360
        /**
361
         * Creates a special method invocation for invoking a default method.
362
         *
363
         * @param targetType The interface on which the default method is to be invoked.
364
         * @param token      A token that uniquely describes the method to invoke.
365
         * @return The corresponding special method invocation which might be illegal if the requested invocation is
366
         * not legal.
367
         */
368
        SpecialMethodInvocation invokeDefault(MethodDescription.SignatureToken token, TypeDescription targetType);
369

370
        /**
371
         * Invokes a dominant method, i.e. if the method token can be invoked as a super method invocation, this invocation is considered dominant.
372
         * Alternatively, a method invocation is attempted on an interface type as a default method invocation only if this invocation is not ambiguous
373
         * for several interfaces.
374
         *
375
         * @param token The method token representing the method to be invoked.
376
         * @return A special method invocation for a method representing the method token.
377
         */
378
        SpecialMethodInvocation invokeDominant(MethodDescription.SignatureToken token);
379

380
        /**
381
         * A factory for creating an {@link Implementation.Target}.
382
         */
383
        interface Factory {
384

385
            /**
386
             * Creates an implementation target.
387
             *
388
             * @param instrumentedType The instrumented type.
389
             * @param methodGraph      A method graph of the instrumented type.
390
             * @param classFileVersion The type's class file version.
391
             * @return An implementation target for the instrumented type.
392
             */
393
            Target make(TypeDescription instrumentedType, MethodGraph.Linked methodGraph, ClassFileVersion classFileVersion);
394
        }
395

396
        /**
397
         * An abstract base implementation for an {@link Implementation.Target}.
398
         */
399
        @HashCodeAndEqualsPlugin.Enhance
400
        abstract class AbstractBase implements Target {
401

402
            /**
403
             * The instrumented type.
404
             */
405
            protected final TypeDescription instrumentedType;
406

407
            /**
408
             * The instrumented type's method graph.
409
             */
410
            protected final MethodGraph.Linked methodGraph;
411

412
            /**
413
             * The default method invocation mode to apply.
414
             */
415
            protected final DefaultMethodInvocation defaultMethodInvocation;
416

417
            /**
418
             * Creates a new implementation target.
419
             *
420
             * @param instrumentedType        The instrumented type.
421
             * @param methodGraph             The instrumented type's method graph.
422
             * @param defaultMethodInvocation The default method invocation mode to apply.
423
             */
424
            protected AbstractBase(TypeDescription instrumentedType, MethodGraph.Linked methodGraph, DefaultMethodInvocation defaultMethodInvocation) {
1✔
425
                this.instrumentedType = instrumentedType;
1✔
426
                this.methodGraph = methodGraph;
1✔
427
                this.defaultMethodInvocation = defaultMethodInvocation;
1✔
428
            }
1✔
429

430
            /**
431
             * {@inheritDoc}
432
             */
433
            public TypeDescription getInstrumentedType() {
434
                return instrumentedType;
1✔
435
            }
436

437
            /**
438
             * {@inheritDoc}
439
             */
440
            public SpecialMethodInvocation invokeDefault(MethodDescription.SignatureToken token) {
441
                SpecialMethodInvocation specialMethodInvocation = SpecialMethodInvocation.Illegal.INSTANCE;
1✔
442
                for (TypeDescription interfaceType : instrumentedType.getInterfaces().asErasures()) {
1✔
443
                    SpecialMethodInvocation invocation = invokeDefault(token, interfaceType).withCheckedCompatibilityTo(token.asTypeToken());
1✔
444
                    if (invocation.isValid()) {
1✔
445
                        if (specialMethodInvocation.isValid()) {
1✔
446
                            return SpecialMethodInvocation.Illegal.INSTANCE;
1✔
447
                        } else {
448
                            specialMethodInvocation = invocation;
1✔
449
                        }
450
                    }
451
                }
1✔
452
                return specialMethodInvocation;
1✔
453
            }
454

455
            /**
456
             * {@inheritDoc}
457
             */
458
            public SpecialMethodInvocation invokeDefault(MethodDescription.SignatureToken token, TypeDescription targetType) {
459
                return defaultMethodInvocation.apply(methodGraph.getInterfaceGraph(targetType).locate(token), targetType);
1✔
460
            }
461

462
            /**
463
             * {@inheritDoc}
464
             */
465
            public SpecialMethodInvocation invokeDominant(MethodDescription.SignatureToken token) {
466
                SpecialMethodInvocation specialMethodInvocation = invokeSuper(token);
1✔
467
                return specialMethodInvocation.isValid()
1✔
468
                        ? specialMethodInvocation
469
                        : invokeDefault(token);
1✔
470
            }
471

472
            /**
473
             * Determines if default method invocations are possible.
474
             */
475
            protected enum DefaultMethodInvocation {
1✔
476

477
                /**
478
                 * Permits default method invocations, if an interface declaring a default method is possible.
479
                 */
480
                ENABLED {
1✔
481
                    @Override
482
                    protected SpecialMethodInvocation apply(MethodGraph.Node node, TypeDescription targetType) {
483
                        return node.getSort().isUnique()
1✔
484
                                ? SpecialMethodInvocation.Simple.of(node.getRepresentative(), targetType)
1✔
485
                                : SpecialMethodInvocation.Illegal.INSTANCE;
486
                    }
487
                },
488

489
                /**
490
                 * Does not permit default method invocations.
491
                 */
492
                DISABLED {
1✔
493
                    @Override
494
                    protected SpecialMethodInvocation apply(MethodGraph.Node node, TypeDescription targetType) {
495
                        return SpecialMethodInvocation.Illegal.INSTANCE;
1✔
496
                    }
497
                };
498

499
                /**
500
                 * Resolves a default method invocation depending on the class file version permitting such calls.
501
                 *
502
                 * @param classFileVersion The class file version to resolve for.
503
                 * @return A suitable default method invocation mode.
504
                 */
505
                public static DefaultMethodInvocation of(ClassFileVersion classFileVersion) {
506
                    return classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
1✔
507
                            ? ENABLED
508
                            : DISABLED;
509
                }
510

511
                /**
512
                 * Resolves a default method invocation for a given node.
513
                 *
514
                 * @param node       The node representing the default method call.
515
                 * @param targetType The target type defining the default method.
516
                 * @return A suitable special method invocation.
517
                 */
518
                protected abstract SpecialMethodInvocation apply(MethodGraph.Node node, TypeDescription targetType);
519
            }
520
        }
521
    }
522

523
    /**
524
     * The context for an implementation application. An implementation context represents a mutable data structure
525
     * where any registration is irrevocable. Calling methods on an implementation context should be considered equally
526
     * sensitive as calling a {@link org.objectweb.asm.MethodVisitor}. As such, an implementation context and a
527
     * {@link org.objectweb.asm.MethodVisitor} are complementary for creating an new Java type.
528
     */
529
    interface Context extends MethodAccessorFactory {
530

531
        /**
532
         * Registers an auxiliary type as required for the current implementation. Registering a type will cause the
533
         * creation of this type even if this type is not effectively used for the current implementation.
534
         *
535
         * @param auxiliaryType The auxiliary type that is required for the current implementation.
536
         * @return A description of the registered auxiliary type.
537
         */
538
        TypeDescription register(AuxiliaryType auxiliaryType);
539

540
        /**
541
         * Caches a single value by storing it in form of a {@code private}, {@code final} and {@code static} field.
542
         * By caching values, expensive instance creations can be avoided and object identity can be preserved.
543
         * The field is initiated in a generated class's static initializer.
544
         *
545
         * @param fieldValue A stack manipulation for creating the value that is to be cached in a {@code static} field.
546
         *                   After executing the stack manipulation, exactly one value must be put onto the operand
547
         *                   stack which is assignable to the given {@code fieldType}.
548
         * @param fieldType  The type of the field for storing the cached value. This field's type determines the value
549
         *                   that is put onto the operand stack by this method's returned stack manipulation.
550
         * @return A description of a field that was defined on the instrumented type which contains the given value.
551
         */
552
        FieldDescription.InDefinedShape cache(StackManipulation fieldValue, TypeDescription fieldType);
553

554
        /**
555
         * Returns the instrumented type of the current implementation. The instrumented type is exposed with the intend of allowing optimal
556
         * byte code generation and not for implementing checks or changing the behavior of a {@link StackManipulation}.
557
         *
558
         * @return The instrumented type of the current implementation.
559
         */
560
        TypeDescription getInstrumentedType();
561

562
        /**
563
         * Returns the class file version of the currently creatgetClassFileVersioned dynamic type.
564
         *
565
         * @return The class file version of the currently created dynamic type.
566
         */
567
        ClassFileVersion getClassFileVersion();
568

569
        /**
570
         * Returns {@code true} if the explicit generation of stack map frames is expected.
571
         *
572
         * @return {@code true} if the explicit generation of stack map frames is expected.
573
         */
574
        FrameGeneration getFrameGeneration();
575

576
        /**
577
         * Indicates the frame generation being applied.
578
         */
579
        enum FrameGeneration {
1✔
580

581
            /**
582
             * Indicates that frames should be generated.
583
             */
584
            GENERATE(true) {
1✔
585
                @Override
586
                public void generate(MethodVisitor methodVisitor,
587
                                     int type,
588
                                     int stackCount,
589
                                     @MaybeNull Object[] stack,
590
                                     int changedLocalVariableCount,
591
                                     @MaybeNull Object[] changedLocalVariable,
592
                                     int fullLocalVariableCount,
593
                                     @MaybeNull Object[] fullLocalVariable) {
594
                    methodVisitor.visitFrame(type, changedLocalVariableCount, changedLocalVariable, stackCount, stack);
1✔
595
                }
1✔
596
            },
597

598
            /**
599
             * Indicates that frames should be generated and expanded.
600
             */
601
            EXPAND(true) {
1✔
602
                @Override
603
                public void generate(MethodVisitor methodVisitor,
604
                                     int type,
605
                                     int stackCount,
606
                                     @MaybeNull Object[] stack,
607
                                     int changedLocalVariableCount,
608
                                     @MaybeNull Object[] changedLocalVariable,
609
                                     int fullLocalVariableCount,
610
                                     @MaybeNull Object[] fullLocalVariable) {
611
                    methodVisitor.visitFrame(Opcodes.F_NEW, fullLocalVariableCount, fullLocalVariable, stackCount, stack);
1✔
612
                }
1✔
613
            },
614

615
            /**
616
             * Indicates that no frames should be generated.
617
             */
618
            DISABLED(false) {
1✔
619
                @Override
620
                public void generate(MethodVisitor methodVisitor,
621
                                     int type,
622
                                     int stackCount,
623
                                     @MaybeNull Object[] stack,
624
                                     int changedLocalVariableCount,
625
                                     @MaybeNull Object[] changedLocalVariable,
626
                                     int fullLocalVariableCount,
627
                                     @MaybeNull Object[] fullLocalVariable) {
628
                    /* do nothing */
629
                }
1✔
630
            };
631

632
            /**
633
             * An empty array to reuse for empty frames.
634
             */
635
            private static final Object[] EMPTY = new Object[0];
1✔
636

637
            /**
638
             * {@code true} if frames should be generated.
639
             */
640
            private final boolean active;
641

642
            /**
643
             * Creates a new frame generation type.
644
             *
645
             * @param active {@code true} if frames should be generated.
646
             */
647
            FrameGeneration(boolean active) {
1✔
648
                this.active = active;
1✔
649
            }
1✔
650

651
            /**
652
             * Returns {@code true} if frames should be generated.
653
             *
654
             * @return {@code true} if frames should be generated.
655
             */
656
            public boolean isActive() {
657
                return active;
1✔
658
            }
659

660
            /**
661
             * Inserts a {@link Opcodes#F_SAME} frame.
662
             *
663
             * @param methodVisitor  The method visitor to write to.
664
             * @param localVariables The local variables that are defined at this frame location.
665
             */
666
            public void same(MethodVisitor methodVisitor,
667
                             List<? extends TypeDefinition> localVariables) {
668
                generate(methodVisitor,
1✔
669
                        Opcodes.F_SAME,
670
                        EMPTY.length,
671
                        EMPTY,
672
                        EMPTY.length,
673
                        EMPTY,
674
                        localVariables.size(),
1✔
675
                        toStackMapFrames(localVariables));
1✔
676
            }
1✔
677

678
            /**
679
             * Inserts a {@link Opcodes#F_SAME1} frame.
680
             *
681
             * @param methodVisitor  The method visitor to write to.
682
             * @param stackValue     The single stack value.
683
             * @param localVariables The local variables that are defined at this frame location.
684
             */
685
            public void same1(MethodVisitor methodVisitor,
686
                              TypeDefinition stackValue,
687
                              List<? extends TypeDefinition> localVariables) {
688
                generate(methodVisitor,
1✔
689
                        Opcodes.F_SAME1,
690
                        1,
691
                        new Object[]{toStackMapFrame(stackValue)},
1✔
692
                        EMPTY.length,
693
                        EMPTY,
694
                        localVariables.size(),
1✔
695
                        toStackMapFrames(localVariables));
1✔
696
            }
1✔
697

698
            /**
699
             * Inserts a {@link Opcodes#F_APPEND} frame.
700
             *
701
             * @param methodVisitor  The method visitor to write to.
702
             * @param appended       The appended local variables.
703
             * @param localVariables The local variables that are defined at this frame location, excluding the ones appended.
704
             */
705
            public void append(MethodVisitor methodVisitor,
706
                               List<? extends TypeDefinition> appended,
707
                               List<? extends TypeDefinition> localVariables) {
708
                generate(methodVisitor,
1✔
709
                        Opcodes.F_APPEND,
710
                        EMPTY.length,
711
                        EMPTY,
712
                        appended.size(),
1✔
713
                        toStackMapFrames(appended),
1✔
714
                        localVariables.size() + appended.size(),
1✔
715
                        toStackMapFrames(CompoundList.of(localVariables, appended)));
1✔
716
            }
1✔
717

718
            /**
719
             * Inserts a {@link Opcodes#F_CHOP} frame.
720
             *
721
             * @param methodVisitor  The method visitor to write to.
722
             * @param chopped        The number of chopped values.
723
             * @param localVariables The local variables that are defined at this frame location, excluding the chopped variables.
724
             */
725
            public void chop(MethodVisitor methodVisitor,
726
                             int chopped,
727
                             List<? extends TypeDefinition> localVariables) {
728
                generate(methodVisitor,
1✔
729
                        Opcodes.F_CHOP,
730
                        EMPTY.length,
731
                        EMPTY,
732
                        chopped,
733
                        EMPTY,
734
                        localVariables.size(),
1✔
735
                        toStackMapFrames(localVariables));
1✔
736
            }
1✔
737

738
            /**
739
             * Inserts a {@link Opcodes#F_FULL} frame.
740
             *
741
             * @param methodVisitor  The method visitor to write to.
742
             * @param stackValues    The values on the operand stack.
743
             * @param localVariables The local variables that are defined at this frame location.
744
             */
745
            public void full(MethodVisitor methodVisitor,
746
                             List<? extends TypeDefinition> stackValues,
747
                             List<? extends TypeDefinition> localVariables) {
748
                generate(methodVisitor,
1✔
749
                        Opcodes.F_FULL,
750
                        stackValues.size(),
1✔
751
                        toStackMapFrames(stackValues),
1✔
752
                        localVariables.size(),
1✔
753
                        toStackMapFrames(localVariables),
1✔
754
                        localVariables.size(),
1✔
755
                        toStackMapFrames(localVariables));
1✔
756
            }
1✔
757

758
            /**
759
             * Writes frames to a {@link MethodVisitor}, if applicable.
760
             *
761
             * @param methodVisitor             The method visitor to use
762
             * @param type                      The frame type.
763
             * @param stackCount                The number of values on the operand stack.
764
             * @param stack                     The values on the operand stack up to {@code stackCount}, or {@code null}, if none.
765
             * @param changedLocalVariableCount The number of local variables that were changed.
766
             * @param changedLocalVariable      The values added to the local variable array up to {@code changedLocalVariableCount}
767
             *                                  or {@code null}, if none or not applicable.
768
             * @param fullLocalVariableCount    The number of local variables.
769
             * @param fullLocalVariable         The total number of local variables up to {@code fullLocalVariableCount} or
770
             *                                  {@code null}, if none.
771
             */
772
            protected abstract void generate(MethodVisitor methodVisitor,
773
                                             int type,
774
                                             int stackCount,
775
                                             @MaybeNull Object[] stack,
776
                                             int changedLocalVariableCount,
777
                                             @MaybeNull Object[] changedLocalVariable,
778
                                             int fullLocalVariableCount,
779
                                             @MaybeNull Object[] fullLocalVariable);
780

781
            private static Object[] toStackMapFrames(List<? extends TypeDefinition> typeDefinitions) {
782
                Object[] value = typeDefinitions.isEmpty() ? EMPTY : new Object[typeDefinitions.size()];
1✔
783
                for (int index = 0; index < typeDefinitions.size(); index++) {
1✔
784
                    value[index] = toStackMapFrame(typeDefinitions.get(index));
1✔
785
                }
786
                return value;
1✔
787
            }
788

789
            private static Object toStackMapFrame(TypeDefinition typeDefinition) {
790
                if (typeDefinition.represents(boolean.class)
1✔
791
                        || typeDefinition.represents(byte.class)
1✔
792
                        || typeDefinition.represents(short.class)
1✔
793
                        || typeDefinition.represents(char.class)
1✔
794
                        || typeDefinition.represents(int.class)) {
1✔
795
                    return Opcodes.INTEGER;
1✔
796
                } else if (typeDefinition.represents(long.class)) {
1✔
797
                    return Opcodes.LONG;
×
798
                } else if (typeDefinition.represents(float.class)) {
1✔
799
                    return Opcodes.FLOAT;
×
800
                } else if (typeDefinition.represents(double.class)) {
1✔
801
                    return Opcodes.DOUBLE;
×
802
                } else {
803
                    return typeDefinition.asErasure().getInternalName();
1✔
804
                }
805
            }
806
        }
807

808
        /**
809
         * Represents an extractable view of an {@link Implementation.Context} which
810
         * allows the retrieval of any registered auxiliary type.
811
         */
812
        interface ExtractableView extends Context {
813

814
            /**
815
             * Returns {@code true} if this implementation context permits the registration of any implicit type initializers.
816
             *
817
             * @return {@code true} if this implementation context permits the registration of any implicit type initializers.
818
             */
819
            boolean isEnabled();
820

821
            /**
822
             * Returns any {@link net.bytebuddy.implementation.auxiliary.AuxiliaryType} that was registered
823
             * with this {@link Implementation.Context}.
824
             *
825
             * @return A list of all manifested registered auxiliary types.
826
             */
827
            List<DynamicType> getAuxiliaryTypes();
828

829
            /**
830
             * Writes any information that was registered with an {@link Implementation.Context}
831
             * to the provided class visitor. This contains any fields for value caching, any accessor method and it
832
             * writes the type initializer. The type initializer must therefore never be written manually.
833
             *
834
             * @param drain                        The drain to write the type initializer to.
835
             * @param classVisitor                 The class visitor to which the extractable view is to be written.
836
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotation.
837
             */
838
            void drain(TypeInitializer.Drain drain, ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
839

840
            /**
841
             * An abstract base implementation of an extractable view of an implementation context.
842
             */
843
            @HashCodeAndEqualsPlugin.Enhance
844
            abstract class AbstractBase implements ExtractableView {
845

846
                /**
847
                 * The instrumented type.
848
                 */
849
                protected final TypeDescription instrumentedType;
850

851
                /**
852
                 * The class file version of the dynamic type.
853
                 */
854
                protected final ClassFileVersion classFileVersion;
855

856
                /**
857
                 * Determines the frame generation to be applied.
858
                 */
859
                protected final FrameGeneration frameGeneration;
860

861
                /**
862
                 * Create a new extractable view.
863
                 *
864
                 * @param instrumentedType The instrumented type.
865
                 * @param classFileVersion The class file version of the dynamic type.
866
                 * @param frameGeneration  Determines the frame generation to be applied.
867
                 */
868
                protected AbstractBase(TypeDescription instrumentedType, ClassFileVersion classFileVersion, FrameGeneration frameGeneration) {
1✔
869
                    this.instrumentedType = instrumentedType;
1✔
870
                    this.classFileVersion = classFileVersion;
1✔
871
                    this.frameGeneration = frameGeneration;
1✔
872
                }
1✔
873

874
                /**
875
                 * {@inheritDoc}
876
                 */
877
                public TypeDescription getInstrumentedType() {
878
                    return instrumentedType;
1✔
879
                }
880

881
                /**
882
                 * {@inheritDoc}
883
                 */
884
                public ClassFileVersion getClassFileVersion() {
885
                    return classFileVersion;
1✔
886
                }
887

888
                /**
889
                 * {@inheritDoc}
890
                 */
891
                public FrameGeneration getFrameGeneration() {
892
                    return frameGeneration;
1✔
893
                }
894
            }
895
        }
896

897
        /**
898
         * A factory for creating a new implementation context.
899
         */
900
        interface Factory {
901

902
            /**
903
             * Creates a new implementation context.
904
             *
905
             * @param instrumentedType            The description of the type that is currently subject of creation.
906
             * @param auxiliaryTypeNamingStrategy The naming strategy for naming an auxiliary type.
907
             * @param typeInitializer             The type initializer of the created instrumented type.
908
             * @param classFileVersion            The class file version of the created class.
909
             * @param auxiliaryClassFileVersion   The class file version of any auxiliary classes.
910
             * @return An implementation context in its extractable view.
911
             * @deprecated Use {@link Implementation.Context.Factory#make(TypeDescription, AuxiliaryType.NamingStrategy, TypeInitializer, ClassFileVersion, ClassFileVersion, Implementation.Context.FrameGeneration)}.
912
             */
913
            @Deprecated
914
            ExtractableView make(TypeDescription instrumentedType,
915
                                 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
916
                                 TypeInitializer typeInitializer,
917
                                 ClassFileVersion classFileVersion,
918
                                 ClassFileVersion auxiliaryClassFileVersion);
919

920
            /**
921
             * Creates a new implementation context.
922
             *
923
             * @param instrumentedType            The description of the type that is currently subject of creation.
924
             * @param auxiliaryTypeNamingStrategy The naming strategy for naming an auxiliary type.
925
             * @param typeInitializer             The type initializer of the created instrumented type.
926
             * @param classFileVersion            The class file version of the created class.
927
             * @param auxiliaryClassFileVersion   The class file version of any auxiliary classes.
928
             * @param frameGeneration             Indicates the frame generation being applied.
929
             * @return An implementation context in its extractable view.
930
             */
931
            ExtractableView make(TypeDescription instrumentedType,
932
                                 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
933
                                 TypeInitializer typeInitializer,
934
                                 ClassFileVersion classFileVersion,
935
                                 ClassFileVersion auxiliaryClassFileVersion,
936
                                 FrameGeneration frameGeneration);
937
        }
938

939
        /**
940
         * An implementation context that does not allow for any injections into the static initializer block. This can be useful when
941
         * redefining a class when it is not allowed to add methods to a class what is an implicit requirement when copying the static
942
         * initializer block into another method.
943
         */
944
        class Disabled extends ExtractableView.AbstractBase {
945

946
            /**
947
             * Creates a new disabled implementation context.
948
             *
949
             * @param instrumentedType The instrumented type.
950
             * @param classFileVersion The class file version to create the class in.
951
             * @param frameGeneration  Determines the frame generation to be applied.
952
             */
953
            protected Disabled(TypeDescription instrumentedType, ClassFileVersion classFileVersion, FrameGeneration frameGeneration) {
954
                super(instrumentedType, classFileVersion, frameGeneration);
1✔
955
            }
1✔
956

957
            /**
958
             * {@inheritDoc}
959
             */
960
            public boolean isEnabled() {
961
                return false;
1✔
962
            }
963

964
            /**
965
             * {@inheritDoc}
966
             */
967
            public List<DynamicType> getAuxiliaryTypes() {
968
                return Collections.emptyList();
1✔
969
            }
970

971
            /**
972
             * {@inheritDoc}
973
             */
974
            public void drain(TypeInitializer.Drain drain, ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
975
                drain.apply(classVisitor, TypeInitializer.None.INSTANCE, this);
1✔
976
            }
1✔
977

978
            /**
979
             * {@inheritDoc}
980
             */
981
            public TypeDescription register(AuxiliaryType auxiliaryType) {
982
                throw new IllegalStateException("Registration of auxiliary types was disabled: " + auxiliaryType);
1✔
983
            }
984

985
            /**
986
             * {@inheritDoc}
987
             */
988
            public MethodDescription.InDefinedShape registerAccessorFor(SpecialMethodInvocation specialMethodInvocation, AccessType accessType) {
989
                throw new IllegalStateException("Registration of method accessors was disabled: " + specialMethodInvocation.getMethodDescription());
1✔
990
            }
991

992
            /**
993
             * {@inheritDoc}
994
             */
995
            public MethodDescription.InDefinedShape registerGetterFor(FieldDescription fieldDescription, AccessType accessType) {
996
                throw new IllegalStateException("Registration of field accessor was disabled: " + fieldDescription);
1✔
997
            }
998

999
            /**
1000
             * {@inheritDoc}
1001
             */
1002
            public MethodDescription.InDefinedShape registerSetterFor(FieldDescription fieldDescription, AccessType accessType) {
1003
                throw new IllegalStateException("Registration of field accessor was disabled: " + fieldDescription);
1✔
1004
            }
1005

1006
            /**
1007
             * {@inheritDoc}
1008
             */
1009
            public FieldDescription.InDefinedShape cache(StackManipulation fieldValue, TypeDescription fieldType) {
1010
                throw new IllegalStateException("Field values caching was disabled: " + fieldType);
1✔
1011
            }
1012

1013
            /**
1014
             * A factory for creating a {@link net.bytebuddy.implementation.Implementation.Context.Disabled}.
1015
             */
1016
            public enum Factory implements Context.Factory {
1✔
1017

1018
                /**
1019
                 * The singleton instance.
1020
                 */
1021
                INSTANCE;
1✔
1022

1023
                /**
1024
                 * {@inheritDoc}
1025
                 */
1026
                @Deprecated
1027
                public ExtractableView make(TypeDescription instrumentedType,
1028
                                            AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1029
                                            TypeInitializer typeInitializer,
1030
                                            ClassFileVersion classFileVersion,
1031
                                            ClassFileVersion auxiliaryClassFileVersion) {
1032
                    return make(instrumentedType,
×
1033
                            auxiliaryTypeNamingStrategy,
1034
                            typeInitializer,
1035
                            classFileVersion,
1036
                            auxiliaryClassFileVersion,
1037
                            classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
×
1038
                                    ? FrameGeneration.GENERATE
1039
                                    : FrameGeneration.DISABLED);
1040
                }
1041

1042
                /**
1043
                 * {@inheritDoc}
1044
                 */
1045
                public ExtractableView make(TypeDescription instrumentedType,
1046
                                            AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1047
                                            TypeInitializer typeInitializer,
1048
                                            ClassFileVersion classFileVersion,
1049
                                            ClassFileVersion auxiliaryClassFileVersion,
1050
                                            FrameGeneration frameGeneration) {
1051
                    if (typeInitializer.isDefined()) {
1✔
1052
                        throw new IllegalStateException("Cannot define type initializer which was explicitly disabled: " + typeInitializer);
1✔
1053
                    }
1054
                    return new Disabled(instrumentedType, classFileVersion, frameGeneration);
1✔
1055
                }
1056
            }
1057
        }
1058

1059
        /**
1060
         * A default implementation of an {@link Implementation.Context.ExtractableView}
1061
         * which serves as its own {@link MethodAccessorFactory}.
1062
         */
1063
        class Default extends ExtractableView.AbstractBase {
1064

1065
            /**
1066
             * The name suffix to be appended to an accessor method.
1067
             */
1068
            public static final String ACCESSOR_METHOD_SUFFIX = "accessor";
1069

1070
            /**
1071
             * The name prefix to be prepended to a field storing a cached value.
1072
             */
1073
            public static final String FIELD_CACHE_PREFIX = "cachedValue";
1074

1075
            /**
1076
             * The naming strategy for naming auxiliary types that are registered.
1077
             */
1078
            private final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
1079

1080
            /**
1081
             * The type initializer of the created instrumented type.
1082
             */
1083
            private final TypeInitializer typeInitializer;
1084

1085
            /**
1086
             * The class file version to use for auxiliary classes.
1087
             */
1088
            private final ClassFileVersion auxiliaryClassFileVersion;
1089

1090
            /**
1091
             * A mapping of special method invocations to their accessor methods that each invoke their mapped invocation.
1092
             */
1093
            private final Map<SpecialMethodInvocation, DelegationRecord> registeredAccessorMethods;
1094

1095
            /**
1096
             * The registered getters.
1097
             */
1098
            private final Map<FieldDescription, DelegationRecord> registeredGetters;
1099

1100
            /**
1101
             * The registered setters.
1102
             */
1103
            private final Map<FieldDescription, DelegationRecord> registeredSetters;
1104

1105
            /**
1106
             * A map of registered auxiliary types to their dynamic type representation.
1107
             */
1108
            private final Map<AuxiliaryType, DynamicType> auxiliaryTypes;
1109

1110
            /**
1111
             * A map of already registered field caches to their field representation.
1112
             */
1113
            private final Map<FieldCacheEntry, FieldDescription.InDefinedShape> registeredFieldCacheEntries;
1114

1115
            /**
1116
             * A set of registered field cache entries.
1117
             */
1118
            private final Set<FieldDescription.InDefinedShape> registeredFieldCacheFields;
1119

1120
            /**
1121
             * The suffix to append to the names of accessor methods.
1122
             */
1123
            private final String suffix;
1124

1125
            /**
1126
             * If {@code false}, the type initializer for this instance was already drained what prohibits the registration of additional cached field values.
1127
             */
1128
            private boolean fieldCacheCanAppendEntries;
1129

1130
            /**
1131
             * Creates a new default implementation context.
1132
             *
1133
             * @param instrumentedType            The description of the type that is currently subject of creation.
1134
             * @param classFileVersion            The class file version of the created class.
1135
             * @param auxiliaryTypeNamingStrategy The naming strategy for naming an auxiliary type.
1136
             * @param typeInitializer             The type initializer of the created instrumented type.
1137
             * @param auxiliaryClassFileVersion   The class file version to use for auxiliary classes.
1138
             * @param frameGeneration             Determines the frame generation to be applied.
1139
             * @param suffix                      The suffix to append to the names of accessor methods.
1140
             */
1141
            protected Default(TypeDescription instrumentedType,
1142
                              ClassFileVersion classFileVersion,
1143
                              AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1144
                              TypeInitializer typeInitializer,
1145
                              ClassFileVersion auxiliaryClassFileVersion,
1146
                              FrameGeneration frameGeneration,
1147
                              String suffix) {
1148
                super(instrumentedType, classFileVersion, frameGeneration);
1✔
1149
                this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
1✔
1150
                this.typeInitializer = typeInitializer;
1✔
1151
                this.auxiliaryClassFileVersion = auxiliaryClassFileVersion;
1✔
1152
                this.suffix = suffix;
1✔
1153
                registeredAccessorMethods = new HashMap<SpecialMethodInvocation, DelegationRecord>();
1✔
1154
                registeredGetters = new HashMap<FieldDescription, DelegationRecord>();
1✔
1155
                registeredSetters = new HashMap<FieldDescription, DelegationRecord>();
1✔
1156
                auxiliaryTypes = new HashMap<AuxiliaryType, DynamicType>();
1✔
1157
                registeredFieldCacheEntries = new HashMap<FieldCacheEntry, FieldDescription.InDefinedShape>();
1✔
1158
                registeredFieldCacheFields = new HashSet<FieldDescription.InDefinedShape>();
1✔
1159
                fieldCacheCanAppendEntries = true;
1✔
1160
            }
1✔
1161

1162
            /**
1163
             * {@inheritDoc}
1164
             */
1165
            public boolean isEnabled() {
1166
                return true;
1✔
1167
            }
1168

1169
            /**
1170
             * {@inheritDoc}
1171
             */
1172
            public MethodDescription.InDefinedShape registerAccessorFor(SpecialMethodInvocation specialMethodInvocation, AccessType accessType) {
1173
                DelegationRecord record = registeredAccessorMethods.get(specialMethodInvocation);
1✔
1174
                record = record == null
1✔
1175
                        ? new AccessorMethodDelegation(instrumentedType, suffix, accessType, specialMethodInvocation)
1176
                        : record.with(accessType);
1✔
1177
                registeredAccessorMethods.put(specialMethodInvocation, record);
1✔
1178
                return record.getMethod();
1✔
1179
            }
1180

1181
            /**
1182
             * {@inheritDoc}
1183
             */
1184
            public MethodDescription.InDefinedShape registerGetterFor(FieldDescription fieldDescription, AccessType accessType) {
1185
                DelegationRecord record = registeredGetters.get(fieldDescription);
1✔
1186
                record = record == null
1✔
1187
                        ? new FieldGetterDelegation(instrumentedType, suffix, accessType, fieldDescription)
1188
                        : record.with(accessType);
1✔
1189
                registeredGetters.put(fieldDescription, record);
1✔
1190
                return record.getMethod();
1✔
1191
            }
1192

1193
            /**
1194
             * {@inheritDoc}
1195
             */
1196
            public MethodDescription.InDefinedShape registerSetterFor(FieldDescription fieldDescription, AccessType accessType) {
1197
                DelegationRecord record = registeredSetters.get(fieldDescription);
1✔
1198
                record = record == null
1✔
1199
                        ? new FieldSetterDelegation(instrumentedType, suffix, accessType, fieldDescription)
1200
                        : record.with(accessType);
1✔
1201
                registeredSetters.put(fieldDescription, record);
1✔
1202
                return record.getMethod();
1✔
1203
            }
1204

1205
            /**
1206
             * {@inheritDoc}
1207
             */
1208
            public TypeDescription register(AuxiliaryType auxiliaryType) {
1209
                DynamicType dynamicType = auxiliaryTypes.get(auxiliaryType);
1✔
1210
                if (dynamicType == null) {
1✔
1211
                    dynamicType = auxiliaryType.make(auxiliaryTypeNamingStrategy.name(instrumentedType, auxiliaryType),
1✔
1212
                            auxiliaryClassFileVersion,
1213
                            this);
1214
                    auxiliaryTypes.put(auxiliaryType, dynamicType);
1✔
1215
                }
1216
                return dynamicType.getTypeDescription();
1✔
1217
            }
1218

1219
            /**
1220
             * {@inheritDoc}
1221
             */
1222
            public List<DynamicType> getAuxiliaryTypes() {
1223
                return new ArrayList<DynamicType>(auxiliaryTypes.values());
1✔
1224
            }
1225

1226
            /**
1227
             * {@inheritDoc}
1228
             */
1229
            public FieldDescription.InDefinedShape cache(StackManipulation fieldValue, TypeDescription fieldType) {
1230
                FieldCacheEntry fieldCacheEntry = new FieldCacheEntry(fieldValue, fieldType);
1✔
1231
                FieldDescription.InDefinedShape fieldCache = registeredFieldCacheEntries.get(fieldCacheEntry);
1✔
1232
                if (fieldCache != null) {
1✔
1233
                    return fieldCache;
1✔
1234
                }
1235
                if (!fieldCacheCanAppendEntries) {
1✔
1236
                    throw new IllegalStateException("Cached values cannot be registered after defining the type initializer for " + instrumentedType);
1✔
1237
                }
1238
                int hashCode = fieldValue.hashCode();
1✔
1239
                do {
1240
                    fieldCache = new CacheValueField(instrumentedType, fieldType.asGenericType(), suffix, hashCode++);
1✔
1241
                } while (!registeredFieldCacheFields.add(fieldCache));
1✔
1242
                registeredFieldCacheEntries.put(fieldCacheEntry, fieldCache);
1✔
1243
                return fieldCache;
1✔
1244
            }
1245

1246
            /**
1247
             * {@inheritDoc}
1248
             */
1249
            public void drain(TypeInitializer.Drain drain,
1250
                              ClassVisitor classVisitor,
1251
                              AnnotationValueFilter.Factory annotationValueFilterFactory) {
1252
                fieldCacheCanAppendEntries = false;
1✔
1253
                TypeInitializer typeInitializer = this.typeInitializer;
1✔
1254
                for (Map.Entry<FieldCacheEntry, FieldDescription.InDefinedShape> entry : registeredFieldCacheEntries.entrySet()) {
1✔
1255
                    FieldVisitor fieldVisitor = classVisitor.visitField(entry.getValue().getModifiers(),
1✔
1256
                            entry.getValue().getInternalName(),
1✔
1257
                            entry.getValue().getDescriptor(),
1✔
1258
                            entry.getValue().getGenericSignature(),
1✔
1259
                            FieldDescription.NO_DEFAULT_VALUE);
1260
                    if (fieldVisitor != null) {
1✔
1261
                        fieldVisitor.visitEnd();
1✔
1262
                        typeInitializer = typeInitializer.expandWith(entry.getKey().storeIn(entry.getValue()));
1✔
1263
                    }
1264
                }
1✔
1265
                drain.apply(classVisitor, typeInitializer, this);
1✔
1266
                for (TypeWriter.MethodPool.Record record : registeredAccessorMethods.values()) {
1✔
1267
                    record.apply(classVisitor, this, annotationValueFilterFactory);
1✔
1268
                }
1✔
1269
                for (TypeWriter.MethodPool.Record record : registeredGetters.values()) {
1✔
1270
                    record.apply(classVisitor, this, annotationValueFilterFactory);
1✔
1271
                }
1✔
1272
                for (TypeWriter.MethodPool.Record record : registeredSetters.values()) {
1✔
1273
                    record.apply(classVisitor, this, annotationValueFilterFactory);
1✔
1274
                }
1✔
1275
            }
1✔
1276

1277
            /**
1278
             * A description of a field that stores a cached value.
1279
             */
1280
            protected static class CacheValueField extends FieldDescription.InDefinedShape.AbstractBase {
1281

1282
                /**
1283
                 * The instrumented type.
1284
                 */
1285
                private final TypeDescription instrumentedType;
1286

1287
                /**
1288
                 * The type of the cache's field.
1289
                 */
1290
                private final TypeDescription.Generic fieldType;
1291

1292
                /**
1293
                 * The name of the field.
1294
                 */
1295
                private final String name;
1296

1297
                /**
1298
                 * Creates a new cache value field.
1299
                 *
1300
                 * @param instrumentedType The instrumented type.
1301
                 * @param fieldType        The type of the cache's field.
1302
                 * @param suffix           The suffix to use for the cache field's name.
1303
                 * @param hashCode         The hash value of the field's value for creating a unique field name.
1304
                 */
1305
                protected CacheValueField(TypeDescription instrumentedType, TypeDescription.Generic fieldType, String suffix, int hashCode) {
1✔
1306
                    this.instrumentedType = instrumentedType;
1✔
1307
                    this.fieldType = fieldType;
1✔
1308
                    name = FIELD_CACHE_PREFIX + "$" + suffix + "$" + RandomString.hashOf(hashCode);
1✔
1309
                }
1✔
1310

1311
                /**
1312
                 * {@inheritDoc}
1313
                 */
1314
                public TypeDescription.Generic getType() {
1315
                    return fieldType;
1✔
1316
                }
1317

1318
                /**
1319
                 * {@inheritDoc}
1320
                 */
1321
                public AnnotationList getDeclaredAnnotations() {
1322
                    return new AnnotationList.Empty();
×
1323
                }
1324

1325
                /**
1326
                 * {@inheritDoc}
1327
                 */
1328
                @Nonnull
1329
                public TypeDescription getDeclaringType() {
1330
                    return instrumentedType;
1✔
1331
                }
1332

1333
                /**
1334
                 * {@inheritDoc}
1335
                 */
1336
                public int getModifiers() {
1337
                    return Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC | (instrumentedType.isInterface()
1✔
1338
                            ? Opcodes.ACC_PUBLIC
1339
                            : Opcodes.ACC_PRIVATE);
1340
                }
1341

1342
                /**
1343
                 * {@inheritDoc}
1344
                 */
1345
                public String getName() {
1346
                    return name;
1✔
1347
                }
1348
            }
1349

1350
            /**
1351
             * A field cache entry for uniquely identifying a cached field. A cached field is described by the stack
1352
             * manipulation that loads the field's value onto the operand stack and the type of the field.
1353
             */
1354
            protected static class FieldCacheEntry implements StackManipulation {
1355

1356
                /**
1357
                 * The field value that is represented by this field cache entry.
1358
                 */
1359
                private final StackManipulation fieldValue;
1360

1361
                /**
1362
                 * The field type that is represented by this field cache entry.
1363
                 */
1364
                private final TypeDescription fieldType;
1365

1366
                /**
1367
                 * Creates a new field cache entry.
1368
                 *
1369
                 * @param fieldValue The field value that is represented by this field cache entry.
1370
                 * @param fieldType  The field type that is represented by this field cache entry.
1371
                 */
1372
                protected FieldCacheEntry(StackManipulation fieldValue, TypeDescription fieldType) {
1✔
1373
                    this.fieldValue = fieldValue;
1✔
1374
                    this.fieldType = fieldType;
1✔
1375
                }
1✔
1376

1377
                /**
1378
                 * Returns a stack manipulation where the represented value is stored in the given field.
1379
                 *
1380
                 * @param fieldDescription A static field in which the value is to be stored.
1381
                 * @return A byte code appender that represents this storage.
1382
                 */
1383
                protected ByteCodeAppender storeIn(FieldDescription fieldDescription) {
1384
                    return new ByteCodeAppender.Simple(this, FieldAccess.forField(fieldDescription).write());
1✔
1385
                }
1386

1387
                /**
1388
                 * Returns the field type that is represented by this field cache entry.
1389
                 *
1390
                 * @return The field type that is represented by this field cache entry.
1391
                 */
1392
                protected TypeDescription getFieldType() {
1393
                    return fieldType;
×
1394
                }
1395

1396
                /**
1397
                 * {@inheritDoc}
1398
                 */
1399
                public boolean isValid() {
1400
                    return fieldValue.isValid();
×
1401
                }
1402

1403
                /**
1404
                 * {@inheritDoc}
1405
                 */
1406
                public Size apply(MethodVisitor methodVisitor, Context implementationContext) {
1407
                    return fieldValue.apply(methodVisitor, implementationContext);
1✔
1408
                }
1409

1410
                @Override
1411
                public int hashCode() {
1412
                    int result = fieldValue.hashCode();
1✔
1413
                    result = 31 * result + fieldType.hashCode();
1✔
1414
                    return result;
1✔
1415
                }
1416

1417
                @Override
1418
                public boolean equals(@MaybeNull Object other) {
1419
                    if (this == other) {
1✔
1420
                        return true;
×
1421
                    } else if (other == null || getClass() != other.getClass()) {
1✔
1422
                        return false;
×
1423
                    }
1424
                    FieldCacheEntry fieldCacheEntry = (FieldCacheEntry) other;
1✔
1425
                    return fieldValue.equals(fieldCacheEntry.fieldValue) && fieldType.equals(fieldCacheEntry.fieldType);
1✔
1426
                }
1427
            }
1428

1429
            /**
1430
             * A base implementation of a method that accesses a property of an instrumented type.
1431
             */
1432
            protected abstract static class AbstractPropertyAccessorMethod extends MethodDescription.InDefinedShape.AbstractBase {
1✔
1433

1434
                /**
1435
                 * {@inheritDoc}
1436
                 */
1437
                public int getModifiers() {
1438
                    return Opcodes.ACC_SYNTHETIC | getBaseModifiers() | (getDeclaringType().isInterface()
1✔
1439
                            ? Opcodes.ACC_PUBLIC
1440
                            : Opcodes.ACC_FINAL);
1441
                }
1442

1443
                /**
1444
                 * Returns the base modifiers, i.e. the modifiers that define the accessed property's features.
1445
                 *
1446
                 * @return Returns the base modifiers of the represented methods.
1447
                 */
1448
                protected abstract int getBaseModifiers();
1449
            }
1450

1451
            /**
1452
             * A description of an accessor method to access another method from outside the instrumented type.
1453
             */
1454
            protected static class AccessorMethod extends AbstractPropertyAccessorMethod {
1455

1456
                /**
1457
                 * The instrumented type.
1458
                 */
1459
                private final TypeDescription instrumentedType;
1460

1461
                /**
1462
                 * The method that is being accessed.
1463
                 */
1464
                private final MethodDescription methodDescription;
1465

1466
                /**
1467
                 * The name of the method.
1468
                 */
1469
                private final String name;
1470

1471
                /**
1472
                 * Creates a new accessor method.
1473
                 *
1474
                 * @param instrumentedType  The instrumented type.
1475
                 * @param methodDescription The method that is being accessed.
1476
                 * @param typeDescription   The targeted type of the accessor method.
1477
                 * @param suffix            The suffix to append to the accessor method's name.
1478
                 */
1479
                protected AccessorMethod(TypeDescription instrumentedType,
1480
                                         MethodDescription methodDescription,
1481
                                         TypeDescription typeDescription,
1482
                                         String suffix) {
1✔
1483
                    this.instrumentedType = instrumentedType;
1✔
1484
                    this.methodDescription = methodDescription;
1✔
1485
                    name = methodDescription.getInternalName()
1✔
1486
                            + "$" + ACCESSOR_METHOD_SUFFIX
1487
                            + "$" + suffix
1488
                            + (typeDescription.isInterface() ? "$" + RandomString.hashOf(typeDescription.hashCode()) : "");
1✔
1489
                }
1✔
1490

1491
                /**
1492
                 * {@inheritDoc}
1493
                 */
1494
                public TypeDescription.Generic getReturnType() {
1495
                    return methodDescription.getReturnType().asRawType();
1✔
1496
                }
1497

1498
                /**
1499
                 * {@inheritDoc}
1500
                 */
1501
                public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1502
                    return new ParameterList.Explicit.ForTypes(this, methodDescription.getParameters().asTypeList().asRawTypes());
1✔
1503
                }
1504

1505
                /**
1506
                 * {@inheritDoc}
1507
                 */
1508
                public TypeList.Generic getExceptionTypes() {
1509
                    return methodDescription.getExceptionTypes().asRawTypes();
1✔
1510
                }
1511

1512
                /**
1513
                 * {@inheritDoc}
1514
                 */
1515
                @MaybeNull
1516
                public AnnotationValue<?, ?> getDefaultValue() {
1517
                    return AnnotationValue.UNDEFINED;
×
1518
                }
1519

1520
                /**
1521
                 * {@inheritDoc}
1522
                 */
1523
                public TypeList.Generic getTypeVariables() {
1524
                    return new TypeList.Generic.Empty();
1✔
1525
                }
1526

1527
                /**
1528
                 * {@inheritDoc}
1529
                 */
1530
                public AnnotationList getDeclaredAnnotations() {
1531
                    return new AnnotationList.Empty();
1✔
1532
                }
1533

1534
                /**
1535
                 * {@inheritDoc}
1536
                 */
1537
                @Nonnull
1538
                public TypeDescription getDeclaringType() {
1539
                    return instrumentedType;
1✔
1540
                }
1541

1542
                @Override
1543
                protected int getBaseModifiers() {
1544
                    return methodDescription.isStatic()
1✔
1545
                            ? Opcodes.ACC_STATIC
1546
                            : EMPTY_MASK;
1547
                }
1548

1549
                /**
1550
                 * {@inheritDoc}
1551
                 */
1552
                public String getInternalName() {
1553
                    return name;
1✔
1554
                }
1555
            }
1556

1557
            /**
1558
             * A description of a field getter method.
1559
             */
1560
            protected static class FieldGetter extends AbstractPropertyAccessorMethod {
1561

1562
                /**
1563
                 * The instrumented type.
1564
                 */
1565
                private final TypeDescription instrumentedType;
1566

1567
                /**
1568
                 * The field for which a getter is described.
1569
                 */
1570
                private final FieldDescription fieldDescription;
1571

1572
                /**
1573
                 * The name of the getter method.
1574
                 */
1575
                private final String name;
1576

1577
                /**
1578
                 * Creates a new field getter.
1579
                 *
1580
                 * @param instrumentedType The instrumented type.
1581
                 * @param fieldDescription The field for which a getter is described.
1582
                 * @param suffix           The name suffix for the field getter method.
1583
                 */
1584
                protected FieldGetter(TypeDescription instrumentedType, FieldDescription fieldDescription, String suffix) {
1✔
1585
                    this.instrumentedType = instrumentedType;
1✔
1586
                    this.fieldDescription = fieldDescription;
1✔
1587
                    name = fieldDescription.getName() + "$" + ACCESSOR_METHOD_SUFFIX + "$" + suffix;
1✔
1588
                }
1✔
1589

1590
                /**
1591
                 * {@inheritDoc}
1592
                 */
1593
                public TypeDescription.Generic getReturnType() {
1594
                    return fieldDescription.getType().asRawType();
1✔
1595
                }
1596

1597
                /**
1598
                 * {@inheritDoc}
1599
                 */
1600
                public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1601
                    return new ParameterList.Empty<ParameterDescription.InDefinedShape>();
1✔
1602
                }
1603

1604
                /**
1605
                 * {@inheritDoc}
1606
                 */
1607
                public TypeList.Generic getExceptionTypes() {
1608
                    return new TypeList.Generic.Empty();
1✔
1609
                }
1610

1611
                /**
1612
                 * {@inheritDoc}
1613
                 */
1614
                @MaybeNull
1615
                public AnnotationValue<?, ?> getDefaultValue() {
1616
                    return AnnotationValue.UNDEFINED;
×
1617
                }
1618

1619
                /**
1620
                 * {@inheritDoc}
1621
                 */
1622
                public TypeList.Generic getTypeVariables() {
1623
                    return new TypeList.Generic.Empty();
1✔
1624
                }
1625

1626
                /**
1627
                 * {@inheritDoc}
1628
                 */
1629
                public AnnotationList getDeclaredAnnotations() {
1630
                    return new AnnotationList.Empty();
1✔
1631
                }
1632

1633
                /**
1634
                 * {@inheritDoc}
1635
                 */
1636
                @Nonnull
1637
                public TypeDescription getDeclaringType() {
1638
                    return instrumentedType;
1✔
1639
                }
1640

1641
                @Override
1642
                protected int getBaseModifiers() {
1643
                    return fieldDescription.isStatic()
1✔
1644
                            ? Opcodes.ACC_STATIC
1645
                            : EMPTY_MASK;
1646
                }
1647

1648
                /**
1649
                 * {@inheritDoc}
1650
                 */
1651
                public String getInternalName() {
1652
                    return name;
1✔
1653
                }
1654
            }
1655

1656
            /**
1657
             * A description of a field setter method.
1658
             */
1659
            protected static class FieldSetter extends AbstractPropertyAccessorMethod {
1660

1661
                /**
1662
                 * The instrumented type.
1663
                 */
1664
                private final TypeDescription instrumentedType;
1665

1666
                /**
1667
                 * The field for which a setter is described.
1668
                 */
1669
                private final FieldDescription fieldDescription;
1670

1671
                /**
1672
                 * The name of the field setter.
1673
                 */
1674
                private final String name;
1675

1676
                /**
1677
                 * Creates a new field setter.
1678
                 *
1679
                 * @param instrumentedType The instrumented type.
1680
                 * @param fieldDescription The field for which a setter is described.
1681
                 * @param suffix           The name suffix for the field setter method.
1682
                 */
1683
                protected FieldSetter(TypeDescription instrumentedType, FieldDescription fieldDescription, String suffix) {
1✔
1684
                    this.instrumentedType = instrumentedType;
1✔
1685
                    this.fieldDescription = fieldDescription;
1✔
1686
                    name = fieldDescription.getName() + "$" + ACCESSOR_METHOD_SUFFIX + "$" + suffix;
1✔
1687
                }
1✔
1688

1689
                /**
1690
                 * {@inheritDoc}
1691
                 */
1692
                public TypeDescription.Generic getReturnType() {
1693
                    return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(void.class);
1✔
1694
                }
1695

1696
                /**
1697
                 * {@inheritDoc}
1698
                 */
1699
                public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1700
                    return new ParameterList.Explicit.ForTypes(this, Collections.singletonList(fieldDescription.getType().asRawType()));
1✔
1701
                }
1702

1703
                /**
1704
                 * {@inheritDoc}
1705
                 */
1706
                public TypeList.Generic getExceptionTypes() {
1707
                    return new TypeList.Generic.Empty();
1✔
1708
                }
1709

1710
                /**
1711
                 * {@inheritDoc}
1712
                 */
1713
                @MaybeNull
1714
                public AnnotationValue<?, ?> getDefaultValue() {
1715
                    return AnnotationValue.UNDEFINED;
×
1716
                }
1717

1718
                /**
1719
                 * {@inheritDoc}
1720
                 */
1721
                public TypeList.Generic getTypeVariables() {
1722
                    return new TypeList.Generic.Empty();
1✔
1723
                }
1724

1725
                /**
1726
                 * {@inheritDoc}
1727
                 */
1728
                public AnnotationList getDeclaredAnnotations() {
1729
                    return new AnnotationList.Empty();
1✔
1730
                }
1731

1732
                /**
1733
                 * {@inheritDoc}
1734
                 */
1735
                @Nonnull
1736
                public TypeDescription getDeclaringType() {
1737
                    return instrumentedType;
1✔
1738
                }
1739

1740
                @Override
1741
                protected int getBaseModifiers() {
1742
                    return fieldDescription.isStatic()
1✔
1743
                            ? Opcodes.ACC_STATIC
1744
                            : EMPTY_MASK;
1745
                }
1746

1747
                /**
1748
                 * {@inheritDoc}
1749
                 */
1750
                public String getInternalName() {
1751
                    return name;
1✔
1752
                }
1753
            }
1754

1755
            /**
1756
             * An abstract method pool entry that delegates the implementation of a method to itself.
1757
             */
1758
            @HashCodeAndEqualsPlugin.Enhance
1759
            protected abstract static class DelegationRecord extends TypeWriter.MethodPool.Record.ForDefinedMethod implements ByteCodeAppender {
1760

1761
                /**
1762
                 * The delegation method.
1763
                 */
1764
                protected final MethodDescription.InDefinedShape methodDescription;
1765

1766
                /**
1767
                 * The record's visibility.
1768
                 */
1769
                protected final Visibility visibility;
1770

1771
                /**
1772
                 * Creates a new delegation record.
1773
                 *
1774
                 * @param methodDescription The delegation method.
1775
                 * @param visibility        The method's actual visibility.
1776
                 */
1777
                protected DelegationRecord(MethodDescription.InDefinedShape methodDescription, Visibility visibility) {
1✔
1778
                    this.methodDescription = methodDescription;
1✔
1779
                    this.visibility = visibility;
1✔
1780
                }
1✔
1781

1782
                /**
1783
                 * Returns this delegation record with the minimal visibility represented by the supplied access type.
1784
                 *
1785
                 * @param accessType The access type to enforce.
1786
                 * @return A new version of this delegation record with the minimal implied visibility.
1787
                 */
1788
                protected abstract DelegationRecord with(AccessType accessType);
1789

1790
                /**
1791
                 * {@inheritDoc}
1792
                 */
1793
                public MethodDescription.InDefinedShape getMethod() {
1794
                    return methodDescription;
1✔
1795
                }
1796

1797
                /**
1798
                 * {@inheritDoc}
1799
                 */
1800
                public Sort getSort() {
1801
                    return Sort.IMPLEMENTED;
1✔
1802
                }
1803

1804
                /**
1805
                 * {@inheritDoc}
1806
                 */
1807
                public Visibility getVisibility() {
1808
                    return visibility;
1✔
1809
                }
1810

1811
                /**
1812
                 * {@inheritDoc}
1813
                 */
1814
                public void applyHead(MethodVisitor methodVisitor) {
1815
                    /* do nothing */
1816
                }
1✔
1817

1818
                /**
1819
                 * {@inheritDoc}
1820
                 */
1821
                public void applyBody(MethodVisitor methodVisitor, Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1822
                    methodVisitor.visitCode();
1✔
1823
                    Size size = applyCode(methodVisitor, implementationContext);
1✔
1824
                    methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
1825
                }
1✔
1826

1827
                /**
1828
                 * {@inheritDoc}
1829
                 */
1830
                public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1831
                    /* do nothing */
1832
                }
×
1833

1834
                /**
1835
                 * {@inheritDoc}
1836
                 */
1837
                public Size applyCode(MethodVisitor methodVisitor, Context implementationContext) {
1838
                    return apply(methodVisitor, implementationContext, getMethod());
1✔
1839
                }
1840

1841
                /**
1842
                 * {@inheritDoc}
1843
                 */
1844
                public TypeWriter.MethodPool.Record prepend(ByteCodeAppender byteCodeAppender) {
1845
                    throw new UnsupportedOperationException("Cannot prepend code to a delegation for " + methodDescription);
1✔
1846
                }
1847
            }
1848

1849
            /**
1850
             * An implementation of a {@link TypeWriter.MethodPool.Record} for implementing
1851
             * an accessor method.
1852
             */
1853
            @HashCodeAndEqualsPlugin.Enhance
1854
            protected static class AccessorMethodDelegation extends DelegationRecord {
1855

1856
                /**
1857
                 * The stack manipulation that represents the requested special method invocation.
1858
                 */
1859
                private final StackManipulation accessorMethodInvocation;
1860

1861
                /**
1862
                 * Creates a delegation to an accessor method.
1863
                 *
1864
                 * @param instrumentedType        The instrumented type.
1865
                 * @param suffix                  The suffix to append to the method.
1866
                 * @param accessType              The access type.
1867
                 * @param specialMethodInvocation The actual method's invocation.
1868
                 */
1869
                protected AccessorMethodDelegation(TypeDescription instrumentedType,
1870
                                                   String suffix,
1871
                                                   AccessType accessType,
1872
                                                   SpecialMethodInvocation specialMethodInvocation) {
1873
                    this(new AccessorMethod(instrumentedType,
1✔
1874
                            specialMethodInvocation.getMethodDescription(),
1✔
1875
                            specialMethodInvocation.getTypeDescription(),
1✔
1876
                            suffix), accessType.getVisibility(), specialMethodInvocation);
1✔
1877
                }
1✔
1878

1879
                /**
1880
                 * Creates a delegation to an accessor method.
1881
                 *
1882
                 * @param methodDescription        The accessor method.
1883
                 * @param visibility               The method's visibility.
1884
                 * @param accessorMethodInvocation The actual method's invocation.
1885
                 */
1886
                private AccessorMethodDelegation(MethodDescription.InDefinedShape methodDescription,
1887
                                                 Visibility visibility,
1888
                                                 StackManipulation accessorMethodInvocation) {
1889
                    super(methodDescription, visibility);
1✔
1890
                    this.accessorMethodInvocation = accessorMethodInvocation;
1✔
1891
                }
1✔
1892

1893
                @Override
1894
                protected DelegationRecord with(AccessType accessType) {
1895
                    return new AccessorMethodDelegation(methodDescription, visibility.expandTo(accessType.getVisibility()), accessorMethodInvocation);
1✔
1896
                }
1897

1898
                /**
1899
                 * {@inheritDoc}
1900
                 */
1901
                public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1902
                    StackManipulation.Size stackSize = new StackManipulation.Compound(
1✔
1903
                            MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
1✔
1904
                            accessorMethodInvocation,
1905
                            MethodReturn.of(instrumentedMethod.getReturnType())
1✔
1906
                    ).apply(methodVisitor, implementationContext);
1✔
1907
                    return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
1✔
1908
                }
1909
            }
1910

1911
            /**
1912
             * An implementation for a field getter.
1913
             */
1914
            @HashCodeAndEqualsPlugin.Enhance
1915
            protected static class FieldGetterDelegation extends DelegationRecord {
1916

1917
                /**
1918
                 * The field to read from.
1919
                 */
1920
                private final FieldDescription fieldDescription;
1921

1922
                /**
1923
                 * Creates a new field getter implementation.
1924
                 *
1925
                 * @param instrumentedType The instrumented type.
1926
                 * @param suffix           The suffix to use for the setter method.
1927
                 * @param accessType       The method's access type.
1928
                 * @param fieldDescription The field to write to.
1929
                 */
1930
                protected FieldGetterDelegation(TypeDescription instrumentedType, String suffix, AccessType accessType, FieldDescription fieldDescription) {
1931
                    this(new FieldGetter(instrumentedType, fieldDescription, suffix), accessType.getVisibility(), fieldDescription);
1✔
1932
                }
1✔
1933

1934
                /**
1935
                 * Creates a new field getter implementation.
1936
                 *
1937
                 * @param methodDescription The delegation method.
1938
                 * @param visibility        The delegation method's visibility.
1939
                 * @param fieldDescription  The field to read.
1940
                 */
1941
                private FieldGetterDelegation(MethodDescription.InDefinedShape methodDescription, Visibility visibility, FieldDescription fieldDescription) {
1942
                    super(methodDescription, visibility);
1✔
1943
                    this.fieldDescription = fieldDescription;
1✔
1944
                }
1✔
1945

1946
                @Override
1947
                protected DelegationRecord with(AccessType accessType) {
1948
                    return new FieldGetterDelegation(methodDescription, visibility.expandTo(accessType.getVisibility()), fieldDescription);
1✔
1949
                }
1950

1951
                /**
1952
                 * {@inheritDoc}
1953
                 */
1954
                public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1955
                    StackManipulation.Size stackSize = new StackManipulation.Compound(
1✔
1956
                            fieldDescription.isStatic()
1✔
1957
                                    ? StackManipulation.Trivial.INSTANCE
1958
                                    : MethodVariableAccess.loadThis(),
1✔
1959
                            FieldAccess.forField(fieldDescription).read(),
1✔
1960
                            MethodReturn.of(fieldDescription.getType())
1✔
1961
                    ).apply(methodVisitor, implementationContext);
1✔
1962
                    return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
1✔
1963
                }
1964
            }
1965

1966
            /**
1967
             * An implementation for a field setter.
1968
             */
1969
            @HashCodeAndEqualsPlugin.Enhance
1970
            protected static class FieldSetterDelegation extends DelegationRecord {
1971

1972
                /**
1973
                 * The field to write to.
1974
                 */
1975
                private final FieldDescription fieldDescription;
1976

1977
                /**
1978
                 * Creates a new field setter implementation.
1979
                 *
1980
                 * @param instrumentedType The instrumented type.
1981
                 * @param suffix           The suffix to use for the setter method.
1982
                 * @param accessType       The method's access type.
1983
                 * @param fieldDescription The field to write to.
1984
                 */
1985
                protected FieldSetterDelegation(TypeDescription instrumentedType, String suffix, AccessType accessType, FieldDescription fieldDescription) {
1986
                    this(new FieldSetter(instrumentedType, fieldDescription, suffix), accessType.getVisibility(), fieldDescription);
1✔
1987
                }
1✔
1988

1989
                /**
1990
                 * Creates a new field setter.
1991
                 *
1992
                 * @param methodDescription The field accessor method.
1993
                 * @param visibility        The delegation method's visibility.
1994
                 * @param fieldDescription  The field to write to.
1995
                 */
1996
                private FieldSetterDelegation(MethodDescription.InDefinedShape methodDescription, Visibility visibility, FieldDescription fieldDescription) {
1997
                    super(methodDescription, visibility);
1✔
1998
                    this.fieldDescription = fieldDescription;
1✔
1999
                }
1✔
2000

2001
                @Override
2002
                protected DelegationRecord with(AccessType accessType) {
2003
                    return new FieldSetterDelegation(methodDescription, visibility.expandTo(accessType.getVisibility()), fieldDescription);
1✔
2004
                }
2005

2006
                /**
2007
                 * {@inheritDoc}
2008
                 */
2009
                public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
2010
                    StackManipulation.Size stackSize = new StackManipulation.Compound(
1✔
2011
                            MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
1✔
2012
                            FieldAccess.forField(fieldDescription).write(),
1✔
2013
                            MethodReturn.VOID
2014
                    ).apply(methodVisitor, implementationContext);
1✔
2015
                    return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
1✔
2016
                }
2017
            }
2018

2019
            /**
2020
             * A factory for creating a {@link net.bytebuddy.implementation.Implementation.Context.Default}
2021
             * that uses a random suffix for accessors.
2022
             */
2023
            public enum Factory implements ExtractableView.Factory {
1✔
2024

2025
                /**
2026
                 * The singleton instance.
2027
                 */
2028
                INSTANCE;
1✔
2029

2030
                /**
2031
                 * {@inheritDoc}
2032
                 */
2033
                @Deprecated
2034
                public ExtractableView make(TypeDescription instrumentedType,
2035
                                            AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2036
                                            TypeInitializer typeInitializer,
2037
                                            ClassFileVersion classFileVersion,
2038
                                            ClassFileVersion auxiliaryClassFileVersion) {
2039
                    return make(instrumentedType,
×
2040
                            auxiliaryTypeNamingStrategy,
2041
                            typeInitializer,
2042
                            classFileVersion,
2043
                            auxiliaryClassFileVersion,
2044
                            classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
×
2045
                                    ? FrameGeneration.GENERATE
2046
                                    : FrameGeneration.DISABLED);
2047
                }
2048

2049
                /**
2050
                 * {@inheritDoc}
2051
                 */
2052
                public ExtractableView make(TypeDescription instrumentedType,
2053
                                            AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2054
                                            TypeInitializer typeInitializer,
2055
                                            ClassFileVersion classFileVersion,
2056
                                            ClassFileVersion auxiliaryClassFileVersion,
2057
                                            FrameGeneration frameGeneration) {
2058
                    return new Default(instrumentedType,
1✔
2059
                            classFileVersion,
2060
                            auxiliaryTypeNamingStrategy,
2061
                            typeInitializer,
2062
                            auxiliaryClassFileVersion,
2063
                            frameGeneration,
2064
                            RandomString.make());
1✔
2065
                }
2066

2067
                /**
2068
                 * A factory for creating a {@link net.bytebuddy.implementation.Implementation.Context.Default}
2069
                 * that uses a given suffix for accessors.
2070
                 */
2071
                @HashCodeAndEqualsPlugin.Enhance
2072
                public static class WithFixedSuffix implements ExtractableView.Factory {
2073

2074
                    /**
2075
                     * The suffix to use.
2076
                     */
2077
                    private final String suffix;
2078

2079
                    /**
2080
                     * Creates a factory for an implementation context with a fixed suffix.
2081
                     *
2082
                     * @param suffix The suffix to use.
2083
                     */
2084
                    public WithFixedSuffix(String suffix) {
1✔
2085
                        this.suffix = suffix;
1✔
2086
                    }
1✔
2087

2088
                    /**
2089
                     * {@inheritDoc}
2090
                     */
2091
                    @Deprecated
2092
                    public ExtractableView make(TypeDescription instrumentedType,
2093
                                                AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2094
                                                TypeInitializer typeInitializer,
2095
                                                ClassFileVersion classFileVersion,
2096
                                                ClassFileVersion auxiliaryClassFileVersion) {
2097
                        return make(instrumentedType,
×
2098
                                auxiliaryTypeNamingStrategy,
2099
                                typeInitializer,
2100
                                classFileVersion,
2101
                                auxiliaryClassFileVersion,
2102
                                classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
×
2103
                                        ? FrameGeneration.GENERATE
2104
                                        : FrameGeneration.DISABLED);
2105
                    }
2106

2107
                    /**
2108
                     * {@inheritDoc}
2109
                     */
2110
                    public ExtractableView make(TypeDescription instrumentedType,
2111
                                                AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2112
                                                TypeInitializer typeInitializer,
2113
                                                ClassFileVersion classFileVersion,
2114
                                                ClassFileVersion auxiliaryClassFileVersion,
2115
                                                FrameGeneration frameGeneration) {
2116
                        return new Default(instrumentedType,
1✔
2117
                                classFileVersion,
2118
                                auxiliaryTypeNamingStrategy,
2119
                                typeInitializer,
2120
                                auxiliaryClassFileVersion,
2121
                                frameGeneration,
2122
                                suffix);
2123
                    }
2124
                }
2125
            }
2126
        }
2127
    }
2128

2129
    /**
2130
     * A compound implementation that allows to combine several implementations.
2131
     * <p>&nbsp;</p>
2132
     * Note that the combination of two implementation might break the contract for implementing
2133
     * {@link java.lang.Object#equals(Object)} and {@link Object#hashCode()} as described for
2134
     * {@link Implementation}.
2135
     *
2136
     * @see Implementation
2137
     */
2138
    @HashCodeAndEqualsPlugin.Enhance
2139
    class Compound implements Implementation {
2140

2141
        /**
2142
         * All implementation that are represented by this compound implementation.
2143
         */
2144
        private final List<Implementation> implementations;
2145

2146
        /**
2147
         * Creates a new immutable compound implementation.
2148
         *
2149
         * @param implementation The implementations to combine in their order.
2150
         */
2151
        public Compound(Implementation... implementation) {
2152
            this(Arrays.asList(implementation));
1✔
2153
        }
1✔
2154

2155
        /**
2156
         * Creates a new immutable compound implementation.
2157
         *
2158
         * @param implementations The implementations to combine in their order.
2159
         */
2160
        public Compound(List<? extends Implementation> implementations) {
1✔
2161
            this.implementations = new ArrayList<Implementation>();
1✔
2162
            for (Implementation implementation : implementations) {
1✔
2163
                if (implementation instanceof Compound.Composable) {
1✔
2164
                    this.implementations.addAll(((Compound.Composable) implementation).implementations);
×
2165
                    this.implementations.add(((Compound.Composable) implementation).composable);
×
2166
                } else if (implementation instanceof Compound) {
1✔
2167
                    this.implementations.addAll(((Compound) implementation).implementations);
1✔
2168
                } else {
2169
                    this.implementations.add(implementation);
1✔
2170
                }
2171
            }
1✔
2172
        }
1✔
2173

2174
        /**
2175
         * {@inheritDoc}
2176
         */
2177
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
2178
            for (Implementation implementation : implementations) {
1✔
2179
                instrumentedType = implementation.prepare(instrumentedType);
1✔
2180
            }
1✔
2181
            return instrumentedType;
1✔
2182
        }
2183

2184
        /**
2185
         * {@inheritDoc}
2186
         */
2187
        public ByteCodeAppender appender(Target implementationTarget) {
2188
            ByteCodeAppender[] byteCodeAppender = new ByteCodeAppender[implementations.size()];
1✔
2189
            int index = 0;
1✔
2190
            for (Implementation implementation : implementations) {
1✔
2191
                byteCodeAppender[index++] = implementation.appender(implementationTarget);
1✔
2192
            }
1✔
2193
            return new ByteCodeAppender.Compound(byteCodeAppender);
1✔
2194
        }
2195

2196
        /**
2197
         * A compound implementation that allows to combine several implementations and that is {@link Implementation.Composable}.
2198
         * <p>&nbsp;</p>
2199
         * Note that the combination of two implementation might break the contract for implementing
2200
         * {@link java.lang.Object#equals(Object)} and {@link Object#hashCode()} as described for
2201
         * {@link Implementation}.
2202
         *
2203
         * @see Implementation
2204
         */
2205
        @HashCodeAndEqualsPlugin.Enhance
2206
        public static class Composable implements Implementation.Composable {
2207

2208
            /**
2209
             * The composable implementation that is applied last.
2210
             */
2211
            private final Implementation.Composable composable;
2212

2213
            /**
2214
             * All implementation that are represented by this compound implementation.
2215
             */
2216
            private final List<Implementation> implementations;
2217

2218
            /**
2219
             * Creates a new compound composable.
2220
             *
2221
             * @param implementation An implementation that is represented by this compound implementation prior to the composable.
2222
             * @param composable     The composable implementation that is applied last.
2223
             */
2224
            public Composable(Implementation implementation, Implementation.Composable composable) {
2225
                this(Collections.singletonList(implementation), composable);
1✔
2226
            }
1✔
2227

2228
            /**
2229
             * Creates a new compound composable.
2230
             *
2231
             * @param implementations All implementation that are represented by this compound implementation excluding the composable.
2232
             * @param composable      The composable implementation that is applied last.
2233
             */
2234
            public Composable(List<? extends Implementation> implementations, Implementation.Composable composable) {
1✔
2235
                this.implementations = new ArrayList<Implementation>();
1✔
2236
                for (Implementation implementation : implementations) {
1✔
2237
                    if (implementation instanceof Compound.Composable) {
1✔
2238
                        this.implementations.addAll(((Compound.Composable) implementation).implementations);
×
2239
                        this.implementations.add(((Compound.Composable) implementation).composable);
×
2240
                    } else if (implementation instanceof Compound) {
1✔
2241
                        this.implementations.addAll(((Compound) implementation).implementations);
×
2242
                    } else {
2243
                        this.implementations.add(implementation);
1✔
2244
                    }
2245
                }
1✔
2246
                if (composable instanceof Compound.Composable) {
1✔
2247
                    this.implementations.addAll(((Compound.Composable) composable).implementations);
1✔
2248
                    this.composable = ((Compound.Composable) composable).composable;
1✔
2249
                } else {
2250
                    this.composable = composable;
1✔
2251
                }
2252
            }
1✔
2253

2254
            /**
2255
             * {@inheritDoc}
2256
             */
2257
            public InstrumentedType prepare(InstrumentedType instrumentedType) {
2258
                for (Implementation implementation : implementations) {
1✔
2259
                    instrumentedType = implementation.prepare(instrumentedType);
1✔
2260
                }
1✔
2261
                return composable.prepare(instrumentedType);
1✔
2262
            }
2263

2264
            /**
2265
             * {@inheritDoc}
2266
             */
2267
            public ByteCodeAppender appender(Target implementationTarget) {
2268
                ByteCodeAppender[] byteCodeAppender = new ByteCodeAppender[implementations.size() + 1];
1✔
2269
                int index = 0;
1✔
2270
                for (Implementation implementation : implementations) {
1✔
2271
                    byteCodeAppender[index++] = implementation.appender(implementationTarget);
1✔
2272
                }
1✔
2273
                byteCodeAppender[index] = composable.appender(implementationTarget);
1✔
2274
                return new ByteCodeAppender.Compound(byteCodeAppender);
1✔
2275
            }
2276

2277
            /**
2278
             * {@inheritDoc}
2279
             */
2280
            public Implementation andThen(Implementation implementation) {
2281
                return new Compound(CompoundList.of(implementations, composable.andThen(implementation)));
1✔
2282
            }
2283

2284
            /**
2285
             * {@inheritDoc}
2286
             */
2287
            public Implementation.Composable andThen(Implementation.Composable implementation) {
2288
                return new Compound.Composable(implementations, composable.andThen(implementation));
1✔
2289
            }
2290
        }
2291
    }
2292

2293
    /**
2294
     * A simple implementation that does not register any members with the instrumented type.
2295
     */
2296
    @HashCodeAndEqualsPlugin.Enhance
2297
    class Simple implements Implementation {
2298

2299
        /**
2300
         * Indicates that no additional local variable slots are required.
2301
         */
2302
        private static final int NO_ADDITIONAL_VARIABLES = 0;
2303

2304
        /**
2305
         * The byte code appender to emmit.
2306
         */
2307
        private final ByteCodeAppender byteCodeAppender;
2308

2309
        /**
2310
         * Creates a new simple implementation for the given byte code appenders.
2311
         *
2312
         * @param byteCodeAppender The byte code appenders to apply in their order of application.
2313
         */
2314
        public Simple(ByteCodeAppender... byteCodeAppender) {
1✔
2315
            this.byteCodeAppender = new ByteCodeAppender.Compound(byteCodeAppender);
1✔
2316
        }
1✔
2317

2318
        /**
2319
         * Creates a new simple instrumentation for the given stack manipulations which are summarized in a
2320
         * byte code appender that defines any requested method by these manipulations.
2321
         *
2322
         * @param stackManipulation The stack manipulation to apply in their order of application.
2323
         */
2324
        public Simple(StackManipulation... stackManipulation) {
1✔
2325
            byteCodeAppender = new ByteCodeAppender.Simple(stackManipulation);
1✔
2326
        }
1✔
2327

2328
        /**
2329
         * Resolves a simple implementation that applies the given dispatcher without defining additional local variables.
2330
         *
2331
         * @param dispatcher The dispatcher to use.
2332
         * @return An implementation for the supplied dispatcher.
2333
         */
2334
        public static Implementation of(Dispatcher dispatcher) {
2335
            return of(dispatcher, NO_ADDITIONAL_VARIABLES);
1✔
2336
        }
2337

2338
        /**
2339
         * Resolves a simple implementation that applies the given dispatcher.
2340
         *
2341
         * @param dispatcher               The dispatcher to use.
2342
         * @param additionalVariableLength The amount of additional slots required in the local variable array.
2343
         * @return An implementation for the supplied dispatcher.
2344
         */
2345
        public static Implementation of(Dispatcher dispatcher, int additionalVariableLength) {
2346
            return of(dispatcher, NoOp.INSTANCE, additionalVariableLength);
1✔
2347
        }
2348

2349
        /**
2350
         * Resolves a simple implementation that applies the given dispatcher without defining additional local variables.
2351
         *
2352
         * @param dispatcher  The dispatcher to use.
2353
         * @param prepareable A preparation of the instrumented type.
2354
         * @return An implementation for the supplied dispatcher.
2355
         */
2356
        public static Implementation of(Dispatcher dispatcher, InstrumentedType.Prepareable prepareable) {
2357
            return of(dispatcher, prepareable, NO_ADDITIONAL_VARIABLES);
×
2358
        }
2359

2360
        /**
2361
         * Resolves a simple implementation that applies the given dispatcher.
2362
         *
2363
         * @param dispatcher               The dispatcher to use.
2364
         * @param prepareable              A preparation of the instrumented type.
2365
         * @param additionalVariableLength The amount of additional slots required in the local variable array.
2366
         * @return An implementation for the supplied dispatcher.
2367
         */
2368
        public static Implementation of(Dispatcher dispatcher, InstrumentedType.Prepareable prepareable, int additionalVariableLength) {
2369
            if (additionalVariableLength < NO_ADDITIONAL_VARIABLES) {
1✔
2370
                throw new IllegalArgumentException("Additional variable length cannot be negative: " + additionalVariableLength);
×
2371
            }
2372
            return new ForDispatcher(dispatcher, prepareable, additionalVariableLength);
1✔
2373
        }
2374

2375
        /**
2376
         * {@inheritDoc}
2377
         */
2378
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
2379
            return instrumentedType;
1✔
2380
        }
2381

2382
        /**
2383
         * {@inheritDoc}
2384
         */
2385
        public ByteCodeAppender appender(Target implementationTarget) {
2386
            return byteCodeAppender;
1✔
2387
        }
2388

2389
        /**
2390
         * A dispatcher for a simple {@link Implementation}, typically implemented as a lambda expression.
2391
         */
2392
        public interface Dispatcher {
2393

2394
            /**
2395
             * Creates a stack manipulation from a simple method dispatch.
2396
             *
2397
             * @param implementationTarget The implementation target to use.
2398
             * @param instrumentedMethod   The instrumented method.
2399
             * @return The stack manipulation to apply.
2400
             */
2401
            StackManipulation apply(Target implementationTarget, MethodDescription instrumentedMethod);
2402
        }
2403

2404
        /**
2405
         * A {@link ByteCodeAppender} for a dispatcher.
2406
         */
2407
        @HashCodeAndEqualsPlugin.Enhance
2408
        protected static class ForDispatcher implements Implementation {
2409

2410
            /**
2411
             * The dispatcher to use.
2412
             */
2413
            private final Dispatcher dispatcher;
2414

2415
            /**
2416
             * A preparation of the instrumented type.
2417
             */
2418
            private final InstrumentedType.Prepareable prepareable;
2419

2420
            /**
2421
             * The additional length of the local variable array.
2422
             */
2423
            private final int additionalVariableLength;
2424

2425
            /**
2426
             * Creates a new byte code appender for a dispatcher.
2427
             *
2428
             * @param dispatcher               The dispatcher to use.
2429
             * @param prepareable              A preparation of the instrumented type.
2430
             * @param additionalVariableLength The additional length of the local variable array.
2431
             */
2432
            protected ForDispatcher(Dispatcher dispatcher, InstrumentedType.Prepareable prepareable, int additionalVariableLength) {
1✔
2433
                this.dispatcher = dispatcher;
1✔
2434
                this.prepareable = prepareable;
1✔
2435
                this.additionalVariableLength = additionalVariableLength;
1✔
2436
            }
1✔
2437

2438
            /**
2439
             * {@inheritDoc}
2440
             */
2441
            public InstrumentedType prepare(InstrumentedType instrumentedType) {
2442
                return prepareable.prepare(instrumentedType);
×
2443
            }
2444

2445
            /**
2446
             * {@inheritDoc}
2447
             */
2448
            public ByteCodeAppender appender(Target implementationTarget) {
2449
                return new Appender(implementationTarget);
1✔
2450
            }
2451

2452
            /**
2453
             * An appender for a dispatcher-based simple implementation.
2454
             */
2455
            @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
2456
            protected class Appender implements ByteCodeAppender {
2457

2458
                /**
2459
                 * The implementation target.
2460
                 */
2461
                private final Target implementationTarget;
2462

2463
                /**
2464
                 * Creates a new appender.
2465
                 *
2466
                 * @param implementationTarget The implementation target.
2467
                 */
2468
                protected Appender(Target implementationTarget) {
1✔
2469
                    this.implementationTarget = implementationTarget;
1✔
2470
                }
1✔
2471

2472
                /**
2473
                 * {@inheritDoc}
2474
                 */
2475
                public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
2476
                    return new Size(dispatcher.apply(implementationTarget, instrumentedMethod)
1✔
2477
                            .apply(methodVisitor, implementationContext)
1✔
2478
                            .getMaximalSize(), instrumentedMethod.getStackSize() + additionalVariableLength);
1✔
2479
                }
2480
            }
2481
        }
2482
    }
2483
}
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