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

raphw / byte-buddy / #717

17 Jan 2025 09:06PM UTC coverage: 85.373% (-0.1%) from 85.479%
#717

push

raphw
Fix build.

0 of 4 new or added lines in 1 file covered. (0.0%)

572 existing lines in 8 files now uncovered.

28973 of 33937 relevant lines covered (85.37%)

0.85 hits per line

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

81.14
/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/TypeWriter.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.dynamic.scaffold;
17

18
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.ClassFileVersion;
20
import net.bytebuddy.asm.AsmVisitorWrapper;
21
import net.bytebuddy.build.AccessControllerPlugin;
22
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
23
import net.bytebuddy.description.annotation.AnnotationList;
24
import net.bytebuddy.description.annotation.AnnotationValue;
25
import net.bytebuddy.description.field.FieldDescription;
26
import net.bytebuddy.description.field.FieldList;
27
import net.bytebuddy.description.method.MethodDescription;
28
import net.bytebuddy.description.method.MethodList;
29
import net.bytebuddy.description.method.ParameterDescription;
30
import net.bytebuddy.description.method.ParameterList;
31
import net.bytebuddy.description.modifier.ModifierContributor;
32
import net.bytebuddy.description.modifier.Visibility;
33
import net.bytebuddy.description.type.*;
34
import net.bytebuddy.dynamic.ClassFileLocator;
35
import net.bytebuddy.dynamic.DynamicType;
36
import net.bytebuddy.dynamic.TypeResolutionStrategy;
37
import net.bytebuddy.dynamic.scaffold.inline.MethodRebaseResolver;
38
import net.bytebuddy.dynamic.scaffold.inline.RebaseImplementationTarget;
39
import net.bytebuddy.dynamic.scaffold.subclass.SubclassImplementationTarget;
40
import net.bytebuddy.implementation.Implementation;
41
import net.bytebuddy.implementation.LoadedTypeInitializer;
42
import net.bytebuddy.implementation.attribute.*;
43
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
44
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
45
import net.bytebuddy.implementation.bytecode.StackManipulation;
46
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
47
import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
48
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
49
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
50
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
51
import net.bytebuddy.pool.TypePool;
52
import net.bytebuddy.utility.AsmClassReader;
53
import net.bytebuddy.utility.AsmClassWriter;
54
import net.bytebuddy.utility.CompoundList;
55
import net.bytebuddy.utility.OpenedClassReader;
56
import net.bytebuddy.utility.nullability.AlwaysNull;
57
import net.bytebuddy.utility.nullability.MaybeNull;
58
import net.bytebuddy.utility.nullability.UnknownNull;
59
import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
60
import net.bytebuddy.utility.visitor.ContextClassVisitor;
61
import net.bytebuddy.utility.visitor.MetadataAwareClassVisitor;
62
import org.objectweb.asm.*;
63
import org.objectweb.asm.commons.ClassRemapper;
64
import org.objectweb.asm.commons.Remapper;
65
import org.objectweb.asm.commons.SimpleRemapper;
66

67
import javax.annotation.Nonnull;
68
import java.io.File;
69
import java.io.FileOutputStream;
70
import java.io.IOException;
71
import java.io.OutputStream;
72
import java.security.PrivilegedAction;
73
import java.security.PrivilegedExceptionAction;
74
import java.util.*;
75

76
import static net.bytebuddy.matcher.ElementMatchers.*;
77

78
/**
79
 * A type writer is a utility for writing an actual class file using the ASM library.
80
 *
81
 * @param <T> The best known loaded type for the dynamically created type.
82
 */
83
public interface TypeWriter<T> {
84

85
    /**
86
     * A system property that indicates a folder for Byte Buddy to dump class files of all types that it creates.
87
     * If this property is not set, Byte Buddy does not dump any class files. This property is only read a single
88
     * time which is why it must be set on application start-up.
89
     */
90
    String DUMP_PROPERTY = "net.bytebuddy.dump";
91

92
    /**
93
     * Creates the dynamic type that is described by this type writer.
94
     *
95
     * @param typeResolver The type resolution strategy to use.
96
     * @return An unloaded dynamic type that describes the created type.
97
     */
98
    DynamicType.Unloaded<T> make(TypeResolutionStrategy.Resolved typeResolver);
99

100
    /**
101
     * Wraps another ASM class visitor with a visitor that represents this ASM class writer.
102
     *
103
     * @param classVisitor The class visitor to wrap.
104
     * @param writerFlags  The ASM writer flags to consider.
105
     * @param readerFlags  The ASM reader flags to consider.
106
     * @return The supplied class visitor wrapped by this type writer.
107
     */
108
    ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags);
109

110
    /**
111
     * An field pool that allows a lookup for how to implement a field.
112
     */
113
    interface FieldPool {
114

115
        /**
116
         * Looks up a handler entry for a given field.
117
         *
118
         * @param fieldDescription The field being processed.
119
         * @return A handler entry for the given field.
120
         */
121
        Record target(FieldDescription fieldDescription);
122

123
        /**
124
         * An entry of a field pool that describes how a field is implemented.
125
         *
126
         * @see net.bytebuddy.dynamic.scaffold.TypeWriter.FieldPool
127
         */
128
        interface Record {
129

130
            /**
131
             * Determines if this record is implicit, i.e is not defined by a {@link FieldPool}.
132
             *
133
             * @return {@code true} if this record is implicit.
134
             */
135
            boolean isImplicit();
136

137
            /**
138
             * Returns the field that this record represents.
139
             *
140
             * @return The field that this record represents.
141
             */
142
            FieldDescription getField();
143

144
            /**
145
             * Returns the field attribute appender for a given field.
146
             *
147
             * @return The attribute appender to be applied on the given field.
148
             */
149
            FieldAttributeAppender getFieldAppender();
150

151
            /**
152
             * Resolves the default value that this record represents. This is not possible for implicit records.
153
             *
154
             * @param defaultValue The default value that was defined previously or {@code null} if no default value is defined.
155
             * @return The default value for the represented field or {@code null} if no default value is to be defined.
156
             */
157
            @MaybeNull
158
            Object resolveDefault(@MaybeNull Object defaultValue);
159

160
            /**
161
             * Writes this entry to a given class visitor.
162
             *
163
             * @param classVisitor                 The class visitor to which this entry is to be written to.
164
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
165
             */
166
            void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
167

168
            /**
169
             * Applies this record to a field visitor. This is not possible for implicit records.
170
             *
171
             * @param fieldVisitor                 The field visitor onto which this record is to be applied.
172
             * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
173
             */
174
            void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
175

176
            /**
177
             * A record for a simple field without a default value where all of the field's declared annotations are appended.
178
             */
179
            @HashCodeAndEqualsPlugin.Enhance
180
            class ForImplicitField implements Record {
181

182
                /**
183
                 * The implemented field.
184
                 */
185
                private final FieldDescription fieldDescription;
186

187
                /**
188
                 * Creates a new record for a simple field.
189
                 *
190
                 * @param fieldDescription The described field.
191
                 */
192
                public ForImplicitField(FieldDescription fieldDescription) {
1✔
193
                    this.fieldDescription = fieldDescription;
1✔
194
                }
1✔
195

196
                /**
197
                 * {@inheritDoc}
198
                 */
199
                public boolean isImplicit() {
200
                    return true;
1✔
201
                }
202

203
                /**
204
                 * {@inheritDoc}
205
                 */
206
                public FieldDescription getField() {
207
                    return fieldDescription;
1✔
208
                }
209

210
                /**
211
                 * {@inheritDoc}
212
                 */
213
                public FieldAttributeAppender getFieldAppender() {
214
                    throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
1✔
215
                }
216

217
                /**
218
                 * {@inheritDoc}
219
                 */
220
                public Object resolveDefault(@MaybeNull Object defaultValue) {
221
                    throw new IllegalStateException("An implicit field record does not expose a default value: " + this);
1✔
222
                }
223

224
                /**
225
                 * {@inheritDoc}
226
                 */
227
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
228
                    FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
1✔
229
                            fieldDescription.getInternalName(),
1✔
230
                            fieldDescription.getDescriptor(),
1✔
231
                            fieldDescription.getGenericSignature(),
1✔
232
                            FieldDescription.NO_DEFAULT_VALUE);
233
                    if (fieldVisitor != null) {
1✔
234
                        FieldAttributeAppender.ForInstrumentedField.INSTANCE.apply(fieldVisitor,
1✔
235
                                fieldDescription,
236
                                annotationValueFilterFactory.on(fieldDescription));
1✔
237
                        fieldVisitor.visitEnd();
1✔
238
                    }
239
                }
1✔
240

241
                /**
242
                 * {@inheritDoc}
243
                 */
244
                public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
245
                    throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
1✔
246
                }
247
            }
248

249
            /**
250
             * A record for a rich field with attributes and a potential default value.
251
             */
252
            @HashCodeAndEqualsPlugin.Enhance
253
            class ForExplicitField implements Record {
254

255
                /**
256
                 * The attribute appender for the field.
257
                 */
258
                private final FieldAttributeAppender attributeAppender;
259

260
                /**
261
                 * The field's default value.
262
                 */
263
                @MaybeNull
264
                @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
265
                private final Object defaultValue;
266

267
                /**
268
                 * The implemented field.
269
                 */
270
                private final FieldDescription fieldDescription;
271

272
                /**
273
                 * Creates a record for a rich field.
274
                 *
275
                 * @param attributeAppender The attribute appender for the field.
276
                 * @param defaultValue      The field's default value.
277
                 * @param fieldDescription  The implemented field.
278
                 */
279
                public ForExplicitField(FieldAttributeAppender attributeAppender,
280
                                        @MaybeNull Object defaultValue,
281
                                        FieldDescription fieldDescription) {
1✔
282
                    this.attributeAppender = attributeAppender;
1✔
283
                    this.defaultValue = defaultValue;
1✔
284
                    this.fieldDescription = fieldDescription;
1✔
285
                }
1✔
286

287
                /**
288
                 * {@inheritDoc}
289
                 */
290
                public boolean isImplicit() {
291
                    return false;
1✔
292
                }
293

294
                /**
295
                 * {@inheritDoc}
296
                 */
297
                public FieldDescription getField() {
298
                    return fieldDescription;
1✔
299
                }
300

301
                /**
302
                 * {@inheritDoc}
303
                 */
304
                public FieldAttributeAppender getFieldAppender() {
305
                    return attributeAppender;
1✔
306
                }
307

308
                /**
309
                 * {@inheritDoc}
310
                 */
311
                @MaybeNull
312
                public Object resolveDefault(@MaybeNull Object defaultValue) {
313
                    return this.defaultValue == null
1✔
314
                            ? defaultValue
315
                            : this.defaultValue;
316
                }
317

318
                /**
319
                 * {@inheritDoc}
320
                 */
321
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
322
                    FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
1✔
323
                            fieldDescription.getInternalName(),
1✔
324
                            fieldDescription.getDescriptor(),
1✔
325
                            fieldDescription.getGenericSignature(),
1✔
326
                            resolveDefault(FieldDescription.NO_DEFAULT_VALUE));
1✔
327
                    if (fieldVisitor != null) {
1✔
328
                        attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
1✔
329
                        fieldVisitor.visitEnd();
1✔
330
                    }
331
                }
1✔
332

333
                /**
334
                 * {@inheritDoc}
335
                 */
336
                public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
337
                    attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
1✔
338
                }
1✔
339
            }
340
        }
341

342
        /**
343
         * A field pool that does not allow any look ups.
344
         */
345
        enum Disabled implements FieldPool {
1✔
346

347
            /**
348
             * The singleton instance.
349
             */
350
            INSTANCE;
1✔
351

352
            /**
353
             * {@inheritDoc}
354
             */
355
            public Record target(FieldDescription fieldDescription) {
356
                throw new IllegalStateException("Cannot look up field from disabled pool");
1✔
357
            }
358
        }
359
    }
360

361
    /**
362
     * An method pool that allows a lookup for how to implement a method.
363
     */
364
    interface MethodPool {
365

366
        /**
367
         * Looks up a handler entry for a given method.
368
         *
369
         * @param methodDescription The method being processed.
370
         * @return A handler entry for the given method.
371
         */
372
        Record target(MethodDescription methodDescription);
373

374
        /**
375
         * An entry of a method pool that describes how a method is implemented.
376
         *
377
         * @see net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool
378
         */
379
        interface Record {
380

381
            /**
382
             * Returns the sort of this method instrumentation.
383
             *
384
             * @return The sort of this method instrumentation.
385
             */
386
            Sort getSort();
387

388
            /**
389
             * Returns the method that is implemented where the returned method resembles a potential transformation. An implemented
390
             * method is only defined if a method is not {@link Record.Sort#SKIPPED}.
391
             *
392
             * @return The implemented method.
393
             */
394
            MethodDescription getMethod();
395

396
            /**
397
             * The visibility to enforce for this method.
398
             *
399
             * @return The visibility to enforce for this method.
400
             */
401
            Visibility getVisibility();
402

403
            /**
404
             * Prepends the given method appender to this entry.
405
             *
406
             * @param byteCodeAppender The byte code appender to prepend.
407
             * @return This entry with the given code prepended.
408
             */
409
            Record prepend(ByteCodeAppender byteCodeAppender);
410

411
            /**
412
             * Applies this method entry. This method can always be called and might be a no-op.
413
             *
414
             * @param classVisitor                 The class visitor to which this entry should be applied.
415
             * @param implementationContext        The implementation context to which this entry should be applied.
416
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
417
             */
418
            void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
419

420
            /**
421
             * Applies the head of this entry. Applying an entry is only possible if a method is defined, i.e. the sort of this entry is not
422
             * {@link Record.Sort#SKIPPED}.
423
             *
424
             * @param methodVisitor The method visitor to which this entry should be applied.
425
             */
426
            void applyHead(MethodVisitor methodVisitor);
427

428
            /**
429
             * Applies the body of this entry. Applying the body of an entry is only possible if a method is implemented, i.e. the sort of this
430
             * entry is {@link Record.Sort#IMPLEMENTED}.
431
             *
432
             * @param methodVisitor                The method visitor to which this entry should be applied.
433
             * @param implementationContext        The implementation context to which this entry should be applied.
434
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
435
             */
436
            void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
437

438
            /**
439
             * Applies the attributes of this entry. Applying the body of an entry is only possible if a method is implemented, i.e. the sort of this
440
             * entry is {@link Record.Sort#DEFINED}.
441
             *
442
             * @param methodVisitor                The method visitor to which this entry should be applied.
443
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
444
             */
445
            void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
446

447
            /**
448
             * Applies the code of this entry. Applying the body of an entry is only possible if a method is implemented, i.e. the sort of this
449
             * entry is {@link Record.Sort#IMPLEMENTED}.
450
             *
451
             * @param methodVisitor         The method visitor to which this entry should be applied.
452
             * @param implementationContext The implementation context to which this entry should be applied.
453
             * @return The size requirements of the implemented code.
454
             */
455
            ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext);
456

457
            /**
458
             * The sort of an entry.
459
             */
460
            enum Sort {
1✔
461

462
                /**
463
                 * Describes a method that should not be implemented or retained in its original state.
464
                 */
465
                SKIPPED(false, false),
1✔
466

467
                /**
468
                 * Describes a method that should be defined but is abstract or native, i.e. does not define any byte code.
469
                 */
470
                DEFINED(true, false),
1✔
471

472
                /**
473
                 * Describes a method that is implemented in byte code.
474
                 */
475
                IMPLEMENTED(true, true);
1✔
476

477
                /**
478
                 * Indicates if this sort defines a method, with or without byte code.
479
                 */
480
                private final boolean define;
481

482
                /**
483
                 * Indicates if this sort defines byte code.
484
                 */
485
                private final boolean implement;
486

487
                /**
488
                 * Creates a new sort.
489
                 *
490
                 * @param define    Indicates if this sort defines a method, with or without byte code.
491
                 * @param implement Indicates if this sort defines byte code.
492
                 */
493
                Sort(boolean define, boolean implement) {
1✔
494
                    this.define = define;
1✔
495
                    this.implement = implement;
1✔
496
                }
1✔
497

498
                /**
499
                 * Indicates if this sort defines a method, with or without byte code.
500
                 *
501
                 * @return {@code true} if this sort defines a method, with or without byte code.
502
                 */
503
                public boolean isDefined() {
504
                    return define;
1✔
505
                }
506

507
                /**
508
                 * Indicates if this sort defines byte code.
509
                 *
510
                 * @return {@code true} if this sort defines byte code.
511
                 */
512
                public boolean isImplemented() {
513
                    return implement;
1✔
514
                }
515
            }
516

517
            /**
518
             * A canonical implementation of a method that is not declared but inherited by the instrumented type.
519
             */
520
            @HashCodeAndEqualsPlugin.Enhance
521
            class ForNonImplementedMethod implements Record {
522

523
                /**
524
                 * The undefined method.
525
                 */
526
                private final MethodDescription methodDescription;
527

528
                /**
529
                 * Creates a new undefined record.
530
                 *
531
                 * @param methodDescription The undefined method.
532
                 */
533
                public ForNonImplementedMethod(MethodDescription methodDescription) {
1✔
534
                    this.methodDescription = methodDescription;
1✔
535
                }
1✔
536

537
                /**
538
                 * {@inheritDoc}
539
                 */
540
                public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
541
                    /* do nothing */
542
                }
1✔
543

544
                /**
545
                 * {@inheritDoc}
546
                 */
547
                public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
548
                    throw new IllegalStateException("Cannot apply body for non-implemented method on " + methodDescription);
1✔
549
                }
550

551
                /**
552
                 * {@inheritDoc}
553
                 */
554
                public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
555
                    /* do nothing */
556
                }
1✔
557

558
                /**
559
                 * {@inheritDoc}
560
                 */
561
                public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
562
                    throw new IllegalStateException("Cannot apply code for non-implemented method on " + methodDescription);
×
563
                }
564

565
                /**
566
                 * {@inheritDoc}
567
                 */
568
                public void applyHead(MethodVisitor methodVisitor) {
569
                    throw new IllegalStateException("Cannot apply head for non-implemented method on " + methodDescription);
1✔
570
                }
571

572
                /**
573
                 * {@inheritDoc}
574
                 */
575
                public MethodDescription getMethod() {
576
                    return methodDescription;
1✔
577
                }
578

579
                /**
580
                 * {@inheritDoc}
581
                 */
582
                public Visibility getVisibility() {
583
                    return methodDescription.getVisibility();
×
584
                }
585

586
                /**
587
                 * {@inheritDoc}
588
                 */
589
                public Sort getSort() {
590
                    return Sort.SKIPPED;
1✔
591
                }
592

593
                /**
594
                 * {@inheritDoc}
595
                 */
596
                public Record prepend(ByteCodeAppender byteCodeAppender) {
597
                    return new ForDefinedMethod.WithBody(methodDescription, new ByteCodeAppender.Compound(byteCodeAppender,
1✔
598
                            new ByteCodeAppender.Simple(DefaultValue.of(methodDescription.getReturnType()), MethodReturn.of(methodDescription.getReturnType()))));
1✔
599
                }
600
            }
601

602
            /**
603
             * A base implementation of an abstract entry that defines a method.
604
             */
605
            abstract class ForDefinedMethod implements Record {
1✔
606

607
                /**
608
                 * {@inheritDoc}
609
                 */
610
                public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
611
                    MethodVisitor methodVisitor = classVisitor.visitMethod(getMethod().getActualModifiers(getSort().isImplemented(), getVisibility()),
1✔
612
                            getMethod().getInternalName(),
1✔
613
                            getMethod().getDescriptor(),
1✔
614
                            getMethod().getGenericSignature(),
1✔
615
                            getMethod().getExceptionTypes().asErasures().toInternalNames());
1✔
616
                    if (methodVisitor != null) {
1✔
617
                        ParameterList<?> parameterList = getMethod().getParameters();
1✔
618
                        if (parameterList.hasExplicitMetaData()) {
1✔
619
                            for (ParameterDescription parameterDescription : parameterList) {
1✔
620
                                methodVisitor.visitParameter(parameterDescription.getName(), parameterDescription.getModifiers());
1✔
621
                            }
1✔
622
                        }
623
                        applyHead(methodVisitor);
1✔
624
                        applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
1✔
625
                        methodVisitor.visitEnd();
1✔
626
                    }
627
                }
1✔
628

629
                /**
630
                 * Describes an entry that defines a method as byte code.
631
                 */
632
                @HashCodeAndEqualsPlugin.Enhance
633
                public static class WithBody extends ForDefinedMethod {
634

635
                    /**
636
                     * The implemented method.
637
                     */
638
                    private final MethodDescription methodDescription;
639

640
                    /**
641
                     * The byte code appender to apply.
642
                     */
643
                    private final ByteCodeAppender byteCodeAppender;
644

645
                    /**
646
                     * The method attribute appender to apply.
647
                     */
648
                    private final MethodAttributeAppender methodAttributeAppender;
649

650
                    /**
651
                     * The represented method's minimum visibility.
652
                     */
653
                    private final Visibility visibility;
654

655
                    /**
656
                     * Creates a new record for an implemented method without attributes or a modifier resolver.
657
                     *
658
                     * @param methodDescription The implemented method.
659
                     * @param byteCodeAppender  The byte code appender to apply.
660
                     */
661
                    public WithBody(MethodDescription methodDescription, ByteCodeAppender byteCodeAppender) {
662
                        this(methodDescription, byteCodeAppender, MethodAttributeAppender.NoOp.INSTANCE, methodDescription.getVisibility());
1✔
663
                    }
1✔
664

665
                    /**
666
                     * Creates a new entry for a method that defines a method as byte code.
667
                     *
668
                     * @param methodDescription       The implemented method.
669
                     * @param byteCodeAppender        The byte code appender to apply.
670
                     * @param methodAttributeAppender The method attribute appender to apply.
671
                     * @param visibility              The represented method's minimum visibility.
672
                     */
673
                    public WithBody(MethodDescription methodDescription,
674
                                    ByteCodeAppender byteCodeAppender,
675
                                    MethodAttributeAppender methodAttributeAppender,
676
                                    Visibility visibility) {
1✔
677
                        this.methodDescription = methodDescription;
1✔
678
                        this.byteCodeAppender = byteCodeAppender;
1✔
679
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
680
                        this.visibility = visibility;
1✔
681
                    }
1✔
682

683
                    /**
684
                     * {@inheritDoc}
685
                     */
686
                    public MethodDescription getMethod() {
687
                        return methodDescription;
1✔
688
                    }
689

690
                    /**
691
                     * {@inheritDoc}
692
                     */
693
                    public Sort getSort() {
694
                        return Sort.IMPLEMENTED;
1✔
695
                    }
696

697
                    /**
698
                     * {@inheritDoc}
699
                     */
700
                    public Visibility getVisibility() {
701
                        return visibility;
1✔
702
                    }
703

704
                    /**
705
                     * {@inheritDoc}
706
                     */
707
                    public void applyHead(MethodVisitor methodVisitor) {
708
                        /* do nothing */
709
                    }
1✔
710

711
                    /**
712
                     * {@inheritDoc}
713
                     */
714
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
715
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
716
                        methodVisitor.visitCode();
1✔
717
                        ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
1✔
718
                        methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
719
                    }
1✔
720

721
                    /**
722
                     * {@inheritDoc}
723
                     */
724
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
725
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
726
                    }
1✔
727

728
                    /**
729
                     * {@inheritDoc}
730
                     */
731
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
732
                        return byteCodeAppender.apply(methodVisitor, implementationContext, methodDescription);
1✔
733
                    }
734

735
                    /**
736
                     * {@inheritDoc}
737
                     */
738
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
739
                        return new WithBody(methodDescription,
1✔
740
                                new ByteCodeAppender.Compound(byteCodeAppender, this.byteCodeAppender),
741
                                methodAttributeAppender,
742
                                visibility);
743
                    }
744
                }
745

746
                /**
747
                 * Describes an entry that defines a method but without byte code and without an annotation value.
748
                 */
749
                @HashCodeAndEqualsPlugin.Enhance
750
                public static class WithoutBody extends ForDefinedMethod {
751

752
                    /**
753
                     * The implemented method.
754
                     */
755
                    private final MethodDescription methodDescription;
756

757
                    /**
758
                     * The method attribute appender to apply.
759
                     */
760
                    private final MethodAttributeAppender methodAttributeAppender;
761

762
                    /**
763
                     * The represented method's minimum visibility.
764
                     */
765
                    private final Visibility visibility;
766

767
                    /**
768
                     * Creates a new entry for a method that is defines but does not append byte code, i.e. is native or abstract.
769
                     *
770
                     * @param methodDescription       The implemented method.
771
                     * @param methodAttributeAppender The method attribute appender to apply.
772
                     * @param visibility              The represented method's minimum visibility.
773
                     */
774
                    public WithoutBody(MethodDescription methodDescription, MethodAttributeAppender methodAttributeAppender, Visibility visibility) {
1✔
775
                        this.methodDescription = methodDescription;
1✔
776
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
777
                        this.visibility = visibility;
1✔
778
                    }
1✔
779

780
                    /**
781
                     * {@inheritDoc}
782
                     */
783
                    public MethodDescription getMethod() {
784
                        return methodDescription;
1✔
785
                    }
786

787
                    /**
788
                     * {@inheritDoc}
789
                     */
790
                    public Sort getSort() {
791
                        return Sort.DEFINED;
1✔
792
                    }
793

794
                    /**
795
                     * {@inheritDoc}
796
                     */
797
                    public Visibility getVisibility() {
798
                        return visibility;
1✔
799
                    }
800

801
                    /**
802
                     * {@inheritDoc}
803
                     */
804
                    public void applyHead(MethodVisitor methodVisitor) {
805
                        /* do nothing */
806
                    }
1✔
807

808
                    /**
809
                     * {@inheritDoc}
810
                     */
811
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
812
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
813
                    }
1✔
814

815
                    /**
816
                     * {@inheritDoc}
817
                     */
818
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
819
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
820
                    }
1✔
821

822
                    /**
823
                     * {@inheritDoc}
824
                     */
825
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
826
                        throw new IllegalStateException("Cannot apply code for abstract method on " + methodDescription);
1✔
827
                    }
828

829
                    /**
830
                     * {@inheritDoc}
831
                     */
832
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
833
                        throw new IllegalStateException("Cannot prepend code for abstract method on " + methodDescription);
1✔
834
                    }
835
                }
836

837
                /**
838
                 * Describes an entry that defines a method with a default annotation value.
839
                 */
840
                @HashCodeAndEqualsPlugin.Enhance
841
                public static class WithAnnotationDefaultValue extends ForDefinedMethod {
842

843
                    /**
844
                     * The implemented method.
845
                     */
846
                    private final MethodDescription methodDescription;
847

848
                    /**
849
                     * The annotation value to define.
850
                     */
851
                    private final AnnotationValue<?, ?> annotationValue;
852

853
                    /**
854
                     * The method attribute appender to apply.
855
                     */
856
                    private final MethodAttributeAppender methodAttributeAppender;
857

858
                    /**
859
                     * Creates a new entry for defining a method with a default annotation value.
860
                     *
861
                     * @param methodDescription       The implemented method.
862
                     * @param annotationValue         The annotation value to define.
863
                     * @param methodAttributeAppender The method attribute appender to apply.
864
                     */
865
                    public WithAnnotationDefaultValue(MethodDescription methodDescription,
866
                                                      AnnotationValue<?, ?> annotationValue,
867
                                                      MethodAttributeAppender methodAttributeAppender) {
1✔
868
                        this.methodDescription = methodDescription;
1✔
869
                        this.annotationValue = annotationValue;
1✔
870
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
871
                    }
1✔
872

873
                    /**
874
                     * {@inheritDoc}
875
                     */
876
                    public MethodDescription getMethod() {
877
                        return methodDescription;
1✔
878
                    }
879

880
                    /**
881
                     * {@inheritDoc}
882
                     */
883
                    public Sort getSort() {
884
                        return Sort.DEFINED;
1✔
885
                    }
886

887
                    /**
888
                     * {@inheritDoc}
889
                     */
890
                    public Visibility getVisibility() {
891
                        return methodDescription.getVisibility();
1✔
892
                    }
893

894
                    /**
895
                     * {@inheritDoc}
896
                     */
897
                    public void applyHead(MethodVisitor methodVisitor) {
898
                        if (!methodDescription.isDefaultValue(annotationValue)) {
1✔
899
                            throw new IllegalStateException("Cannot set " + annotationValue + " as default for " + methodDescription);
1✔
900
                        }
901
                        AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
1✔
902
                        AnnotationAppender.Default.apply(annotationVisitor,
1✔
903
                                methodDescription.getReturnType().asErasure(),
1✔
904
                                AnnotationAppender.NO_NAME,
905
                                annotationValue.resolve());
1✔
906
                        annotationVisitor.visitEnd();
1✔
907
                    }
1✔
908

909
                    /**
910
                     * {@inheritDoc}
911
                     */
912
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
913
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
914
                    }
1✔
915

916
                    /**
917
                     * {@inheritDoc}
918
                     */
919
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
920
                        throw new IllegalStateException("Cannot apply attributes for default value on " + methodDescription);
1✔
921
                    }
922

923
                    /**
924
                     * {@inheritDoc}
925
                     */
926
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
927
                        throw new IllegalStateException("Cannot apply code for default value on " + methodDescription);
1✔
928
                    }
929

930
                    /**
931
                     * {@inheritDoc}
932
                     */
933
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
934
                        throw new IllegalStateException("Cannot prepend code for default value on " + methodDescription);
1✔
935
                    }
936
                }
937

938
                /**
939
                 * A record for a visibility bridge.
940
                 */
941
                @HashCodeAndEqualsPlugin.Enhance
942
                public static class OfVisibilityBridge extends ForDefinedMethod implements ByteCodeAppender {
943

944
                    /**
945
                     * The visibility bridge.
946
                     */
947
                    private final MethodDescription visibilityBridge;
948

949
                    /**
950
                     * The method the visibility bridge invokes.
951
                     */
952
                    private final MethodDescription bridgeTarget;
953

954
                    /**
955
                     * The type on which the bridge method is invoked.
956
                     */
957
                    private final TypeDescription bridgeType;
958

959
                    /**
960
                     * The attribute appender to apply to the visibility bridge.
961
                     */
962
                    private final MethodAttributeAppender attributeAppender;
963

964
                    /**
965
                     * Creates a new record for a visibility bridge.
966
                     *
967
                     * @param visibilityBridge  The visibility bridge.
968
                     * @param bridgeTarget      The method the visibility bridge invokes.
969
                     * @param bridgeType        The type of the instrumented type.
970
                     * @param attributeAppender The attribute appender to apply to the visibility bridge.
971
                     */
972
                    protected OfVisibilityBridge(MethodDescription visibilityBridge,
973
                                                 MethodDescription bridgeTarget,
974
                                                 TypeDescription bridgeType,
975
                                                 MethodAttributeAppender attributeAppender) {
1✔
976
                        this.visibilityBridge = visibilityBridge;
1✔
977
                        this.bridgeTarget = bridgeTarget;
1✔
978
                        this.bridgeType = bridgeType;
1✔
979
                        this.attributeAppender = attributeAppender;
1✔
980
                    }
1✔
981

982
                    /**
983
                     * Creates a record for a visibility bridge.
984
                     *
985
                     * @param instrumentedType  The instrumented type.
986
                     * @param bridgeTarget      The target method of the visibility bridge.
987
                     * @param attributeAppender The attribute appender to apply to the visibility bridge.
988
                     * @return A record describing the visibility bridge.
989
                     */
990
                    public static Record of(TypeDescription instrumentedType, MethodDescription bridgeTarget, MethodAttributeAppender attributeAppender) {
991
                        // Default method bridges must be dispatched on an implemented interface type, not considering the declaring type.
992
                        TypeDefinition bridgeType = null;
1✔
993
                        if (bridgeTarget.isDefaultMethod()) {
1✔
994
                            TypeDescription declaringType = bridgeTarget.getDeclaringType().asErasure();
1✔
995
                            for (TypeDescription interfaceType : instrumentedType.getInterfaces().asErasures().filter(isSubTypeOf(declaringType))) {
1✔
996
                                if (bridgeType == null || declaringType.isAssignableTo(bridgeType.asErasure())) {
1✔
997
                                    bridgeType = interfaceType;
1✔
998
                                }
999
                            }
1✔
1000
                        }
1001
                        // Non-default method or default method that is inherited by a super class.
1002
                        if (bridgeType == null) {
1✔
1003
                            bridgeType = instrumentedType.getSuperClass();
1✔
1004
                            if (bridgeType == null) {
1✔
1005
                                bridgeType = TypeDescription.ForLoadedType.of(Object.class);
×
1006
                            }
1007
                        }
1008
                        return new OfVisibilityBridge(new VisibilityBridge(instrumentedType, bridgeTarget),
1✔
1009
                                bridgeTarget,
1010
                                bridgeType.asErasure(),
1✔
1011
                                attributeAppender);
1012
                    }
1013

1014
                    /**
1015
                     * {@inheritDoc}
1016
                     */
1017
                    public MethodDescription getMethod() {
1018
                        return visibilityBridge;
1✔
1019
                    }
1020

1021
                    /**
1022
                     * {@inheritDoc}
1023
                     */
1024
                    public Sort getSort() {
1025
                        return Sort.IMPLEMENTED;
1✔
1026
                    }
1027

1028
                    /**
1029
                     * {@inheritDoc}
1030
                     */
1031
                    public Visibility getVisibility() {
1032
                        return bridgeTarget.getVisibility();
1✔
1033
                    }
1034

1035
                    /**
1036
                     * {@inheritDoc}
1037
                     */
1038
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
1039
                        return new ForDefinedMethod.WithBody(visibilityBridge,
1✔
1040
                                new ByteCodeAppender.Compound(this, byteCodeAppender),
1041
                                attributeAppender,
1042
                                bridgeTarget.getVisibility());
1✔
1043
                    }
1044

1045
                    /**
1046
                     * {@inheritDoc}
1047
                     */
1048
                    public void applyHead(MethodVisitor methodVisitor) {
1049
                        /* do nothing */
1050
                    }
1✔
1051

1052
                    /**
1053
                     * {@inheritDoc}
1054
                     */
1055
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1056
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
1057
                        methodVisitor.visitCode();
1✔
1058
                        ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
1✔
1059
                        methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
1060
                    }
1✔
1061

1062
                    /**
1063
                     * {@inheritDoc}
1064
                     */
1065
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1066
                        attributeAppender.apply(methodVisitor, visibilityBridge, annotationValueFilterFactory.on(visibilityBridge));
1✔
1067
                    }
1✔
1068

1069
                    /**
1070
                     * {@inheritDoc}
1071
                     */
1072
                    public Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1073
                        return apply(methodVisitor, implementationContext, visibilityBridge);
1✔
1074
                    }
1075

1076
                    /**
1077
                     * {@inheritDoc}
1078
                     */
1079
                    public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1080
                        return new ByteCodeAppender.Simple(
1✔
1081
                                MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
1✔
1082
                                MethodInvocation.invoke(bridgeTarget).special(bridgeType),
1✔
1083
                                MethodReturn.of(instrumentedMethod.getReturnType())
1✔
1084
                        ).apply(methodVisitor, implementationContext, instrumentedMethod);
1✔
1085
                    }
1086

1087
                    /**
1088
                     * A method describing a visibility bridge.
1089
                     */
1090
                    protected static class VisibilityBridge extends MethodDescription.InDefinedShape.AbstractBase {
1091

1092
                        /**
1093
                         * The instrumented type.
1094
                         */
1095
                        private final TypeDescription instrumentedType;
1096

1097
                        /**
1098
                         * The method that is the target of the bridge.
1099
                         */
1100
                        private final MethodDescription bridgeTarget;
1101

1102
                        /**
1103
                         * Creates a new visibility bridge.
1104
                         *
1105
                         * @param instrumentedType The instrumented type.
1106
                         * @param bridgeTarget     The method that is the target of the bridge.
1107
                         */
1108
                        protected VisibilityBridge(TypeDescription instrumentedType, MethodDescription bridgeTarget) {
1✔
1109
                            this.instrumentedType = instrumentedType;
1✔
1110
                            this.bridgeTarget = bridgeTarget;
1✔
1111
                        }
1✔
1112

1113
                        /**
1114
                         * {@inheritDoc}
1115
                         */
1116
                        @Nonnull
1117
                        public TypeDescription getDeclaringType() {
1118
                            return instrumentedType;
1✔
1119
                        }
1120

1121
                        /**
1122
                         * {@inheritDoc}
1123
                         */
1124
                        public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1125
                            return new ParameterList.Explicit.ForTypes(this, bridgeTarget.getParameters().asTypeList().asRawTypes());
1✔
1126
                        }
1127

1128
                        /**
1129
                         * {@inheritDoc}
1130
                         */
1131
                        public TypeDescription.Generic getReturnType() {
1132
                            return bridgeTarget.getReturnType().asRawType();
1✔
1133
                        }
1134

1135
                        /**
1136
                         * {@inheritDoc}
1137
                         */
1138
                        public TypeList.Generic getExceptionTypes() {
1139
                            return bridgeTarget.getExceptionTypes().asRawTypes();
1✔
1140
                        }
1141

1142
                        /**
1143
                         * {@inheritDoc}
1144
                         */
1145
                        @MaybeNull
1146
                        public AnnotationValue<?, ?> getDefaultValue() {
1147
                            return AnnotationValue.UNDEFINED;
×
1148
                        }
1149

1150
                        /**
1151
                         * {@inheritDoc}
1152
                         */
1153
                        public TypeList.Generic getTypeVariables() {
1154
                            return new TypeList.Generic.Empty();
1✔
1155
                        }
1156

1157
                        /**
1158
                         * {@inheritDoc}
1159
                         */
1160
                        public AnnotationList getDeclaredAnnotations() {
1161
                            return bridgeTarget.getDeclaredAnnotations();
1✔
1162
                        }
1163

1164
                        /**
1165
                         * {@inheritDoc}
1166
                         */
1167
                        public int getModifiers() {
1168
                            return (bridgeTarget.getModifiers() | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_BRIDGE) & ~Opcodes.ACC_NATIVE;
1✔
1169
                        }
1170

1171
                        /**
1172
                         * {@inheritDoc}
1173
                         */
1174
                        public String getInternalName() {
1175
                            return bridgeTarget.getName();
1✔
1176
                        }
1177
                    }
1178
                }
1179
            }
1180

1181
            /**
1182
             * A wrapper that appends accessor bridges for a method's implementation. The bridges are only added if
1183
             * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool.Record#apply(ClassVisitor, Implementation.Context, AnnotationValueFilter.Factory)}
1184
             * is invoked such that bridges are not appended for methods that are rebased or redefined as such types already have bridge methods in place.
1185
             */
1186
            @HashCodeAndEqualsPlugin.Enhance
1187
            class AccessBridgeWrapper implements Record {
1188

1189
                /**
1190
                 * The delegate for implementing the bridge's target.
1191
                 */
1192
                private final Record delegate;
1193

1194
                /**
1195
                 * The instrumented type that defines the bridge methods and the bridge target.
1196
                 */
1197
                private final TypeDescription instrumentedType;
1198

1199
                /**
1200
                 * The target of the bridge method.
1201
                 */
1202
                private final MethodDescription bridgeTarget;
1203

1204
                /**
1205
                 * A collection of all tokens representing all bridge methods.
1206
                 */
1207
                private final Set<MethodDescription.TypeToken> bridgeTypes;
1208

1209
                /**
1210
                 * The attribute appender being applied for the bridge target.
1211
                 */
1212
                private final MethodAttributeAppender attributeAppender;
1213

1214
                /**
1215
                 * Creates a wrapper for adding accessor bridges.
1216
                 *
1217
                 * @param delegate          The delegate for implementing the bridge's target.
1218
                 * @param instrumentedType  The instrumented type that defines the bridge methods and the bridge target.
1219
                 * @param bridgeTarget      The target of the bridge method.
1220
                 * @param bridgeTypes       A collection of all tokens representing all bridge methods.
1221
                 * @param attributeAppender The attribute appender being applied for the bridge target.
1222
                 */
1223
                protected AccessBridgeWrapper(Record delegate,
1224
                                              TypeDescription instrumentedType,
1225
                                              MethodDescription bridgeTarget,
1226
                                              Set<MethodDescription.TypeToken> bridgeTypes,
1227
                                              MethodAttributeAppender attributeAppender) {
1✔
1228
                    this.delegate = delegate;
1✔
1229
                    this.instrumentedType = instrumentedType;
1✔
1230
                    this.bridgeTarget = bridgeTarget;
1✔
1231
                    this.bridgeTypes = bridgeTypes;
1✔
1232
                    this.attributeAppender = attributeAppender;
1✔
1233
                }
1✔
1234

1235
                /**
1236
                 * Wraps the given record in an accessor bridge wrapper if necessary.
1237
                 *
1238
                 * @param delegate          The delegate for implementing the bridge's target.
1239
                 * @param instrumentedType  The instrumented type that defines the bridge methods and the bridge target.
1240
                 * @param bridgeTarget      The bridge methods' target methods.
1241
                 * @param bridgeTypes       A collection of all tokens representing all bridge methods.
1242
                 * @param attributeAppender The attribute appender being applied for the bridge target.
1243
                 * @return The given record wrapped by a bridge method wrapper if necessary.
1244
                 */
1245
                public static Record of(Record delegate,
1246
                                        TypeDescription instrumentedType,
1247
                                        MethodDescription bridgeTarget,
1248
                                        Set<MethodDescription.TypeToken> bridgeTypes,
1249
                                        MethodAttributeAppender attributeAppender) {
1250
                    Set<MethodDescription.TypeToken> compatibleBridgeTypes = new HashSet<MethodDescription.TypeToken>();
1✔
1251
                    for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1✔
1252
                        if (bridgeTarget.isBridgeCompatible(bridgeType)) {
1✔
1253
                            compatibleBridgeTypes.add(bridgeType);
1✔
1254
                        }
1255
                    }
1✔
1256
                    return compatibleBridgeTypes.isEmpty() || (instrumentedType.isInterface() && !delegate.getSort().isImplemented())
1✔
1257
                            ? delegate
1258
                            : new AccessBridgeWrapper(delegate, instrumentedType, bridgeTarget, compatibleBridgeTypes, attributeAppender);
1259
                }
1260

1261
                /**
1262
                 * {@inheritDoc}
1263
                 */
1264
                public Sort getSort() {
1265
                    return delegate.getSort();
1✔
1266
                }
1267

1268
                /**
1269
                 * {@inheritDoc}
1270
                 */
1271
                public MethodDescription getMethod() {
1272
                    return bridgeTarget;
×
1273
                }
1274

1275
                /**
1276
                 * {@inheritDoc}
1277
                 */
1278
                public Visibility getVisibility() {
1279
                    return delegate.getVisibility();
1✔
1280
                }
1281

1282
                /**
1283
                 * {@inheritDoc}
1284
                 */
1285
                public Record prepend(ByteCodeAppender byteCodeAppender) {
1286
                    return new AccessBridgeWrapper(delegate.prepend(byteCodeAppender), instrumentedType, bridgeTarget, bridgeTypes, attributeAppender);
1✔
1287
                }
1288

1289
                /**
1290
                 * {@inheritDoc}
1291
                 */
1292
                public void apply(ClassVisitor classVisitor,
1293
                                  Implementation.Context implementationContext,
1294
                                  AnnotationValueFilter.Factory annotationValueFilterFactory) {
1295
                    delegate.apply(classVisitor, implementationContext, annotationValueFilterFactory);
1✔
1296
                    for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1✔
1297
                        MethodDescription.InDefinedShape bridgeMethod = new AccessorBridge(bridgeTarget, bridgeType, instrumentedType);
1✔
1298
                        MethodDescription.InDefinedShape bridgeTarget = new BridgeTarget(this.bridgeTarget, instrumentedType);
1✔
1299
                        MethodVisitor methodVisitor = classVisitor.visitMethod(bridgeMethod.getActualModifiers(true, getVisibility()),
1✔
1300
                                bridgeMethod.getInternalName(),
1✔
1301
                                bridgeMethod.getDescriptor(),
1✔
1302
                                MethodDescription.NON_GENERIC_SIGNATURE,
1303
                                bridgeMethod.getExceptionTypes().asErasures().toInternalNames());
1✔
1304
                        if (methodVisitor != null) {
1✔
1305
                            attributeAppender.apply(methodVisitor, bridgeMethod, annotationValueFilterFactory.on(instrumentedType));
1✔
1306
                            methodVisitor.visitCode();
1✔
1307
                            ByteCodeAppender.Size size = new ByteCodeAppender.Simple(
1✔
1308
                                    MethodVariableAccess.allArgumentsOf(bridgeMethod).asBridgeOf(bridgeTarget).prependThisReference(),
1✔
1309
                                    MethodInvocation.invoke(bridgeTarget).virtual(instrumentedType),
1✔
1310
                                    bridgeTarget.getReturnType().asErasure().isAssignableTo(bridgeMethod.getReturnType().asErasure())
1✔
1311
                                            ? StackManipulation.Trivial.INSTANCE
1312
                                            : TypeCasting.to(bridgeMethod.getReturnType().asErasure()),
1✔
1313
                                    MethodReturn.of(bridgeMethod.getReturnType())
1✔
1314
                            ).apply(methodVisitor, implementationContext, bridgeMethod);
1✔
1315
                            methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
1316
                            methodVisitor.visitEnd();
1✔
1317
                        }
1318
                    }
1✔
1319
                }
1✔
1320

1321
                /**
1322
                 * {@inheritDoc}
1323
                 */
1324
                public void applyHead(MethodVisitor methodVisitor) {
1325
                    delegate.applyHead(methodVisitor);
1✔
1326
                }
1✔
1327

1328
                /**
1329
                 * {@inheritDoc}
1330
                 */
1331
                public void applyBody(MethodVisitor methodVisitor,
1332
                                      Implementation.Context implementationContext,
1333
                                      AnnotationValueFilter.Factory annotationValueFilterFactory) {
1334
                    delegate.applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
1✔
1335
                }
1✔
1336

1337
                /**
1338
                 * {@inheritDoc}
1339
                 */
1340
                public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1341
                    delegate.applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
1342
                }
1✔
1343

1344
                /**
1345
                 * {@inheritDoc}
1346
                 */
1347
                public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1348
                    return delegate.applyCode(methodVisitor, implementationContext);
1✔
1349
                }
1350

1351
                /**
1352
                 * A method representing an accessor bridge method.
1353
                 */
1354
                protected static class AccessorBridge extends MethodDescription.InDefinedShape.AbstractBase {
1355

1356
                    /**
1357
                     * The target method of the bridge.
1358
                     */
1359
                    private final MethodDescription bridgeTarget;
1360

1361
                    /**
1362
                     * The bridge's type token.
1363
                     */
1364
                    private final MethodDescription.TypeToken bridgeType;
1365

1366
                    /**
1367
                     * The instrumented type defining the bridge target.
1368
                     */
1369
                    private final TypeDescription instrumentedType;
1370

1371
                    /**
1372
                     * Creates a new accessor bridge method.
1373
                     *
1374
                     * @param bridgeTarget     The target method of the bridge.
1375
                     * @param bridgeType       The bridge's type token.
1376
                     * @param instrumentedType The instrumented type defining the bridge target.
1377
                     */
1378
                    protected AccessorBridge(MethodDescription bridgeTarget, TypeToken bridgeType, TypeDescription instrumentedType) {
1✔
1379
                        this.bridgeTarget = bridgeTarget;
1✔
1380
                        this.bridgeType = bridgeType;
1✔
1381
                        this.instrumentedType = instrumentedType;
1✔
1382
                    }
1✔
1383

1384
                    /**
1385
                     * {@inheritDoc}
1386
                     */
1387
                    @Nonnull
1388
                    public TypeDescription getDeclaringType() {
1389
                        return instrumentedType;
1✔
1390
                    }
1391

1392
                    /**
1393
                     * {@inheritDoc}
1394
                     */
1395
                    public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1396
                        return new ParameterList.Explicit.ForTypes(this, bridgeType.getParameterTypes());
1✔
1397
                    }
1398

1399
                    /**
1400
                     * {@inheritDoc}
1401
                     */
1402
                    public TypeDescription.Generic getReturnType() {
1403
                        return bridgeType.getReturnType().asGenericType();
1✔
1404
                    }
1405

1406
                    /**
1407
                     * {@inheritDoc}
1408
                     */
1409
                    public TypeList.Generic getExceptionTypes() {
1410
                        return bridgeTarget.getExceptionTypes().accept(TypeDescription.Generic.Visitor.TypeErasing.INSTANCE);
1✔
1411
                    }
1412

1413
                    /**
1414
                     * {@inheritDoc}
1415
                     */
1416
                    @MaybeNull
1417
                    public AnnotationValue<?, ?> getDefaultValue() {
1418
                        return AnnotationValue.UNDEFINED;
×
1419
                    }
1420

1421
                    /**
1422
                     * {@inheritDoc}
1423
                     */
1424
                    public TypeList.Generic getTypeVariables() {
1425
                        return new TypeList.Generic.Empty();
1✔
1426
                    }
1427

1428
                    /**
1429
                     * {@inheritDoc}
1430
                     */
1431
                    public AnnotationList getDeclaredAnnotations() {
1432
                        return new AnnotationList.Empty();
1✔
1433
                    }
1434

1435
                    /**
1436
                     * {@inheritDoc}
1437
                     */
1438
                    public int getModifiers() {
1439
                        return (bridgeTarget.getModifiers() | Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC) & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE);
1✔
1440
                    }
1441

1442
                    /**
1443
                     * {@inheritDoc}
1444
                     */
1445
                    public String getInternalName() {
1446
                        return bridgeTarget.getInternalName();
1✔
1447
                    }
1448
                }
1449

1450
                /**
1451
                 * A method representing a bridge's target method in its defined shape.
1452
                 */
1453
                protected static class BridgeTarget extends MethodDescription.InDefinedShape.AbstractBase {
1454

1455
                    /**
1456
                     * The target method of the bridge.
1457
                     */
1458
                    private final MethodDescription bridgeTarget;
1459

1460
                    /**
1461
                     * The instrumented type defining the bridge target.
1462
                     */
1463
                    private final TypeDescription instrumentedType;
1464

1465
                    /**
1466
                     * Creates a new bridge target.
1467
                     *
1468
                     * @param bridgeTarget     The target method of the bridge.
1469
                     * @param instrumentedType The instrumented type defining the bridge target.
1470
                     */
1471
                    protected BridgeTarget(MethodDescription bridgeTarget, TypeDescription instrumentedType) {
1✔
1472
                        this.bridgeTarget = bridgeTarget;
1✔
1473
                        this.instrumentedType = instrumentedType;
1✔
1474
                    }
1✔
1475

1476
                    /**
1477
                     * {@inheritDoc}
1478
                     */
1479
                    @Nonnull
1480
                    public TypeDescription getDeclaringType() {
1481
                        return instrumentedType;
1✔
1482
                    }
1483

1484
                    /**
1485
                     * {@inheritDoc}
1486
                     */
1487
                    public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1488
                        return new ParameterList.ForTokens(this, bridgeTarget.getParameters().asTokenList(is(instrumentedType)));
1✔
1489
                    }
1490

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

1498
                    /**
1499
                     * {@inheritDoc}
1500
                     */
1501
                    public TypeList.Generic getExceptionTypes() {
1502
                        return bridgeTarget.getExceptionTypes();
×
1503
                    }
1504

1505
                    /**
1506
                     * {@inheritDoc}
1507
                     */
1508
                    @MaybeNull
1509
                    public AnnotationValue<?, ?> getDefaultValue() {
1510
                        return bridgeTarget.getDefaultValue();
×
1511
                    }
1512

1513
                    /**
1514
                     * {@inheritDoc}
1515
                     */
1516
                    public TypeList.Generic getTypeVariables() {
1517
                        return bridgeTarget.getTypeVariables();
×
1518
                    }
1519

1520
                    /**
1521
                     * {@inheritDoc}
1522
                     */
1523
                    public AnnotationList getDeclaredAnnotations() {
1524
                        return bridgeTarget.getDeclaredAnnotations();
×
1525
                    }
1526

1527
                    /**
1528
                     * {@inheritDoc}
1529
                     */
1530
                    public int getModifiers() {
1531
                        return bridgeTarget.getModifiers();
1✔
1532
                    }
1533

1534
                    /**
1535
                     * {@inheritDoc}
1536
                     */
1537
                    public String getInternalName() {
1538
                        return bridgeTarget.getInternalName();
1✔
1539
                    }
1540
                }
1541
            }
1542
        }
1543
    }
1544

1545
    /**
1546
     * An record component pool that allows a lookup for how to implement a record component.
1547
     */
1548
    interface RecordComponentPool {
1549

1550
        /**
1551
         * Looks up a handler entry for a given record component.
1552
         *
1553
         * @param recordComponentDescription The record component being processed.
1554
         * @return A handler entry for the given record component.
1555
         */
1556
        Record target(RecordComponentDescription recordComponentDescription);
1557

1558
        /**
1559
         * An entry of a record component pool that describes how a record component is implemented.
1560
         *
1561
         * @see RecordComponentPool
1562
         */
1563
        interface Record {
1564

1565
            /**
1566
             * Determines if this record is implicit, i.e is not defined by a {@link RecordComponentPool}.
1567
             *
1568
             * @return {@code true} if this record is implicit.
1569
             */
1570
            boolean isImplicit();
1571

1572
            /**
1573
             * Returns the record component that this record represents.
1574
             *
1575
             * @return The record component that this record represents.
1576
             */
1577
            RecordComponentDescription getRecordComponent();
1578

1579
            /**
1580
             * Returns the record component attribute appender for a given record component.
1581
             *
1582
             * @return The record component appender to be applied on the given field.
1583
             */
1584
            RecordComponentAttributeAppender getRecordComponentAppender();
1585

1586
            /**
1587
             * Writes this record to a given class visitor.
1588
             *
1589
             * @param classVisitor                 The class visitor to which this record is to be written to.
1590
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
1591
             */
1592
            void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1593

1594
            /**
1595
             * Applies this record to a record component visitor. This is not possible for implicit records.
1596
             *
1597
             * @param recordComponentVisitor       The record component visitor onto which this record is to be applied.
1598
             * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
1599
             */
1600
            void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1601

1602
            /**
1603
             * A record for a simple field without a default value where all of the record component's declared annotations are appended.
1604
             */
1605
            @HashCodeAndEqualsPlugin.Enhance
1606
            class ForImplicitRecordComponent implements Record {
1607

1608
                /**
1609
                 * The implemented record component.
1610
                 */
1611
                private final RecordComponentDescription recordComponentDescription;
1612

1613
                /**
1614
                 * Creates a new record for a simple record component.
1615
                 *
1616
                 * @param recordComponentDescription The described record component.
1617
                 */
1618
                public ForImplicitRecordComponent(RecordComponentDescription recordComponentDescription) {
1✔
1619
                    this.recordComponentDescription = recordComponentDescription;
1✔
1620
                }
1✔
1621

1622
                /**
1623
                 * {@inheritDoc}
1624
                 */
1625
                public boolean isImplicit() {
1626
                    return true;
1✔
1627
                }
1628

1629
                /**
1630
                 * {@inheritDoc}
1631
                 */
1632
                public RecordComponentDescription getRecordComponent() {
1633
                    return recordComponentDescription;
×
1634
                }
1635

1636
                /**
1637
                 * {@inheritDoc}
1638
                 */
1639
                public RecordComponentAttributeAppender getRecordComponentAppender() {
1640
                    throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
×
1641
                }
1642

1643
                /**
1644
                 * {@inheritDoc}
1645
                 */
1646
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1647
                    RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1✔
1648
                            recordComponentDescription.getDescriptor(),
1✔
1649
                            recordComponentDescription.getGenericSignature());
1✔
1650
                    if (recordComponentVisitor != null) {
1✔
1651
                        RecordComponentAttributeAppender.ForInstrumentedRecordComponent.INSTANCE.apply(recordComponentVisitor,
1✔
1652
                                recordComponentDescription,
1653
                                annotationValueFilterFactory.on(recordComponentDescription));
1✔
1654
                        recordComponentVisitor.visitEnd();
1✔
1655
                    }
1656
                }
1✔
1657

1658
                /**
1659
                 * {@inheritDoc}
1660
                 */
1661
                public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1662
                    throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
1✔
1663
                }
1664
            }
1665

1666
            /**
1667
             * A record for a rich record component with attributes.
1668
             */
1669
            @HashCodeAndEqualsPlugin.Enhance
1670
            class ForExplicitRecordComponent implements Record {
1671

1672
                /**
1673
                 * The attribute appender for the record component.
1674
                 */
1675
                private final RecordComponentAttributeAppender attributeAppender;
1676

1677
                /**
1678
                 * The implemented record component.
1679
                 */
1680
                private final RecordComponentDescription recordComponentDescription;
1681

1682
                /**
1683
                 * Creates a record for a rich record component.
1684
                 *
1685
                 * @param attributeAppender          The attribute appender for the record component.
1686
                 * @param recordComponentDescription The implemented record component.
1687
                 */
1688
                public ForExplicitRecordComponent(RecordComponentAttributeAppender attributeAppender, RecordComponentDescription recordComponentDescription) {
1✔
1689
                    this.attributeAppender = attributeAppender;
1✔
1690
                    this.recordComponentDescription = recordComponentDescription;
1✔
1691
                }
1✔
1692

1693
                /**
1694
                 * {@inheritDoc}
1695
                 */
1696
                public boolean isImplicit() {
1697
                    return false;
1✔
1698
                }
1699

1700
                /**
1701
                 * {@inheritDoc}
1702
                 */
1703
                public RecordComponentDescription getRecordComponent() {
1704
                    return recordComponentDescription;
×
1705
                }
1706

1707
                /**
1708
                 * {@inheritDoc}
1709
                 */
1710
                public RecordComponentAttributeAppender getRecordComponentAppender() {
1711
                    return attributeAppender;
1✔
1712
                }
1713

1714
                /**
1715
                 * {@inheritDoc}
1716
                 */
1717
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1718
                    RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1✔
1719
                            recordComponentDescription.getDescriptor(),
1✔
1720
                            recordComponentDescription.getGenericSignature());
1✔
1721
                    if (recordComponentVisitor != null) {
1✔
1722
                        attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1✔
1723
                        recordComponentVisitor.visitEnd();
1✔
1724
                    }
1725
                }
1✔
1726

1727
                /**
1728
                 * {@inheritDoc}
1729
                 */
1730
                public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1731
                    attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1✔
1732
                }
1✔
1733
            }
1734
        }
1735

1736
        /**
1737
         * A record component pool that does not allow any look ups.
1738
         */
1739
        enum Disabled implements RecordComponentPool {
1✔
1740

1741
            /**
1742
             * The singleton instance.
1743
             */
1744
            INSTANCE;
1✔
1745

1746
            /**
1747
             * {@inheritDoc}
1748
             */
1749
            public Record target(RecordComponentDescription recordComponentDescription) {
1750
                throw new IllegalStateException("Cannot look up record component from disabled pool");
1✔
1751
            }
1752
        }
1753
    }
1754

1755
    /**
1756
     * A default implementation of a {@link net.bytebuddy.dynamic.scaffold.TypeWriter}.
1757
     *
1758
     * @param <S> The best known loaded type for the dynamically created type.
1759
     */
1760
    @HashCodeAndEqualsPlugin.Enhance
1761
    abstract class Default<S> implements TypeWriter<S> {
1762

1763
        /**
1764
         * Indicates an empty reference in a class file which is expressed by {@code null}.
1765
         */
1766
        @AlwaysNull
1767
        private static final String NO_REFERENCE = null;
1✔
1768

1769
        /**
1770
         * A folder for dumping class files or {@code null} if no dump should be generated.
1771
         */
1772
        @MaybeNull
1773
        protected static final String DUMP_FOLDER;
1774

1775
        /*
1776
         * Reads the dumping property that is set at program start up. This might cause an error because of security constraints.
1777
         */
1778
        static {
1779
            String dumpFolder;
1780
            try {
1781
                dumpFolder = doPrivileged(new GetSystemPropertyAction(DUMP_PROPERTY));
1✔
1782
            } catch (RuntimeException exception) {
×
1783
                dumpFolder = null;
×
1784
            }
1✔
1785
            DUMP_FOLDER = dumpFolder;
1✔
1786
        }
1✔
1787

1788
        /**
1789
         * The instrumented type to be created.
1790
         */
1791
        protected final TypeDescription instrumentedType;
1792

1793
        /**
1794
         * The class file specified by the user.
1795
         */
1796
        protected final ClassFileVersion classFileVersion;
1797

1798
        /**
1799
         * The field pool to use.
1800
         */
1801
        protected final FieldPool fieldPool;
1802

1803
        /**
1804
         * The record component pool to use.
1805
         */
1806
        protected final RecordComponentPool recordComponentPool;
1807

1808
        /**
1809
         * The explicit auxiliary types to add to the created type.
1810
         */
1811
        protected final List<? extends DynamicType> auxiliaryTypes;
1812

1813
        /**
1814
         * The instrumented type's declared fields.
1815
         */
1816
        protected final FieldList<FieldDescription.InDefinedShape> fields;
1817

1818
        /**
1819
         * The instrumented type's methods that are declared or inherited.
1820
         */
1821
        protected final MethodList<?> methods;
1822

1823
        /**
1824
         * The instrumented methods relevant to this type creation.
1825
         */
1826
        protected final MethodList<?> instrumentedMethods;
1827

1828
        /**
1829
         * The instrumented type's record components.
1830
         */
1831
        protected final RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents;
1832

1833
        /**
1834
         * The loaded type initializer to apply onto the created type after loading.
1835
         */
1836
        protected final LoadedTypeInitializer loadedTypeInitializer;
1837

1838
        /**
1839
         * The type initializer to include in the created type's type initializer.
1840
         */
1841
        protected final TypeInitializer typeInitializer;
1842

1843
        /**
1844
         * The type attribute appender to apply onto the instrumented type.
1845
         */
1846
        protected final TypeAttributeAppender typeAttributeAppender;
1847

1848
        /**
1849
         * The ASM visitor wrapper to apply onto the class writer.
1850
         */
1851
        protected final AsmVisitorWrapper asmVisitorWrapper;
1852

1853
        /**
1854
         * The annotation value filter factory to apply.
1855
         */
1856
        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
1857

1858
        /**
1859
         * The annotation retention to apply.
1860
         */
1861
        protected final AnnotationRetention annotationRetention;
1862

1863
        /**
1864
         * The naming strategy for auxiliary types to apply.
1865
         */
1866
        protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
1867

1868
        /**
1869
         * The implementation context factory to apply.
1870
         */
1871
        protected final Implementation.Context.Factory implementationContextFactory;
1872

1873
        /**
1874
         * Determines if a type should be explicitly validated.
1875
         */
1876
        protected final TypeValidation typeValidation;
1877

1878
        /**
1879
         * The class reader factory to use.
1880
         */
1881
        protected final AsmClassReader.Factory classReaderFactory;
1882

1883
        /**
1884
         * The class writer factory to use.
1885
         */
1886
        protected final AsmClassWriter.Factory classWriterFactory;
1887

1888
        /**
1889
         * The type pool to use for computing stack map frames, if required.
1890
         */
1891
        protected final TypePool typePool;
1892

1893
        /**
1894
         * Creates a new default type writer.
1895
         *
1896
         * @param instrumentedType             The instrumented type to be created.
1897
         * @param classFileVersion             The class file specified by the user.
1898
         * @param fieldPool                    The field pool to use.
1899
         * @param recordComponentPool          The record component pool to use.
1900
         * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
1901
         * @param fields                       The instrumented type's declared fields.
1902
         * @param methods                      The instrumented type's declared and virtually inherited methods.
1903
         * @param instrumentedMethods          The instrumented methods relevant to this type creation.
1904
         * @param recordComponents             The instrumented type's record components.
1905
         * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
1906
         * @param typeInitializer              The type initializer to include in the created type's type initializer.
1907
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
1908
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
1909
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
1910
         * @param annotationRetention          The annotation retention to apply.
1911
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
1912
         * @param implementationContextFactory The implementation context factory to apply.
1913
         * @param typeValidation               Determines if a type should be explicitly validated.
1914
         * @param classReaderFactory           The class reader factory to use.
1915
         * @param classWriterFactory           The class writer factory to use.
1916
         * @param typePool                     The type pool to use for computing stack map frames, if required.
1917
         */
1918
        protected Default(TypeDescription instrumentedType,
1919
                          ClassFileVersion classFileVersion,
1920
                          FieldPool fieldPool,
1921
                          RecordComponentPool recordComponentPool,
1922
                          List<? extends DynamicType> auxiliaryTypes,
1923
                          FieldList<FieldDescription.InDefinedShape> fields,
1924
                          MethodList<?> methods,
1925
                          MethodList<?> instrumentedMethods,
1926
                          RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
1927
                          LoadedTypeInitializer loadedTypeInitializer,
1928
                          TypeInitializer typeInitializer,
1929
                          TypeAttributeAppender typeAttributeAppender,
1930
                          AsmVisitorWrapper asmVisitorWrapper,
1931
                          AnnotationValueFilter.Factory annotationValueFilterFactory,
1932
                          AnnotationRetention annotationRetention,
1933
                          AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1934
                          Implementation.Context.Factory implementationContextFactory,
1935
                          TypeValidation typeValidation,
1936
                          AsmClassReader.Factory classReaderFactory,
1937
                          AsmClassWriter.Factory classWriterFactory,
1938
                          TypePool typePool) {
1✔
1939
            this.instrumentedType = instrumentedType;
1✔
1940
            this.classFileVersion = classFileVersion;
1✔
1941
            this.fieldPool = fieldPool;
1✔
1942
            this.recordComponentPool = recordComponentPool;
1✔
1943
            this.auxiliaryTypes = auxiliaryTypes;
1✔
1944
            this.fields = fields;
1✔
1945
            this.methods = methods;
1✔
1946
            this.instrumentedMethods = instrumentedMethods;
1✔
1947
            this.recordComponents = recordComponents;
1✔
1948
            this.loadedTypeInitializer = loadedTypeInitializer;
1✔
1949
            this.typeInitializer = typeInitializer;
1✔
1950
            this.typeAttributeAppender = typeAttributeAppender;
1✔
1951
            this.asmVisitorWrapper = asmVisitorWrapper;
1✔
1952
            this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
1✔
1953
            this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
1954
            this.annotationRetention = annotationRetention;
1✔
1955
            this.implementationContextFactory = implementationContextFactory;
1✔
1956
            this.typeValidation = typeValidation;
1✔
1957
            this.classReaderFactory = classReaderFactory;
1✔
1958
            this.classWriterFactory = classWriterFactory;
1✔
1959
            this.typePool = typePool;
1✔
1960
        }
1✔
1961

1962
        /**
1963
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
1964
         *
1965
         * @param action The action to execute from a privileged context.
1966
         * @param <T>    The type of the action's resolved value.
1967
         * @return The action's resolved value.
1968
         */
1969
        @AccessControllerPlugin.Enhance
1970
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
1971
            return action.run();
×
1972
        }
1973

1974
        /**
1975
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
1976
         *
1977
         * @param action The action to execute from a privileged context.
1978
         * @param <T>    The type of the action's resolved value.
1979
         * @return The action's resolved value.
1980
         * @throws Exception If an exception occurs.
1981
         */
1982
        @AccessControllerPlugin.Enhance
1983
        private static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws Exception {
1984
            return action.run();
×
1985
        }
1986

1987
        /**
1988
         * Creates a type writer for creating a new type.
1989
         *
1990
         * @param methodRegistry               The compiled method registry to use.
1991
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
1992
         * @param fieldPool                    The field pool to use.
1993
         * @param recordComponentPool          The record component pool to use.
1994
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
1995
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
1996
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
1997
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
1998
         * @param annotationRetention          The annotation retention to apply.
1999
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2000
         * @param implementationContextFactory The implementation context factory to apply.
2001
         * @param typeValidation               Determines if a type should be explicitly validated.
2002
         * @param classReaderFactory           The class reader factory to use.
2003
         * @param classWriterFactory           The class writer factory to use.
2004
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2005
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2006
         * @return A suitable type writer.
2007
         */
2008
        public static <U> TypeWriter<U> forCreation(MethodRegistry.Compiled methodRegistry,
2009
                                                    List<? extends DynamicType> auxiliaryTypes,
2010
                                                    FieldPool fieldPool,
2011
                                                    RecordComponentPool recordComponentPool,
2012
                                                    TypeAttributeAppender typeAttributeAppender,
2013
                                                    AsmVisitorWrapper asmVisitorWrapper,
2014
                                                    ClassFileVersion classFileVersion,
2015
                                                    AnnotationValueFilter.Factory annotationValueFilterFactory,
2016
                                                    AnnotationRetention annotationRetention,
2017
                                                    AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2018
                                                    Implementation.Context.Factory implementationContextFactory,
2019
                                                    TypeValidation typeValidation,
2020
                                                    AsmClassReader.Factory classReaderFactory,
2021
                                                    AsmClassWriter.Factory classWriterFactory,
2022
                                                    TypePool typePool) {
2023
            return new ForCreation<U>(methodRegistry.getInstrumentedType(),
1✔
2024
                    classFileVersion,
2025
                    fieldPool,
2026
                    methodRegistry,
2027
                    recordComponentPool,
2028
                    auxiliaryTypes,
2029
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2030
                    methodRegistry.getMethods(),
1✔
2031
                    methodRegistry.getInstrumentedMethods(),
1✔
2032
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2033
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2034
                    methodRegistry.getTypeInitializer(),
1✔
2035
                    typeAttributeAppender,
2036
                    asmVisitorWrapper,
2037
                    annotationValueFilterFactory,
2038
                    annotationRetention,
2039
                    auxiliaryTypeNamingStrategy,
2040
                    implementationContextFactory,
2041
                    typeValidation,
2042
                    classReaderFactory,
2043
                    classWriterFactory,
2044
                    typePool);
2045
        }
2046

2047
        /**
2048
         * Creates a type writer for redefining a type.
2049
         *
2050
         * @param methodRegistry               The compiled method registry to use.
2051
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2052
         * @param fieldPool                    The field pool to use.
2053
         * @param recordComponentPool          The record component pool to use.
2054
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2055
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2056
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2057
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2058
         * @param annotationRetention          The annotation retention to apply.
2059
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2060
         * @param implementationContextFactory The implementation context factory to apply.
2061
         * @param typeValidation               Determines if a type should be explicitly validated.
2062
         * @param classReaderFactory           The class reader factory to use.
2063
         * @param classWriterFactory           The class writer factory to use.
2064
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2065
         * @param originalType                 The original type that is being redefined or rebased.
2066
         * @param classFileLocator             The class file locator for locating the original type's class file.
2067
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2068
         * @return A suitable type writer.
2069
         */
2070
        public static <U> TypeWriter<U> forRedefinition(MethodRegistry.Prepared methodRegistry,
2071
                                                        List<? extends DynamicType> auxiliaryTypes,
2072
                                                        FieldPool fieldPool,
2073
                                                        RecordComponentPool recordComponentPool,
2074
                                                        TypeAttributeAppender typeAttributeAppender,
2075
                                                        AsmVisitorWrapper asmVisitorWrapper,
2076
                                                        ClassFileVersion classFileVersion,
2077
                                                        AnnotationValueFilter.Factory annotationValueFilterFactory,
2078
                                                        AnnotationRetention annotationRetention,
2079
                                                        AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2080
                                                        Implementation.Context.Factory implementationContextFactory,
2081
                                                        TypeValidation typeValidation,
2082
                                                        AsmClassReader.Factory classReaderFactory,
2083
                                                        AsmClassWriter.Factory classWriterFactory,
2084
                                                        TypePool typePool,
2085
                                                        TypeDescription originalType,
2086
                                                        ClassFileLocator classFileLocator) {
2087
            return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
1✔
2088
                    classFileVersion,
2089
                    fieldPool,
2090
                    recordComponentPool,
2091
                    auxiliaryTypes,
2092
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2093
                    methodRegistry.getMethods(),
1✔
2094
                    methodRegistry.getInstrumentedMethods(),
1✔
2095
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2096
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2097
                    methodRegistry.getTypeInitializer(),
1✔
2098
                    typeAttributeAppender,
2099
                    asmVisitorWrapper,
2100
                    annotationValueFilterFactory,
2101
                    annotationRetention,
2102
                    auxiliaryTypeNamingStrategy,
2103
                    implementationContextFactory,
2104
                    typeValidation,
2105
                    classReaderFactory,
2106
                    classWriterFactory,
2107
                    typePool,
2108
                    originalType,
2109
                    classFileLocator,
2110
                    methodRegistry,
2111
                    SubclassImplementationTarget.Factory.LEVEL_TYPE,
2112
                    MethodRebaseResolver.Disabled.INSTANCE);
2113
        }
2114

2115
        /**
2116
         * Creates a type writer for rebasing a type.
2117
         *
2118
         * @param methodRegistry               The compiled method registry to use.
2119
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2120
         * @param fieldPool                    The field pool to use.
2121
         * @param recordComponentPool          The record component pool to use.
2122
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2123
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2124
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2125
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2126
         * @param annotationRetention          The annotation retention to apply.
2127
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2128
         * @param implementationContextFactory The implementation context factory to apply.
2129
         * @param typeValidation               Determines if a type should be explicitly validated.
2130
         * @param classReaderFactory           The class reader factory to use.
2131
         * @param classWriterFactory           The class writer factory to use.
2132
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2133
         * @param originalType                 The original type that is being redefined or rebased.
2134
         * @param classFileLocator             The class file locator for locating the original type's class file.
2135
         * @param methodRebaseResolver         The method rebase resolver to use for rebasing names.
2136
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2137
         * @return A suitable type writer.
2138
         */
2139
        public static <U> TypeWriter<U> forRebasing(MethodRegistry.Prepared methodRegistry,
2140
                                                    List<? extends DynamicType> auxiliaryTypes,
2141
                                                    FieldPool fieldPool,
2142
                                                    RecordComponentPool recordComponentPool,
2143
                                                    TypeAttributeAppender typeAttributeAppender,
2144
                                                    AsmVisitorWrapper asmVisitorWrapper,
2145
                                                    ClassFileVersion classFileVersion,
2146
                                                    AnnotationValueFilter.Factory annotationValueFilterFactory,
2147
                                                    AnnotationRetention annotationRetention,
2148
                                                    AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2149
                                                    Implementation.Context.Factory implementationContextFactory,
2150
                                                    TypeValidation typeValidation,
2151
                                                    AsmClassReader.Factory classReaderFactory,
2152
                                                    AsmClassWriter.Factory classWriterFactory,
2153
                                                    TypePool typePool,
2154
                                                    TypeDescription originalType,
2155
                                                    ClassFileLocator classFileLocator,
2156
                                                    MethodRebaseResolver methodRebaseResolver) {
2157
            return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
1✔
2158
                    classFileVersion,
2159
                    fieldPool,
2160
                    recordComponentPool,
2161
                    CompoundList.of(auxiliaryTypes, methodRebaseResolver.getAuxiliaryTypes()),
1✔
2162
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2163
                    methodRegistry.getMethods(),
1✔
2164
                    methodRegistry.getInstrumentedMethods(),
1✔
2165
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2166
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2167
                    methodRegistry.getTypeInitializer(),
1✔
2168
                    typeAttributeAppender,
2169
                    asmVisitorWrapper,
2170
                    annotationValueFilterFactory,
2171
                    annotationRetention,
2172
                    auxiliaryTypeNamingStrategy,
2173
                    implementationContextFactory,
2174
                    typeValidation,
2175
                    classReaderFactory,
2176
                    classWriterFactory,
2177
                    typePool,
2178
                    originalType,
2179
                    classFileLocator,
2180
                    methodRegistry,
2181
                    new RebaseImplementationTarget.Factory(methodRebaseResolver),
2182
                    methodRebaseResolver);
2183
        }
2184

2185
        /**
2186
         * Creates a type writer for decorating a type.
2187
         *
2188
         * @param instrumentedType             The instrumented type.
2189
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2190
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2191
         * @param methods                      The methods to instrument.
2192
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2193
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2194
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2195
         * @param annotationRetention          The annotation retention to apply.
2196
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2197
         * @param implementationContextFactory The implementation context factory to apply.
2198
         * @param typeValidation               Determines if a type should be explicitly validated.
2199
         * @param classReaderFactory           The class reader factory to use.
2200
         * @param classWriterFactory           The class writer factory to use.
2201
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2202
         * @param classFileLocator             The class file locator for locating the original type's class file.
2203
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2204
         * @return A suitable type writer.
2205
         */
2206
        public static <U> TypeWriter<U> forDecoration(TypeDescription instrumentedType,
2207
                                                      ClassFileVersion classFileVersion,
2208
                                                      List<? extends DynamicType> auxiliaryTypes,
2209
                                                      List<? extends MethodDescription> methods,
2210
                                                      TypeAttributeAppender typeAttributeAppender,
2211
                                                      AsmVisitorWrapper asmVisitorWrapper,
2212
                                                      AnnotationValueFilter.Factory annotationValueFilterFactory,
2213
                                                      AnnotationRetention annotationRetention,
2214
                                                      AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2215
                                                      Implementation.Context.Factory implementationContextFactory,
2216
                                                      TypeValidation typeValidation,
2217
                                                      AsmClassReader.Factory classReaderFactory,
2218
                                                      AsmClassWriter.Factory classWriterFactory,
2219
                                                      TypePool typePool,
2220
                                                      ClassFileLocator classFileLocator) {
2221
            return new ForInlining.WithDecorationOnly<U>(instrumentedType,
1✔
2222
                    classFileVersion,
2223
                    auxiliaryTypes,
2224
                    new MethodList.Explicit<MethodDescription>(methods),
2225
                    typeAttributeAppender,
2226
                    asmVisitorWrapper,
2227
                    annotationValueFilterFactory,
2228
                    annotationRetention,
2229
                    auxiliaryTypeNamingStrategy,
2230
                    implementationContextFactory,
2231
                    typeValidation,
2232
                    classReaderFactory,
2233
                    classWriterFactory,
2234
                    typePool,
2235
                    classFileLocator);
2236
        }
2237

2238
        /**
2239
         * {@inheritDoc}
2240
         */
2241
        @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Setting a debugging property should never change the program outcome.")
2242
        public DynamicType.Unloaded<S> make(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2243
            ClassDumpAction.Dispatcher dispatcher = DUMP_FOLDER == null
1✔
2244
                    ? ClassDumpAction.Dispatcher.Disabled.INSTANCE
2245
                    : new ClassDumpAction.Dispatcher.Enabled(DUMP_FOLDER, System.currentTimeMillis());
1✔
2246
            UnresolvedType unresolvedType = create(typeResolutionStrategy.injectedInto(typeInitializer), dispatcher);
1✔
2247
            dispatcher.dump(instrumentedType, false, unresolvedType.getBinaryRepresentation());
1✔
2248
            return unresolvedType.toDynamicType(typeResolutionStrategy);
1✔
2249
        }
2250

2251
        /**
2252
         * Creates an unresolved version of the dynamic type.
2253
         *
2254
         * @param typeInitializer The type initializer to use.
2255
         * @param dispatcher      A dispatcher for dumping class files.
2256
         * @return An unresolved type.
2257
         */
2258
        protected abstract UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher);
2259

2260
        /**
2261
         * An unresolved type.
2262
         */
2263
        @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
2264
        protected class UnresolvedType {
2265

2266
            /**
2267
             * The type's binary representation.
2268
             */
2269
            private final byte[] binaryRepresentation;
2270

2271
            /**
2272
             * A list of auxiliary types for this unresolved type.
2273
             */
2274
            private final List<? extends DynamicType> auxiliaryTypes;
2275

2276
            /**
2277
             * Creates a new unresolved type.
2278
             *
2279
             * @param binaryRepresentation The type's binary representation.
2280
             * @param auxiliaryTypes       A list of auxiliary types for this unresolved type.
2281
             */
2282
            protected UnresolvedType(byte[] binaryRepresentation, List<? extends DynamicType> auxiliaryTypes) {
1✔
2283
                this.binaryRepresentation = binaryRepresentation;
1✔
2284
                this.auxiliaryTypes = auxiliaryTypes;
1✔
2285
            }
1✔
2286

2287
            /**
2288
             * Resolves this type to a dynamic type.
2289
             *
2290
             * @param typeResolutionStrategy The type resolution strategy to apply.
2291
             * @return A dynamic type representing the inlined type.
2292
             */
2293
            protected DynamicType.Unloaded<S> toDynamicType(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2294
                return new DynamicType.Default.Unloaded<S>(instrumentedType,
1✔
2295
                        binaryRepresentation,
2296
                        loadedTypeInitializer,
2297
                        CompoundList.of(Default.this.auxiliaryTypes, auxiliaryTypes),
1✔
2298
                        typeResolutionStrategy);
2299
            }
2300

2301
            /**
2302
             * Returns the binary representation of this unresolved type.
2303
             *
2304
             * @return The binary representation of this unresolved type.
2305
             */
2306
            protected byte[] getBinaryRepresentation() {
2307
                return binaryRepresentation;
1✔
2308
            }
2309
        }
2310

2311
        /**
2312
         * A key to represent a unique signature.
2313
         */
2314
        protected static class SignatureKey {
2315

2316
            /**
2317
             * The represented internal name.
2318
             */
2319
            private final String internalName;
2320

2321
            /**
2322
             * The represented descriptor.
2323
             */
2324
            private final String descriptor;
2325

2326
            /**
2327
             * Creates a new signature key.
2328
             *
2329
             * @param internalName The represented internal name.
2330
             * @param descriptor   The represented descriptor.
2331
             */
2332
            public SignatureKey(String internalName, String descriptor) {
1✔
2333
                this.internalName = internalName;
1✔
2334
                this.descriptor = descriptor;
1✔
2335
            }
1✔
2336

2337
            @Override
2338
            public boolean equals(@MaybeNull Object other) {
2339
                if (this == other) return true;
1✔
2340
                if (other == null || getClass() != other.getClass()) return false;
1✔
2341
                SignatureKey that = (SignatureKey) other;
1✔
2342
                return internalName.equals(that.internalName) && descriptor.equals(that.descriptor);
1✔
2343
            }
2344

2345
            @Override
2346
            public int hashCode() {
2347
                return 17 + internalName.hashCode() + 31 * descriptor.hashCode();
1✔
2348
            }
2349
        }
2350

2351
        /**
2352
         * A class validator that validates that a class only defines members that are appropriate for the sort of the generated class.
2353
         */
2354
        protected static class ValidatingClassVisitor extends ClassVisitor {
2355

2356
            /**
2357
             * Indicates that a method has no method parameters.
2358
             */
2359
            private static final String NO_PARAMETERS = "()";
2360

2361
            /**
2362
             * Indicates that a method returns void.
2363
             */
2364
            private static final String RETURNS_VOID = "V";
2365

2366
            /**
2367
             * The descriptor of the {@link String} type.
2368
             */
2369
            private static final String STRING_DESCRIPTOR = "Ljava/lang/String;";
2370

2371
            /**
2372
             * Indicates that a field is ignored.
2373
             */
2374
            @AlwaysNull
2375
            private static final FieldVisitor IGNORE_FIELD = null;
1✔
2376

2377
            /**
2378
             * Indicates that a method is ignored.
2379
             */
2380
            @AlwaysNull
2381
            private static final MethodVisitor IGNORE_METHOD = null;
1✔
2382

2383
            /**
2384
             * The constraint to assert the members against. The constraint is first defined when the general class information is visited.
2385
             */
2386
            @UnknownNull
2387
            private Constraint constraint;
2388

2389
            /**
2390
             * Creates a validating class visitor.
2391
             *
2392
             * @param classVisitor The class visitor to which any calls are delegated to.
2393
             */
2394
            protected ValidatingClassVisitor(ClassVisitor classVisitor) {
2395
                super(OpenedClassReader.ASM_API, classVisitor);
1✔
2396
            }
1✔
2397

2398
            /**
2399
             * Adds a validating visitor if type validation is enabled.
2400
             *
2401
             * @param classVisitor   The original class visitor.
2402
             * @param typeValidation The type validation state.
2403
             * @return A class visitor that applies type validation if this is required.
2404
             */
2405
            protected static ClassVisitor of(ClassVisitor classVisitor, TypeValidation typeValidation) {
2406
                return typeValidation.isEnabled()
1✔
2407
                        ? new ValidatingClassVisitor(classVisitor)
2408
                        : classVisitor;
2409
            }
2410

2411
            @Override
2412
            public void visit(int version, int modifiers, String name, @MaybeNull String signature, @MaybeNull String superName, @MaybeNull String[] interfaceInternalName) {
2413
                ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(version);
1✔
2414
                List<Constraint> constraints = new ArrayList<Constraint>();
1✔
2415
                constraints.add(new Constraint.ForClassFileVersion(classFileVersion));
1✔
2416
                if (name.endsWith('/' + PackageDescription.PACKAGE_CLASS_NAME)) {
1✔
2417
                    constraints.add(Constraint.ForPackageType.INSTANCE);
1✔
2418
                } else if ((modifiers & Opcodes.ACC_ANNOTATION) != 0) {
1✔
2419
                    if (!classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
1✔
2420
                        throw new IllegalStateException("Cannot define an annotation type for class file version " + classFileVersion);
1✔
2421
                    }
2422
                    constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
1✔
2423
                            ? Constraint.ForAnnotation.JAVA_8
2424
                            : Constraint.ForAnnotation.CLASSIC);
2425
                } else if ((modifiers & Opcodes.ACC_INTERFACE) != 0) {
1✔
2426
                    constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
1✔
2427
                            ? Constraint.ForInterface.JAVA_8
2428
                            : Constraint.ForInterface.CLASSIC);
2429
                } else if ((modifiers & Opcodes.ACC_ABSTRACT) != 0) {
1✔
2430
                    constraints.add(Constraint.ForClass.ABSTRACT);
1✔
2431
                } else {
2432
                    constraints.add(Constraint.ForClass.MANIFEST);
1✔
2433
                }
2434
                boolean record;
2435
                if ((modifiers & Opcodes.ACC_RECORD) != 0) {
1✔
2436
                    constraints.add(Constraint.ForRecord.INSTANCE);
1✔
2437
                    record = true;
1✔
2438
                } else {
2439
                    record = false;
1✔
2440
                }
2441
                constraint = new Constraint.Compound(constraints);
1✔
2442
                constraint.assertType(modifiers, interfaceInternalName != null, signature != null);
1✔
2443
                if (record) {
1✔
2444
                    constraint.assertRecord();
×
2445
                }
2446
                super.visit(version, modifiers, name, signature, superName, interfaceInternalName);
1✔
2447
            }
1✔
2448

2449
            @Override
2450
            public void visitPermittedSubclass(String permittedSubclass) {
2451
                constraint.assertPermittedSubclass();
×
2452
                super.visitPermittedSubclass(permittedSubclass);
×
2453
            }
×
2454

2455
            @Override
2456
            @MaybeNull
2457
            public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
2458
                constraint.assertAnnotation();
1✔
2459
                return super.visitAnnotation(descriptor, visible);
1✔
2460
            }
2461

2462
            @Override
2463
            @MaybeNull
2464
            public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
2465
                constraint.assertTypeAnnotation();
1✔
2466
                return super.visitTypeAnnotation(typeReference, typePath, descriptor, visible);
1✔
2467
            }
2468

2469
            @Override
2470
            public void visitNestHost(String nestHost) {
2471
                constraint.assertNestMate();
×
2472
                super.visitNestHost(nestHost);
×
2473
            }
×
2474

2475
            @Override
2476
            public void visitNestMember(String nestMember) {
2477
                constraint.assertNestMate();
×
2478
                super.visitNestMember(nestMember);
×
2479
            }
×
2480

2481
            @Override
2482
            @MaybeNull
2483
            public FieldVisitor visitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
2484
                if (value != null) {
1✔
2485
                    Class<?> type;
2486
                    switch (descriptor.charAt(0)) {
1✔
2487
                        case 'Z':
2488
                        case 'B':
2489
                        case 'C':
2490
                        case 'S':
2491
                        case 'I':
2492
                            type = Integer.class;
1✔
2493
                            break;
1✔
2494
                        case 'J':
2495
                            type = Long.class;
1✔
2496
                            break;
1✔
2497
                        case 'F':
2498
                            type = Float.class;
1✔
2499
                            break;
1✔
2500
                        case 'D':
2501
                            type = Double.class;
1✔
2502
                            break;
1✔
2503
                        default:
2504
                            if (!descriptor.equals(STRING_DESCRIPTOR)) {
1✔
2505
                                throw new IllegalStateException("Cannot define a default value for type of field " + name);
1✔
2506
                            }
2507
                            type = String.class;
1✔
2508
                    }
2509
                    if (!type.isInstance(value)) {
1✔
2510
                        throw new IllegalStateException("Field " + name + " defines an incompatible default value " + value + " (" + value.getClass().getName() + ")");
1✔
2511
                    } else if (type == Integer.class) {
1✔
2512
                        boolean outOfRange;
2513
                        switch (descriptor.charAt(0)) {
1✔
2514
                            case 'Z':
2515
                                outOfRange = (Integer) value < 0 || (Integer) value > 1;
1✔
2516
                                break;
1✔
2517
                            case 'B':
2518
                                outOfRange = (Integer) value < Byte.MIN_VALUE || (Integer) value > Byte.MAX_VALUE;
1✔
2519
                                break;
1✔
2520
                            case 'S':
2521
                                outOfRange = (Integer) value < Short.MIN_VALUE || (Integer) value > Short.MAX_VALUE;
1✔
2522
                                break;
1✔
2523
                            case 'C':
2524
                                outOfRange = (Integer) value < Character.MIN_VALUE || (Integer) value > Character.MAX_VALUE;
1✔
2525
                                break;
1✔
2526
                            default:
2527
                                outOfRange = false;
1✔
2528
                        }
2529
                        if (outOfRange) {
1✔
2530
                            throw new IllegalStateException("Field " + name + " defines an incompatible default value " + value);
1✔
2531
                        }
2532
                    }
2533
                }
2534
                constraint.assertField(name,
1✔
2535
                        (modifiers & Opcodes.ACC_PUBLIC) != 0,
2536
                        (modifiers & Opcodes.ACC_STATIC) != 0,
2537
                        (modifiers & Opcodes.ACC_FINAL) != 0,
2538
                        signature != null);
2539
                FieldVisitor fieldVisitor = super.visitField(modifiers, name, descriptor, signature, value);
1✔
2540
                return fieldVisitor == null
1✔
2541
                        ? IGNORE_FIELD
2542
                        : new ValidatingFieldVisitor(fieldVisitor);
2543
            }
2544

2545
            @Override
2546
            @MaybeNull
2547
            public MethodVisitor visitMethod(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull String[] exceptionInternalName) {
2548
                constraint.assertMethod(name,
1✔
2549
                        (modifiers & Opcodes.ACC_ABSTRACT) != 0,
2550
                        (modifiers & Opcodes.ACC_PUBLIC) != 0,
2551
                        (modifiers & Opcodes.ACC_PRIVATE) != 0,
2552
                        (modifiers & Opcodes.ACC_STATIC) != 0,
2553
                        !name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME)
1✔
2554
                                && !name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)
1✔
2555
                                && (modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)) == 0,
2556
                        name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME),
1✔
2557
                        !descriptor.startsWith(NO_PARAMETERS) || descriptor.endsWith(RETURNS_VOID),
1✔
2558
                        signature != null);
2559
                MethodVisitor methodVisitor = super.visitMethod(modifiers, name, descriptor, signature, exceptionInternalName);
1✔
2560
                return methodVisitor == null
1✔
2561
                        ? IGNORE_METHOD
2562
                        : new ValidatingMethodVisitor(methodVisitor, name);
2563
            }
2564

2565
            /**
2566
             * A constraint for members that are legal for a given type.
2567
             */
2568
            protected interface Constraint {
2569

2570
                /**
2571
                 * Asserts if the type can legally represent a package description.
2572
                 *
2573
                 * @param modifier          The modifier that is to be written to the type.
2574
                 * @param definesInterfaces {@code true} if this type implements at least one interface.
2575
                 * @param isGeneric         {@code true} if this type defines a generic type signature.
2576
                 */
2577
                void assertType(int modifier, boolean definesInterfaces, boolean isGeneric);
2578

2579
                /**
2580
                 * Asserts a field for being valid.
2581
                 *
2582
                 * @param name      The name of the field.
2583
                 * @param isPublic  {@code true} if this field is public.
2584
                 * @param isStatic  {@code true} if this field is static.
2585
                 * @param isFinal   {@code true} if this field is final.
2586
                 * @param isGeneric {@code true} if this field defines a generic signature.
2587
                 */
2588
                void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric);
2589

2590
                /**
2591
                 * Asserts a method for being valid.
2592
                 *
2593
                 * @param name                       The name of the method.
2594
                 * @param isAbstract                 {@code true} if the method is abstract.
2595
                 * @param isPublic                   {@code true} if this method is public.
2596
                 * @param isPrivate                  {@code true} if this method is private.
2597
                 * @param isStatic                   {@code true} if this method is static.
2598
                 * @param isVirtual                  {@code true} if this method is virtual.
2599
                 * @param isConstructor              {@code true} if this method is a constructor.
2600
                 * @param isDefaultValueIncompatible {@code true} if a method's signature cannot describe an annotation property method.
2601
                 * @param isGeneric                  {@code true} if this method defines a generic signature.
2602
                 */
2603
                void assertMethod(String name,
2604
                                  boolean isAbstract,
2605
                                  boolean isPublic,
2606
                                  boolean isPrivate,
2607
                                  boolean isStatic,
2608
                                  boolean isVirtual,
2609
                                  boolean isConstructor,
2610
                                  boolean isDefaultValueIncompatible,
2611
                                  boolean isGeneric);
2612

2613
                /**
2614
                 * Asserts the legitimacy of an annotation for the instrumented type.
2615
                 */
2616
                void assertAnnotation();
2617

2618
                /**
2619
                 * Asserts the legitimacy of a type annotation for the instrumented type.
2620
                 */
2621
                void assertTypeAnnotation();
2622

2623
                /**
2624
                 * Asserts if a default value is legal for a method.
2625
                 *
2626
                 * @param name The name of the method.
2627
                 */
2628
                void assertDefaultValue(String name);
2629

2630
                /**
2631
                 * Asserts if it is legal to invoke a default method from a type.
2632
                 */
2633
                void assertDefaultMethodCall();
2634

2635
                /**
2636
                 * Asserts the capability to store a type constant in the class's constant pool.
2637
                 */
2638
                void assertTypeInConstantPool();
2639

2640
                /**
2641
                 * Asserts the capability to store a method type constant in the class's constant pool.
2642
                 */
2643
                void assertMethodTypeInConstantPool();
2644

2645
                /**
2646
                 * Asserts the capability to store a method handle in the class's constant pool.
2647
                 */
2648
                void assertHandleInConstantPool();
2649

2650
                /**
2651
                 * Asserts the capability to invoke a method dynamically.
2652
                 */
2653
                void assertInvokeDynamic();
2654

2655
                /**
2656
                 * Asserts the capability of executing a subroutine.
2657
                 */
2658
                void assertSubRoutine();
2659

2660
                /**
2661
                 * Asserts the capability of storing a dynamic value in the constant pool.
2662
                 */
2663
                void assertDynamicValueInConstantPool();
2664

2665
                /**
2666
                 * Asserts the capability of storing nest mate information.
2667
                 */
2668
                void assertNestMate();
2669

2670
                /**
2671
                 * Asserts the presence of a record component.
2672
                 */
2673
                void assertRecord();
2674

2675
                /**
2676
                 * Asserts the presence of a permitted subclass.
2677
                 */
2678
                void assertPermittedSubclass();
2679

2680
                /**
2681
                 * Represents the constraint of a class type.
2682
                 */
2683
                enum ForClass implements Constraint {
1✔
2684

2685
                    /**
2686
                     * Represents the constraints of a non-abstract class.
2687
                     */
2688
                    MANIFEST(true),
1✔
2689

2690
                    /**
2691
                     * Represents the constraints of an abstract class.
2692
                     */
2693
                    ABSTRACT(false);
1✔
2694

2695
                    /**
2696
                     * {@code true} if this instance represents the constraints a non-abstract class.
2697
                     */
2698
                    private final boolean manifestType;
2699

2700
                    /**
2701
                     * Creates a new constraint for a class.
2702
                     *
2703
                     * @param manifestType {@code true} if this instance represents a non-abstract class.
2704
                     */
2705
                    ForClass(boolean manifestType) {
1✔
2706
                        this.manifestType = manifestType;
1✔
2707
                    }
1✔
2708

2709
                    /**
2710
                     * {@inheritDoc}
2711
                     */
2712
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2713
                        /* do nothing */
2714
                    }
1✔
2715

2716
                    /**
2717
                     * {@inheritDoc}
2718
                     */
2719
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2720
                        /* do nothing */
2721
                    }
1✔
2722

2723
                    /**
2724
                     * {@inheritDoc}
2725
                     */
2726
                    public void assertMethod(String name,
2727
                                             boolean isAbstract,
2728
                                             boolean isPublic,
2729
                                             boolean isPrivate,
2730
                                             boolean isStatic,
2731
                                             boolean isVirtual,
2732
                                             boolean isConstructor,
2733
                                             boolean isDefaultValueIncompatible,
2734
                                             boolean isGeneric) {
2735
                        if (isAbstract && manifestType) {
1✔
2736
                            throw new IllegalStateException("Cannot define abstract method '" + name + "' for non-abstract class");
1✔
2737
                        }
2738
                    }
1✔
2739

2740
                    /**
2741
                     * {@inheritDoc}
2742
                     */
2743
                    public void assertAnnotation() {
2744
                        /* do nothing */
2745
                    }
1✔
2746

2747
                    /**
2748
                     * {@inheritDoc}
2749
                     */
2750
                    public void assertTypeAnnotation() {
2751
                        /* do nothing */
2752
                    }
1✔
2753

2754
                    /**
2755
                     * {@inheritDoc}
2756
                     */
2757
                    public void assertDefaultValue(String name) {
2758
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
1✔
2759
                    }
2760

2761
                    /**
2762
                     * {@inheritDoc}
2763
                     */
2764
                    public void assertDefaultMethodCall() {
2765
                        /* do nothing */
2766
                    }
1✔
2767

2768
                    /**
2769
                     * {@inheritDoc}
2770
                     */
2771
                    public void assertTypeInConstantPool() {
2772
                        /* do nothing */
2773
                    }
1✔
2774

2775
                    /**
2776
                     * {@inheritDoc}
2777
                     */
2778
                    public void assertMethodTypeInConstantPool() {
2779
                        /* do nothing */
2780
                    }
1✔
2781

2782
                    /**
2783
                     * {@inheritDoc}
2784
                     */
2785
                    public void assertHandleInConstantPool() {
2786
                        /* do nothing */
2787
                    }
1✔
2788

2789
                    /**
2790
                     * {@inheritDoc}
2791
                     */
2792
                    public void assertInvokeDynamic() {
2793
                        /* do nothing */
2794
                    }
1✔
2795

2796
                    /**
2797
                     * {@inheritDoc}
2798
                     */
2799
                    public void assertSubRoutine() {
2800
                        /* do nothing */
2801
                    }
1✔
2802

2803
                    /**
2804
                     * {@inheritDoc}
2805
                     */
2806
                    public void assertDynamicValueInConstantPool() {
2807
                        /* do nothing */
2808
                    }
×
2809

2810
                    /**
2811
                     * {@inheritDoc}
2812
                     */
2813
                    public void assertNestMate() {
2814
                        /* do nothing */
2815
                    }
×
2816

2817
                    /**
2818
                     * {@inheritDoc}
2819
                     */
2820
                    public void assertRecord() {
2821
                        /* do nothing */
2822
                    }
×
2823

2824
                    /**
2825
                     * {@inheritDoc}
2826
                     */
2827
                    public void assertPermittedSubclass() {
2828
                        /* do nothing */
2829
                    }
×
2830
                }
2831

2832
                /**
2833
                 * Represents the constraint of a package type.
2834
                 */
2835
                enum ForPackageType implements Constraint {
1✔
2836

2837
                    /**
2838
                     * The singleton instance.
2839
                     */
2840
                    INSTANCE;
1✔
2841

2842
                    /**
2843
                     * {@inheritDoc}
2844
                     */
2845
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2846
                        throw new IllegalStateException("Cannot define a field for a package description type");
1✔
2847
                    }
2848

2849
                    /**
2850
                     * {@inheritDoc}
2851
                     */
2852
                    public void assertMethod(String name,
2853
                                             boolean isAbstract,
2854
                                             boolean isPublic,
2855
                                             boolean isPrivate,
2856
                                             boolean isStatic,
2857
                                             boolean isVirtual,
2858
                                             boolean isConstructor,
2859
                                             boolean isNoDefaultValue,
2860
                                             boolean isGeneric) {
2861
                        throw new IllegalStateException("Cannot define a method for a package description type");
×
2862
                    }
2863

2864
                    /**
2865
                     * {@inheritDoc}
2866
                     */
2867
                    public void assertAnnotation() {
2868
                        /* do nothing */
2869
                    }
1✔
2870

2871
                    /**
2872
                     * {@inheritDoc}
2873
                     */
2874
                    public void assertTypeAnnotation() {
2875
                        /* do nothing */
2876
                    }
×
2877

2878
                    /**
2879
                     * {@inheritDoc}
2880
                     */
2881
                    public void assertDefaultValue(String name) {
2882
                        /* do nothing, implicit by forbidding methods */
2883
                    }
×
2884

2885
                    /**
2886
                     * {@inheritDoc}
2887
                     */
2888
                    public void assertDefaultMethodCall() {
2889
                        /* do nothing */
2890
                    }
×
2891

2892
                    /**
2893
                     * {@inheritDoc}
2894
                     */
2895
                    public void assertTypeInConstantPool() {
2896
                        /* do nothing */
2897
                    }
×
2898

2899
                    /**
2900
                     * {@inheritDoc}
2901
                     */
2902
                    public void assertMethodTypeInConstantPool() {
2903
                        /* do nothing */
2904
                    }
×
2905

2906
                    /**
2907
                     * {@inheritDoc}
2908
                     */
2909
                    public void assertHandleInConstantPool() {
2910
                        /* do nothing */
2911
                    }
×
2912

2913
                    /**
2914
                     * {@inheritDoc}
2915
                     */
2916
                    public void assertInvokeDynamic() {
2917
                        /* do nothing */
2918
                    }
×
2919

2920
                    /**
2921
                     * {@inheritDoc}
2922
                     */
2923
                    public void assertSubRoutine() {
2924
                        /* do nothing */
2925
                    }
×
2926

2927
                    /**
2928
                     * {@inheritDoc}
2929
                     */
2930
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2931
                        if (modifier != PackageDescription.PACKAGE_MODIFIERS) {
1✔
2932
                            throw new IllegalStateException("A package description type must define " + PackageDescription.PACKAGE_MODIFIERS + " as modifier");
×
2933
                        } else if (definesInterfaces) {
1✔
2934
                            throw new IllegalStateException("Cannot implement interface for package type");
1✔
2935
                        }
2936
                    }
1✔
2937

2938
                    /**
2939
                     * {@inheritDoc}
2940
                     */
2941
                    public void assertDynamicValueInConstantPool() {
2942
                        /* do nothing */
2943
                    }
×
2944

2945
                    /**
2946
                     * {@inheritDoc}
2947
                     */
2948
                    public void assertNestMate() {
2949
                        /* do nothing */
2950
                    }
×
2951

2952
                    /**
2953
                     * {@inheritDoc}
2954
                     */
2955
                    public void assertRecord() {
2956
                        /* do nothing */
2957
                    }
×
2958

2959
                    /**
2960
                     * {@inheritDoc}
2961
                     */
2962
                    public void assertPermittedSubclass() {
2963
                        /* do nothing */
2964
                    }
×
2965
                }
2966

2967
                /**
2968
                 * Represents the constraint of an interface type.
2969
                 */
2970
                enum ForInterface implements Constraint {
1✔
2971

2972
                    /**
2973
                     * An interface type with the constraints for the Java versions 5 to 7.
2974
                     */
2975
                    CLASSIC(true),
1✔
2976

2977
                    /**
2978
                     * An interface type with the constraints for the Java versions 8+.
2979
                     */
2980
                    JAVA_8(false);
1✔
2981

2982
                    /**
2983
                     * {@code true} if this instance represents a classic interface type (pre Java 8).
2984
                     */
2985
                    private final boolean classic;
2986

2987
                    /**
2988
                     * Creates a constraint for an interface type.
2989
                     *
2990
                     * @param classic {@code true} if this instance represents a classic interface (pre Java 8).
2991
                     */
2992
                    ForInterface(boolean classic) {
1✔
2993
                        this.classic = classic;
1✔
2994
                    }
1✔
2995

2996
                    /**
2997
                     * {@inheritDoc}
2998
                     */
2999
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3000
                        if (!isStatic || !isPublic || !isFinal) {
1✔
3001
                            throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
1✔
3002
                        }
3003
                    }
1✔
3004

3005
                    /**
3006
                     * {@inheritDoc}
3007
                     */
3008
                    public void assertMethod(String name,
3009
                                             boolean isAbstract,
3010
                                             boolean isPublic,
3011
                                             boolean isPrivate,
3012
                                             boolean isStatic,
3013
                                             boolean isVirtual,
3014
                                             boolean isConstructor,
3015
                                             boolean isDefaultValueIncompatible,
3016
                                             boolean isGeneric) {
3017
                        if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
3018
                            if (isConstructor) {
1✔
3019
                                throw new IllegalStateException("Cannot define constructor for interface type");
1✔
3020
                            } else if (classic && !isPublic) {
1✔
3021
                                throw new IllegalStateException("Cannot define non-public method '" + name + "' for interface type");
×
3022
                            } else if (classic && !isVirtual) {
1✔
3023
                                throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 interface type");
×
3024
                            } else if (classic && !isAbstract) {
1✔
3025
                                throw new IllegalStateException("Cannot define default method '" + name + "' for pre-Java 8 interface type");
×
3026
                            }
3027
                        }
3028
                    }
1✔
3029

3030
                    /**
3031
                     * {@inheritDoc}
3032
                     */
3033
                    public void assertAnnotation() {
3034
                        /* do nothing */
3035
                    }
1✔
3036

3037
                    /**
3038
                     * {@inheritDoc}
3039
                     */
3040
                    public void assertTypeAnnotation() {
3041
                        /* do nothing */
3042
                    }
×
3043

3044
                    /**
3045
                     * {@inheritDoc}
3046
                     */
3047
                    public void assertDefaultValue(String name) {
3048
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
×
3049
                    }
3050

3051
                    /**
3052
                     * {@inheritDoc}
3053
                     */
3054
                    public void assertDefaultMethodCall() {
3055
                        /* do nothing */
3056
                    }
1✔
3057

3058
                    /**
3059
                     * {@inheritDoc}
3060
                     */
3061
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3062
                        /* do nothing */
3063
                    }
1✔
3064

3065
                    /**
3066
                     * {@inheritDoc}
3067
                     */
3068
                    public void assertTypeInConstantPool() {
3069
                        /* do nothing */
3070
                    }
×
3071

3072
                    /**
3073
                     * {@inheritDoc}
3074
                     */
3075
                    public void assertMethodTypeInConstantPool() {
3076
                        /* do nothing */
3077
                    }
×
3078

3079
                    /**
3080
                     * {@inheritDoc}
3081
                     */
3082
                    public void assertHandleInConstantPool() {
3083
                        /* do nothing */
3084
                    }
×
3085

3086
                    /**
3087
                     * {@inheritDoc}
3088
                     */
3089
                    public void assertInvokeDynamic() {
3090
                        /* do nothing */
3091
                    }
×
3092

3093
                    /**
3094
                     * {@inheritDoc}
3095
                     */
3096
                    public void assertSubRoutine() {
3097
                        /* do nothing */
3098
                    }
×
3099

3100
                    /**
3101
                     * {@inheritDoc}
3102
                     */
3103
                    public void assertDynamicValueInConstantPool() {
3104
                        /* do nothing */
3105
                    }
×
3106

3107
                    /**
3108
                     * {@inheritDoc}
3109
                     */
3110
                    public void assertNestMate() {
3111
                        /* do nothing */
3112
                    }
×
3113

3114
                    /**
3115
                     * {@inheritDoc}
3116
                     */
3117
                    public void assertRecord() {
3118
                        /* do nothing */
3119
                    }
×
3120

3121
                    /**
3122
                     * {@inheritDoc}
3123
                     */
3124
                    public void assertPermittedSubclass() {
3125
                        /* do nothing */
3126
                    }
×
3127
                }
3128

3129
                /**
3130
                 * Represents the constraint of a record type.
3131
                 */
3132
                enum ForRecord implements Constraint {
1✔
3133

3134
                    /**
3135
                     * The singleton instance.
3136
                     */
3137
                    INSTANCE;
1✔
3138

3139
                    /**
3140
                     * {@inheritDoc}
3141
                     */
3142
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3143
                        /* do nothing */
3144
                    }
×
3145

3146
                    /**
3147
                     * {@inheritDoc}
3148
                     */
3149
                    public void assertMethod(String name,
3150
                                             boolean isAbstract,
3151
                                             boolean isPublic,
3152
                                             boolean isPrivate,
3153
                                             boolean isStatic,
3154
                                             boolean isVirtual,
3155
                                             boolean isConstructor,
3156
                                             boolean isDefaultValueIncompatible,
3157
                                             boolean isGeneric) {
3158
                        /* do nothing */
3159
                    }
×
3160

3161
                    /**
3162
                     * {@inheritDoc}
3163
                     */
3164
                    public void assertAnnotation() {
3165
                        /* do nothing */
3166
                    }
×
3167

3168
                    /**
3169
                     * {@inheritDoc}
3170
                     */
3171
                    public void assertTypeAnnotation() {
3172
                        /* do nothing */
3173
                    }
×
3174

3175
                    /**
3176
                     * {@inheritDoc}
3177
                     */
3178
                    public void assertDefaultValue(String name) {
3179
                        /* do nothing */
3180
                    }
×
3181

3182
                    /**
3183
                     * {@inheritDoc}
3184
                     */
3185
                    public void assertDefaultMethodCall() {
3186
                        /* do nothing */
3187
                    }
×
3188

3189
                    /**
3190
                     * {@inheritDoc}
3191
                     */
3192
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3193
                        if ((modifier & Opcodes.ACC_ABSTRACT) != 0) {
1✔
3194
                            throw new IllegalStateException("Cannot define a record class as abstract");
×
3195
                        }
3196
                    }
1✔
3197

3198
                    /**
3199
                     * {@inheritDoc}
3200
                     */
3201
                    public void assertTypeInConstantPool() {
3202
                        /* do nothing */
3203
                    }
×
3204

3205
                    /**
3206
                     * {@inheritDoc}
3207
                     */
3208
                    public void assertMethodTypeInConstantPool() {
3209
                        /* do nothing */
3210
                    }
×
3211

3212
                    /**
3213
                     * {@inheritDoc}
3214
                     */
3215
                    public void assertHandleInConstantPool() {
3216
                        /* do nothing */
3217
                    }
×
3218

3219
                    /**
3220
                     * {@inheritDoc}
3221
                     */
3222
                    public void assertInvokeDynamic() {
3223
                        /* do nothing */
3224
                    }
×
3225

3226
                    /**
3227
                     * {@inheritDoc}
3228
                     */
3229
                    public void assertSubRoutine() {
3230
                        /* do nothing */
3231
                    }
×
3232

3233
                    /**
3234
                     * {@inheritDoc}
3235
                     */
3236
                    public void assertDynamicValueInConstantPool() {
3237
                        /* do nothing */
3238
                    }
×
3239

3240
                    /**
3241
                     * {@inheritDoc}
3242
                     */
3243
                    public void assertNestMate() {
3244
                        /* do nothing */
3245
                    }
×
3246

3247
                    /**
3248
                     * {@inheritDoc}
3249
                     */
3250
                    public void assertRecord() {
3251
                        /* do nothing */
3252
                    }
×
3253

3254
                    /**
3255
                     * {@inheritDoc}
3256
                     */
3257
                    public void assertPermittedSubclass() {
3258
                        /* do nothing */
3259
                    }
×
3260
                }
3261

3262
                /**
3263
                 * Represents the constraint of an annotation type.
3264
                 */
3265
                enum ForAnnotation implements Constraint {
1✔
3266

3267
                    /**
3268
                     * An annotation type with the constraints for the Java versions 5 to 7.
3269
                     */
3270
                    CLASSIC(true),
1✔
3271

3272
                    /**
3273
                     * An annotation type with the constraints for the Java versions 8+.
3274
                     */
3275
                    JAVA_8(false);
1✔
3276

3277
                    /**
3278
                     * {@code true} if this instance represents a classic annotation type (pre Java 8).
3279
                     */
3280
                    private final boolean classic;
3281

3282
                    /**
3283
                     * Creates a constraint for an annotation type.
3284
                     *
3285
                     * @param classic {@code true} if this instance represents a classic annotation type (pre Java 8).
3286
                     */
3287
                    ForAnnotation(boolean classic) {
1✔
3288
                        this.classic = classic;
1✔
3289
                    }
1✔
3290

3291
                    /**
3292
                     * {@inheritDoc}
3293
                     */
3294
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3295
                        if (!isStatic || !isPublic || !isFinal) {
1✔
3296
                            throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
1✔
3297
                        }
3298
                    }
×
3299

3300
                    /**
3301
                     * {@inheritDoc}
3302
                     */
3303
                    public void assertMethod(String name,
3304
                                             boolean isAbstract,
3305
                                             boolean isPublic,
3306
                                             boolean isPrivate,
3307
                                             boolean isStatic,
3308
                                             boolean isVirtual,
3309
                                             boolean isConstructor,
3310
                                             boolean isDefaultValueIncompatible,
3311
                                             boolean isGeneric) {
3312
                        if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
3313
                            if (isConstructor) {
1✔
3314
                                throw new IllegalStateException("Cannot define constructor for interface type");
1✔
3315
                            } else if (classic && !isVirtual) {
1✔
3316
                                throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 annotation type");
1✔
3317
                            } else if (!isStatic && isDefaultValueIncompatible) {
1✔
3318
                                throw new IllegalStateException("Cannot define method '" + name + "' with the given signature as an annotation type method");
1✔
3319
                            }
3320
                        }
3321
                    }
1✔
3322

3323
                    /**
3324
                     * {@inheritDoc}
3325
                     */
3326
                    public void assertAnnotation() {
3327
                        /* do nothing */
3328
                    }
1✔
3329

3330
                    /**
3331
                     * {@inheritDoc}
3332
                     */
3333
                    public void assertTypeAnnotation() {
3334
                        /* do nothing */
3335
                    }
×
3336

3337
                    /**
3338
                     * {@inheritDoc}
3339
                     */
3340
                    public void assertDefaultValue(String name) {
3341
                        /* do nothing */
3342
                    }
1✔
3343

3344
                    /**
3345
                     * {@inheritDoc}
3346
                     */
3347
                    public void assertDefaultMethodCall() {
3348
                        /* do nothing */
3349
                    }
×
3350

3351
                    /**
3352
                     * {@inheritDoc}
3353
                     */
3354
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3355
                        if ((modifier & Opcodes.ACC_INTERFACE) == 0) {
1✔
3356
                            throw new IllegalStateException("Cannot define annotation type without interface modifier");
×
3357
                        }
3358
                    }
1✔
3359

3360
                    /**
3361
                     * {@inheritDoc}
3362
                     */
3363
                    public void assertTypeInConstantPool() {
3364
                        /* do nothing */
3365
                    }
×
3366

3367
                    /**
3368
                     * {@inheritDoc}
3369
                     */
3370
                    public void assertMethodTypeInConstantPool() {
3371
                        /* do nothing */
3372
                    }
×
3373

3374
                    /**
3375
                     * {@inheritDoc}
3376
                     */
3377
                    public void assertHandleInConstantPool() {
3378
                        /* do nothing */
3379
                    }
×
3380

3381
                    /**
3382
                     * {@inheritDoc}
3383
                     */
3384
                    public void assertInvokeDynamic() {
3385
                        /* do nothing */
3386
                    }
×
3387

3388
                    /**
3389
                     * {@inheritDoc}
3390
                     */
3391
                    public void assertSubRoutine() {
3392
                        /* do nothing */
3393
                    }
×
3394

3395
                    /**
3396
                     * {@inheritDoc}
3397
                     */
3398
                    public void assertDynamicValueInConstantPool() {
3399
                        /* do nothing */
3400
                    }
×
3401

3402
                    /**
3403
                     * {@inheritDoc}
3404
                     */
3405
                    public void assertNestMate() {
3406
                        /* do nothing */
3407
                    }
×
3408

3409
                    /**
3410
                     * {@inheritDoc}
3411
                     */
3412
                    public void assertRecord() {
3413
                        /* do nothing */
3414
                    }
×
3415

3416
                    /**
3417
                     * {@inheritDoc}
3418
                     */
3419
                    public void assertPermittedSubclass() {
3420
                        /* do nothing */
3421
                    }
×
3422
                }
3423

3424
                /**
3425
                 * Represents the constraint implied by a class file version.
3426
                 */
3427
                @HashCodeAndEqualsPlugin.Enhance
3428
                class ForClassFileVersion implements Constraint {
3429

3430
                    /**
3431
                     * The enforced class file version.
3432
                     */
3433
                    private final ClassFileVersion classFileVersion;
3434

3435
                    /**
3436
                     * Creates a new constraint for the given class file version.
3437
                     *
3438
                     * @param classFileVersion The enforced class file version.
3439
                     */
3440
                    protected ForClassFileVersion(ClassFileVersion classFileVersion) {
1✔
3441
                        this.classFileVersion = classFileVersion;
1✔
3442
                    }
1✔
3443

3444
                    /**
3445
                     * {@inheritDoc}
3446
                     */
3447
                    public void assertType(int modifiers, boolean definesInterfaces, boolean isGeneric) {
3448
                        if ((modifiers & Opcodes.ACC_ANNOTATION) != 0 && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
1✔
3449
                            throw new IllegalStateException("Cannot define annotation type for class file version " + classFileVersion);
×
3450
                        } else if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3451
                            throw new IllegalStateException("Cannot define a generic type for class file version " + classFileVersion);
×
3452
                        }
3453
                    }
1✔
3454

3455
                    /**
3456
                     * {@inheritDoc}
3457
                     */
3458
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3459
                        if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3460
                            throw new IllegalStateException("Cannot define generic field '" + name + "' for class file version " + classFileVersion);
×
3461
                        }
3462
                    }
1✔
3463

3464
                    /**
3465
                     * {@inheritDoc}
3466
                     */
3467
                    public void assertMethod(String name,
3468
                                             boolean isAbstract,
3469
                                             boolean isPublic,
3470
                                             boolean isPrivate,
3471
                                             boolean isStatic,
3472
                                             boolean isVirtual,
3473
                                             boolean isConstructor,
3474
                                             boolean isDefaultValueIncompatible,
3475
                                             boolean isGeneric) {
3476
                        if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3477
                            throw new IllegalStateException("Cannot define generic method '" + name + "' for class file version " + classFileVersion);
×
3478
                        } else if (!isVirtual && isAbstract) {
1✔
3479
                            throw new IllegalStateException("Cannot define static or non-virtual method '" + name + "' to be abstract");
1✔
3480
                        }
3481
                    }
1✔
3482

3483
                    /**
3484
                     * {@inheritDoc}
3485
                     */
3486
                    public void assertAnnotation() {
3487
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3488
                            throw new IllegalStateException("Cannot write annotations for class file version " + classFileVersion);
1✔
3489
                        }
3490
                    }
1✔
3491

3492
                    /**
3493
                     * {@inheritDoc}
3494
                     */
3495
                    public void assertTypeAnnotation() {
3496
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3497
                            throw new IllegalStateException("Cannot write type annotations for class file version " + classFileVersion);
×
3498
                        }
3499
                    }
1✔
3500

3501
                    /**
3502
                     * {@inheritDoc}
3503
                     */
3504
                    public void assertDefaultValue(String name) {
3505
                        /* do nothing, implicitly checked by type assertion */
3506
                    }
1✔
3507

3508
                    /**
3509
                     * {@inheritDoc}
3510
                     */
3511
                    public void assertDefaultMethodCall() {
3512
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V8)) {
1✔
3513
                            throw new IllegalStateException("Cannot invoke default method for class file version " + classFileVersion);
×
3514
                        }
3515
                    }
1✔
3516

3517
                    /**
3518
                     * {@inheritDoc}
3519
                     */
3520
                    public void assertTypeInConstantPool() {
3521
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3522
                            throw new IllegalStateException("Cannot write type to constant pool for class file version " + classFileVersion);
×
3523
                        }
3524
                    }
1✔
3525

3526
                    /**
3527
                     * {@inheritDoc}
3528
                     */
3529
                    public void assertMethodTypeInConstantPool() {
3530
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3531
                            throw new IllegalStateException("Cannot write method type to constant pool for class file version " + classFileVersion);
1✔
3532
                        }
3533
                    }
1✔
3534

3535
                    /**
3536
                     * {@inheritDoc}
3537
                     */
3538
                    public void assertHandleInConstantPool() {
3539
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3540
                            throw new IllegalStateException("Cannot write method handle to constant pool for class file version " + classFileVersion);
1✔
3541
                        }
3542
                    }
1✔
3543

3544
                    /**
3545
                     * {@inheritDoc}
3546
                     */
3547
                    public void assertInvokeDynamic() {
3548
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3549
                            throw new IllegalStateException("Cannot write invoke dynamic instruction for class file version " + classFileVersion);
×
3550
                        }
3551
                    }
1✔
3552

3553
                    /**
3554
                     * {@inheritDoc}
3555
                     */
3556
                    public void assertSubRoutine() {
3557
                        if (classFileVersion.isGreaterThan(ClassFileVersion.JAVA_V5)) {
1✔
3558
                            throw new IllegalStateException("Cannot write subroutine for class file version " + classFileVersion);
×
3559
                        }
3560
                    }
1✔
3561

3562
                    /**
3563
                     * {@inheritDoc}
3564
                     */
3565
                    public void assertDynamicValueInConstantPool() {
3566
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
1✔
3567
                            throw new IllegalStateException("Cannot write dynamic constant for class file version " + classFileVersion);
1✔
3568
                        }
3569
                    }
×
3570

3571
                    /**
3572
                     * {@inheritDoc}
3573
                     */
3574
                    public void assertNestMate() {
3575
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
×
3576
                            throw new IllegalStateException("Cannot define nest mate for class file version " + classFileVersion);
×
3577
                        }
3578
                    }
×
3579

3580
                    /**
3581
                     * {@inheritDoc}
3582
                     */
3583
                    public void assertRecord() {
3584
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V14)) {
1✔
3585
                            throw new IllegalStateException("Cannot define record for class file version " + classFileVersion);
1✔
3586
                        }
3587
                    }
×
3588

3589
                    /**
3590
                     * {@inheritDoc}
3591
                     */
3592
                    public void assertPermittedSubclass() {
3593
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V17)) {
×
3594
                            throw new IllegalStateException("Cannot define permitted subclasses for class file version " + classFileVersion);
×
3595
                        }
3596
                    }
×
3597
                }
3598

3599
                /**
3600
                 * A constraint implementation that summarizes several constraints.
3601
                 */
3602
                @HashCodeAndEqualsPlugin.Enhance
3603
                class Compound implements Constraint {
3604

3605
                    /**
3606
                     * A list of constraints that is enforced in the given order.
3607
                     */
3608
                    private final List<Constraint> constraints;
3609

3610
                    /**
3611
                     * Creates a new compound constraint.
3612
                     *
3613
                     * @param constraints A list of constraints that is enforced in the given order.
3614
                     */
3615
                    public Compound(List<? extends Constraint> constraints) {
1✔
3616
                        this.constraints = new ArrayList<Constraint>();
1✔
3617
                        for (Constraint constraint : constraints) {
1✔
3618
                            if (constraint instanceof Compound) {
1✔
3619
                                this.constraints.addAll(((Compound) constraint).constraints);
×
3620
                            } else {
3621
                                this.constraints.add(constraint);
1✔
3622
                            }
3623
                        }
1✔
3624
                    }
1✔
3625

3626
                    /**
3627
                     * {@inheritDoc}
3628
                     */
3629
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3630
                        for (Constraint constraint : constraints) {
1✔
3631
                            constraint.assertType(modifier, definesInterfaces, isGeneric);
1✔
3632
                        }
1✔
3633
                    }
1✔
3634

3635
                    /**
3636
                     * {@inheritDoc}
3637
                     */
3638
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3639
                        for (Constraint constraint : constraints) {
1✔
3640
                            constraint.assertField(name, isPublic, isStatic, isFinal, isGeneric);
1✔
3641
                        }
1✔
3642
                    }
1✔
3643

3644
                    /**
3645
                     * {@inheritDoc}
3646
                     */
3647
                    public void assertMethod(String name,
3648
                                             boolean isAbstract,
3649
                                             boolean isPublic,
3650
                                             boolean isPrivate,
3651
                                             boolean isStatic,
3652
                                             boolean isVirtual,
3653
                                             boolean isConstructor,
3654
                                             boolean isDefaultValueIncompatible,
3655
                                             boolean isGeneric) {
3656
                        for (Constraint constraint : constraints) {
1✔
3657
                            constraint.assertMethod(name,
1✔
3658
                                    isAbstract,
3659
                                    isPublic,
3660
                                    isPrivate,
3661
                                    isStatic,
3662
                                    isVirtual,
3663
                                    isConstructor,
3664
                                    isDefaultValueIncompatible,
3665
                                    isGeneric);
3666
                        }
1✔
3667
                    }
1✔
3668

3669
                    /**
3670
                     * {@inheritDoc}
3671
                     */
3672
                    public void assertDefaultValue(String name) {
3673
                        for (Constraint constraint : constraints) {
1✔
3674
                            constraint.assertDefaultValue(name);
1✔
3675
                        }
1✔
3676
                    }
1✔
3677

3678
                    /**
3679
                     * {@inheritDoc}
3680
                     */
3681
                    public void assertDefaultMethodCall() {
3682
                        for (Constraint constraint : constraints) {
1✔
3683
                            constraint.assertDefaultMethodCall();
1✔
3684
                        }
1✔
3685
                    }
1✔
3686

3687
                    /**
3688
                     * {@inheritDoc}
3689
                     */
3690
                    public void assertAnnotation() {
3691
                        for (Constraint constraint : constraints) {
1✔
3692
                            constraint.assertAnnotation();
1✔
3693
                        }
1✔
3694
                    }
1✔
3695

3696
                    /**
3697
                     * {@inheritDoc}
3698
                     */
3699
                    public void assertTypeAnnotation() {
3700
                        for (Constraint constraint : constraints) {
1✔
3701
                            constraint.assertTypeAnnotation();
1✔
3702
                        }
1✔
3703
                    }
1✔
3704

3705
                    /**
3706
                     * {@inheritDoc}
3707
                     */
3708
                    public void assertTypeInConstantPool() {
3709
                        for (Constraint constraint : constraints) {
1✔
3710
                            constraint.assertTypeInConstantPool();
1✔
3711
                        }
1✔
3712
                    }
1✔
3713

3714
                    /**
3715
                     * {@inheritDoc}
3716
                     */
3717
                    public void assertMethodTypeInConstantPool() {
3718
                        for (Constraint constraint : constraints) {
1✔
3719
                            constraint.assertMethodTypeInConstantPool();
1✔
3720
                        }
1✔
3721
                    }
1✔
3722

3723
                    /**
3724
                     * {@inheritDoc}
3725
                     */
3726
                    public void assertHandleInConstantPool() {
3727
                        for (Constraint constraint : constraints) {
1✔
3728
                            constraint.assertHandleInConstantPool();
1✔
3729
                        }
1✔
3730
                    }
1✔
3731

3732
                    /**
3733
                     * {@inheritDoc}
3734
                     */
3735
                    public void assertInvokeDynamic() {
3736
                        for (Constraint constraint : constraints) {
1✔
3737
                            constraint.assertInvokeDynamic();
1✔
3738
                        }
1✔
3739
                    }
1✔
3740

3741
                    /**
3742
                     * {@inheritDoc}
3743
                     */
3744
                    public void assertSubRoutine() {
3745
                        for (Constraint constraint : constraints) {
1✔
3746
                            constraint.assertSubRoutine();
1✔
3747
                        }
1✔
3748
                    }
1✔
3749

3750
                    /**
3751
                     * {@inheritDoc}
3752
                     */
3753
                    public void assertDynamicValueInConstantPool() {
3754
                        for (Constraint constraint : constraints) {
1✔
3755
                            constraint.assertDynamicValueInConstantPool();
×
3756
                        }
×
3757
                    }
×
3758

3759
                    /**
3760
                     * {@inheritDoc}
3761
                     */
3762
                    public void assertNestMate() {
3763
                        for (Constraint constraint : constraints) {
×
3764
                            constraint.assertNestMate();
×
3765
                        }
×
3766
                    }
×
3767

3768
                    /**
3769
                     * {@inheritDoc}
3770
                     */
3771
                    public void assertRecord() {
3772
                        for (Constraint constraint : constraints) {
1✔
3773
                            constraint.assertRecord();
×
3774
                        }
×
3775
                    }
×
3776

3777
                    /**
3778
                     * {@inheritDoc}
3779
                     */
3780
                    public void assertPermittedSubclass() {
3781
                        for (Constraint constraint : constraints) {
×
3782
                            constraint.assertPermittedSubclass();
×
3783
                        }
×
3784
                    }
×
3785
                }
3786
            }
3787

3788
            /**
3789
             * A field validator for checking default values.
3790
             */
3791
            protected class ValidatingFieldVisitor extends FieldVisitor {
3792

3793
                /**
3794
                 * Creates a validating field visitor.
3795
                 *
3796
                 * @param fieldVisitor The field visitor to which any calls are delegated to.
3797
                 */
3798
                protected ValidatingFieldVisitor(FieldVisitor fieldVisitor) {
1✔
3799
                    super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
3800
                }
1✔
3801

3802
                @Override
3803
                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
3804
                    constraint.assertAnnotation();
1✔
3805
                    return super.visitAnnotation(descriptor, visible);
1✔
3806
                }
3807
            }
3808

3809
            /**
3810
             * A method validator for checking default values.
3811
             */
3812
            protected class ValidatingMethodVisitor extends MethodVisitor {
3813

3814
                /**
3815
                 * The name of the method being visited.
3816
                 */
3817
                private final String name;
3818

3819
                /**
3820
                 * Creates a validating method visitor.
3821
                 *
3822
                 * @param methodVisitor The method visitor to which any calls are delegated to.
3823
                 * @param name          The name of the method being visited.
3824
                 */
3825
                protected ValidatingMethodVisitor(MethodVisitor methodVisitor, String name) {
1✔
3826
                    super(OpenedClassReader.ASM_API, methodVisitor);
1✔
3827
                    this.name = name;
1✔
3828
                }
1✔
3829

3830
                @Override
3831
                @MaybeNull
3832
                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
3833
                    constraint.assertAnnotation();
1✔
3834
                    return super.visitAnnotation(descriptor, visible);
1✔
3835
                }
3836

3837
                @Override
3838
                @MaybeNull
3839
                public AnnotationVisitor visitAnnotationDefault() {
3840
                    constraint.assertDefaultValue(name);
1✔
3841
                    return super.visitAnnotationDefault();
1✔
3842
                }
3843

3844
                @Override
3845
                @SuppressFBWarnings(value = "SF_SWITCH_NO_DEFAULT", justification = "Fall through to default case is intentional.")
3846
                public void visitLdcInsn(Object value) {
3847
                    if (value instanceof Type) {
1✔
3848
                        Type type = (Type) value;
1✔
3849
                        switch (type.getSort()) {
1✔
3850
                            case Type.OBJECT:
3851
                            case Type.ARRAY:
3852
                                constraint.assertTypeInConstantPool();
1✔
3853
                                break;
1✔
3854
                            case Type.METHOD:
3855
                                constraint.assertMethodTypeInConstantPool();
1✔
3856
                                break;
3857
                        }
3858
                    } else if (value instanceof Handle) {
1✔
3859
                        constraint.assertHandleInConstantPool();
1✔
3860
                    } else if (value instanceof ConstantDynamic) {
1✔
3861
                        constraint.assertDynamicValueInConstantPool();
×
3862
                    }
3863
                    super.visitLdcInsn(value);
1✔
3864
                }
1✔
3865

3866
                @Override
3867
                public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
3868
                    if (isInterface && opcode == Opcodes.INVOKESPECIAL) {
1✔
3869
                        constraint.assertDefaultMethodCall();
1✔
3870
                    }
3871
                    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
1✔
3872
                }
1✔
3873

3874
                @Override
3875
                public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethod, Object... bootstrapArgument) {
3876
                    constraint.assertInvokeDynamic();
1✔
3877
                    for (Object constant : bootstrapArgument) {
1✔
3878
                        if (constant instanceof ConstantDynamic) {
1✔
3879
                            constraint.assertDynamicValueInConstantPool();
×
3880
                        }
3881
                    }
3882
                    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethod, bootstrapArgument);
1✔
3883
                }
1✔
3884

3885
                @Override
3886
                public void visitJumpInsn(int opcode, Label label) {
3887
                    if (opcode == Opcodes.JSR) {
1✔
3888
                        constraint.assertSubRoutine();
1✔
3889
                    }
3890
                    super.visitJumpInsn(opcode, label);
1✔
3891
                }
1✔
3892
            }
3893
        }
3894

3895
        /**
3896
         * A type writer that inlines the created type into an existing class file.
3897
         *
3898
         * @param <U> The best known loaded type for the dynamically created type.
3899
         */
3900
        @HashCodeAndEqualsPlugin.Enhance
3901
        public abstract static class ForInlining<U> extends Default<U> {
3902

3903
            /**
3904
             * Indicates that a field should be ignored.
3905
             */
3906
            @AlwaysNull
3907
            private static final FieldVisitor IGNORE_FIELD = null;
1✔
3908

3909
            /**
3910
             * Indicates that a method should be ignored.
3911
             */
3912
            @AlwaysNull
3913
            private static final MethodVisitor IGNORE_METHOD = null;
1✔
3914

3915
            /**
3916
             * Indicates that a record component should be ignored.
3917
             */
3918
            @AlwaysNull
3919
            private static final RecordComponentVisitor IGNORE_RECORD_COMPONENT = null;
1✔
3920

3921
            /**
3922
             * Indicates that an annotation should be ignored.
3923
             */
3924
            @AlwaysNull
3925
            private static final AnnotationVisitor IGNORE_ANNOTATION = null;
1✔
3926

3927
            /**
3928
             * The original type's description.
3929
             */
3930
            protected final TypeDescription originalType;
3931

3932
            /**
3933
             * The class file locator for locating the original type's class file.
3934
             */
3935
            protected final ClassFileLocator classFileLocator;
3936

3937
            /**
3938
             * Creates a new inlining type writer.
3939
             *
3940
             * @param instrumentedType             The instrumented type to be created.
3941
             * @param classFileVersion             The class file specified by the user.
3942
             * @param fieldPool                    The field pool to use.
3943
             * @param recordComponentPool          The record component pool to use.
3944
             * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
3945
             * @param fields                       The instrumented type's declared fields.
3946
             * @param methods                      The instrumented type's declared and virtually inherited methods.
3947
             * @param instrumentedMethods          The instrumented methods relevant to this type creation.
3948
             * @param recordComponents             The instrumented type's record components.
3949
             * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
3950
             * @param typeInitializer              The type initializer to include in the created type's type initializer.
3951
             * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
3952
             * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
3953
             * @param annotationValueFilterFactory The annotation value filter factory to apply.
3954
             * @param annotationRetention          The annotation retention to apply.
3955
             * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
3956
             * @param implementationContextFactory The implementation context factory to apply.
3957
             * @param typeValidation               Determines if a type should be explicitly validated.
3958
             * @param classReaderFactory           The class reader factory to use.
3959
             * @param classWriterFactory           The class writer factory to use.
3960
             * @param typePool                     The type pool to use for computing stack map frames, if required.
3961
             * @param originalType                 The original type's description.
3962
             * @param classFileLocator             The class file locator for locating the original type's class file.
3963
             */
3964
            protected ForInlining(TypeDescription instrumentedType,
3965
                                  ClassFileVersion classFileVersion,
3966
                                  FieldPool fieldPool,
3967
                                  RecordComponentPool recordComponentPool,
3968
                                  List<? extends DynamicType> auxiliaryTypes,
3969
                                  FieldList<FieldDescription.InDefinedShape> fields,
3970
                                  MethodList<?> methods,
3971
                                  MethodList<?> instrumentedMethods,
3972
                                  RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
3973
                                  LoadedTypeInitializer loadedTypeInitializer,
3974
                                  TypeInitializer typeInitializer,
3975
                                  TypeAttributeAppender typeAttributeAppender,
3976
                                  AsmVisitorWrapper asmVisitorWrapper,
3977
                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
3978
                                  AnnotationRetention annotationRetention,
3979
                                  AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
3980
                                  Implementation.Context.Factory implementationContextFactory,
3981
                                  TypeValidation typeValidation,
3982
                                  AsmClassReader.Factory classReaderFactory,
3983
                                  AsmClassWriter.Factory classWriterFactory,
3984
                                  TypePool typePool,
3985
                                  TypeDescription originalType,
3986
                                  ClassFileLocator classFileLocator) {
3987
                super(instrumentedType,
1✔
3988
                        classFileVersion,
3989
                        fieldPool,
3990
                        recordComponentPool,
3991
                        auxiliaryTypes,
3992
                        fields,
3993
                        methods,
3994
                        instrumentedMethods,
3995
                        recordComponents,
3996
                        loadedTypeInitializer,
3997
                        typeInitializer,
3998
                        typeAttributeAppender,
3999
                        asmVisitorWrapper,
4000
                        annotationValueFilterFactory,
4001
                        annotationRetention,
4002
                        auxiliaryTypeNamingStrategy,
4003
                        implementationContextFactory,
4004
                        typeValidation,
4005
                        classReaderFactory,
4006
                        classWriterFactory,
4007
                        typePool);
4008
                this.originalType = originalType;
1✔
4009
                this.classFileLocator = classFileLocator;
1✔
4010
            }
1✔
4011

4012
            /**
4013
             * {@inheritDoc}
4014
             */
4015
            public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags) {
4016
                ContextRegistry contextRegistry = new ContextRegistry();
1✔
4017
                return new RegistryContextClassVisitor(writeTo(ValidatingClassVisitor.of(classVisitor, typeValidation),
1✔
4018
                        typeInitializer,
4019
                        contextRegistry,
4020
                        asmVisitorWrapper.mergeWriter(writerFlags),
1✔
4021
                        asmVisitorWrapper.mergeReader(readerFlags)), contextRegistry);
1✔
4022
            }
4023

4024
            @Override
4025
            protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
4026
                try {
4027
                    int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS);
1✔
4028
                    int readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
1✔
4029
                    byte[] binaryRepresentation = classFileLocator.locate(originalType.getName()).resolve();
1✔
4030
                    dispatcher.dump(instrumentedType, true, binaryRepresentation);
1✔
4031
                    AsmClassReader classReader = classReaderFactory.make(binaryRepresentation);
1✔
4032
                    AsmClassWriter classWriter = classWriterFactory.make(writerFlags, classReader, typePool);
1✔
4033
                    ContextRegistry contextRegistry = new ContextRegistry();
1✔
4034
                    classReader.accept(writeTo(ValidatingClassVisitor.of(classWriter.getVisitor(), typeValidation),
1✔
4035
                            typeInitializer,
4036
                            contextRegistry,
4037
                            writerFlags,
4038
                            readerFlags), readerFlags);
4039
                    return new UnresolvedType(classWriter.getBinaryRepresentation(), contextRegistry.getAuxiliaryTypes());
1✔
4040
                } catch (IOException exception) {
×
4041
                    throw new RuntimeException("The class file could not be written", exception);
×
4042
                }
4043
            }
4044

4045
            /**
4046
             * Creates a class visitor which weaves all changes and additions on the fly.
4047
             *
4048
             * @param classVisitor    The class visitor to which this entry is to be written to.
4049
             * @param typeInitializer The type initializer to apply.
4050
             * @param contextRegistry A context registry to register the lazily created implementation context to.
4051
             * @param writerFlags     The writer flags being used.
4052
             * @param readerFlags     The reader flags being used.
4053
             * @return A class visitor which is capable of applying the changes.
4054
             */
4055
            protected abstract ClassVisitor writeTo(ClassVisitor classVisitor,
4056
                                                    TypeInitializer typeInitializer,
4057
                                                    ContextRegistry contextRegistry,
4058
                                                    int writerFlags,
4059
                                                    int readerFlags);
4060

4061
            /**
4062
             * A context class visitor based on a {@link ContextRegistry}.
4063
             */
4064
            protected class RegistryContextClassVisitor extends ContextClassVisitor {
4065

4066
                /**
4067
                 * The context registry to use.
4068
                 */
4069
                private final ContextRegistry contextRegistry;
4070

4071
                /**
4072
                 * Creates a new context class visitor based on a {@link ContextRegistry}.
4073
                 *
4074
                 * @param classVisitor    The class visitor to delegate to.
4075
                 * @param contextRegistry The context registry to use.
4076
                 */
4077
                protected RegistryContextClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry) {
1✔
4078
                    super(classVisitor);
1✔
4079
                    this.contextRegistry = contextRegistry;
1✔
4080
                }
1✔
4081

4082
                @Override
4083
                public List<DynamicType> getAuxiliaryTypes() {
4084
                    return CompoundList.of(auxiliaryTypes, contextRegistry.getAuxiliaryTypes());
1✔
4085
                }
4086

4087
                @Override
4088
                public LoadedTypeInitializer getLoadedTypeInitializer() {
4089
                    return loadedTypeInitializer;
1✔
4090
                }
4091
            }
4092

4093
            /**
4094
             * A context registry allows to extract auxiliary types from a lazily created implementation context.
4095
             */
4096
            protected static class ContextRegistry {
1✔
4097

4098
                /**
4099
                 * The implementation context that is used for creating a class or {@code null} if it was not registered.
4100
                 */
4101
                @UnknownNull
4102
                private Implementation.Context.ExtractableView implementationContext;
4103

4104
                /**
4105
                 * Registers the implementation context.
4106
                 *
4107
                 * @param implementationContext The implementation context.
4108
                 */
4109
                public void setImplementationContext(Implementation.Context.ExtractableView implementationContext) {
4110
                    this.implementationContext = implementationContext;
1✔
4111
                }
1✔
4112

4113
                /**
4114
                 * Returns the auxiliary types that were registered during class creation. This method must only be called after
4115
                 * a class was created.
4116
                 *
4117
                 * @return The auxiliary types that were registered during class creation
4118
                 */
4119
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Lazy value definition is intended.")
4120
                public List<DynamicType> getAuxiliaryTypes() {
4121
                    return implementationContext.getAuxiliaryTypes();
1✔
4122
                }
4123
            }
4124

4125
            /**
4126
             * A default type writer that reprocesses a type completely.
4127
             *
4128
             * @param <V> The best known loaded type for the dynamically created type.
4129
             */
4130
            @HashCodeAndEqualsPlugin.Enhance
4131
            protected static class WithFullProcessing<V> extends ForInlining<V> {
4132

4133
                /**
4134
                 * An empty array to indicate missing frames.
4135
                 */
4136
                private static final Object[] EMPTY = new Object[0];
1✔
4137

4138
                /**
4139
                 * The method registry to use.
4140
                 */
4141
                private final MethodRegistry.Prepared methodRegistry;
4142

4143
                /**
4144
                 * The implementation target factory to use.
4145
                 */
4146
                private final Implementation.Target.Factory implementationTargetFactory;
4147

4148
                /**
4149
                 * The method rebase resolver to use for rebasing methods.
4150
                 */
4151
                private final MethodRebaseResolver methodRebaseResolver;
4152

4153
                /**
4154
                 * Creates a new inlining type writer that fully reprocesses a type.
4155
                 *
4156
                 * @param instrumentedType             The instrumented type to be created.
4157
                 * @param classFileVersion             The class file specified by the user.
4158
                 * @param fieldPool                    The field pool to use.
4159
                 * @param recordComponentPool          The record component pool to use.
4160
                 * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
4161
                 * @param fields                       The instrumented type's declared fields.
4162
                 * @param methods                      The instrumented type's declared and virtually inherited methods.
4163
                 * @param instrumentedMethods          The instrumented methods relevant to this type creation.
4164
                 * @param recordComponents             The instrumented type's record components.
4165
                 * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
4166
                 * @param typeInitializer              The type initializer to include in the created type's type initializer.
4167
                 * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
4168
                 * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
4169
                 * @param annotationValueFilterFactory The annotation value filter factory to apply.
4170
                 * @param annotationRetention          The annotation retention to apply.
4171
                 * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
4172
                 * @param implementationContextFactory The implementation context factory to apply.
4173
                 * @param typeValidation               Determines if a type should be explicitly validated.
4174
                 * @param classReaderFactory           The class reader factory to use.
4175
                 * @param classWriterFactory           The class writer factory to use.
4176
                 * @param typePool                     The type pool to use for computing stack map frames, if required.
4177
                 * @param originalType                 The original type's description.
4178
                 * @param classFileLocator             The class file locator for locating the original type's class file.
4179
                 * @param methodRegistry               The method registry to use.
4180
                 * @param implementationTargetFactory  The implementation target factory to use.
4181
                 * @param methodRebaseResolver         The method rebase resolver to use for rebasing methods.
4182
                 */
4183
                protected WithFullProcessing(TypeDescription instrumentedType,
4184
                                             ClassFileVersion classFileVersion,
4185
                                             FieldPool fieldPool,
4186
                                             RecordComponentPool recordComponentPool,
4187
                                             List<? extends DynamicType> auxiliaryTypes,
4188
                                             FieldList<FieldDescription.InDefinedShape> fields,
4189
                                             MethodList<?> methods, MethodList<?> instrumentedMethods,
4190
                                             RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
4191
                                             LoadedTypeInitializer loadedTypeInitializer,
4192
                                             TypeInitializer typeInitializer,
4193
                                             TypeAttributeAppender typeAttributeAppender,
4194
                                             AsmVisitorWrapper asmVisitorWrapper,
4195
                                             AnnotationValueFilter.Factory annotationValueFilterFactory,
4196
                                             AnnotationRetention annotationRetention,
4197
                                             AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
4198
                                             Implementation.Context.Factory implementationContextFactory,
4199
                                             TypeValidation typeValidation,
4200
                                             AsmClassReader.Factory classReaderFactory,
4201
                                             AsmClassWriter.Factory classWriterFactory,
4202
                                             TypePool typePool,
4203
                                             TypeDescription originalType,
4204
                                             ClassFileLocator classFileLocator,
4205
                                             MethodRegistry.Prepared methodRegistry,
4206
                                             Implementation.Target.Factory implementationTargetFactory,
4207
                                             MethodRebaseResolver methodRebaseResolver) {
4208
                    super(instrumentedType,
1✔
4209
                            classFileVersion,
4210
                            fieldPool,
4211
                            recordComponentPool,
4212
                            auxiliaryTypes,
4213
                            fields,
4214
                            methods,
4215
                            instrumentedMethods,
4216
                            recordComponents,
4217
                            loadedTypeInitializer,
4218
                            typeInitializer,
4219
                            typeAttributeAppender,
4220
                            asmVisitorWrapper,
4221
                            annotationValueFilterFactory,
4222
                            annotationRetention,
4223
                            auxiliaryTypeNamingStrategy,
4224
                            implementationContextFactory,
4225
                            typeValidation,
4226
                            classReaderFactory,
4227
                            classWriterFactory,
4228
                            typePool,
4229
                            originalType,
4230
                            classFileLocator);
4231
                    this.methodRegistry = methodRegistry;
1✔
4232
                    this.implementationTargetFactory = implementationTargetFactory;
1✔
4233
                    this.methodRebaseResolver = methodRebaseResolver;
1✔
4234
                }
1✔
4235

4236
                /**
4237
                 * {@inheritDoc}
4238
                 */
4239
                protected ClassVisitor writeTo(ClassVisitor classVisitor, TypeInitializer typeInitializer, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
4240
                    classVisitor = new RedefinitionClassVisitor(classVisitor, typeInitializer, contextRegistry, writerFlags, readerFlags);
1✔
4241
                    return originalType.getName().equals(instrumentedType.getName())
1✔
4242
                            ? classVisitor
4243
                            : new OpenedClassRemapper(classVisitor, new SimpleRemapper(originalType.getInternalName(), instrumentedType.getInternalName()));
1✔
4244
                }
4245

4246
                /**
4247
                 * A {@link ClassRemapper} that uses the Byte Buddy-defined API version.
4248
                 */
4249
                protected static class OpenedClassRemapper extends ClassRemapper {
4250

4251
                    /**
4252
                     * Creates a new opened class remapper.
4253
                     *
4254
                     * @param classVisitor The class visitor to wrap
4255
                     * @param remapper     The remapper to apply.
4256
                     */
4257
                    protected OpenedClassRemapper(ClassVisitor classVisitor, Remapper remapper) {
4258
                        super(OpenedClassReader.ASM_API, classVisitor, remapper);
1✔
4259
                    }
1✔
4260
                }
4261

4262
                /**
4263
                 * An initialization handler is responsible for handling the creation of the type initializer.
4264
                 */
4265
                protected interface InitializationHandler {
4266

4267
                    /**
4268
                     * Invoked upon completion of writing the instrumented type.
4269
                     *
4270
                     * @param classVisitor          The class visitor to write any methods to.
4271
                     * @param implementationContext The implementation context to use.
4272
                     */
4273
                    void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext);
4274

4275
                    /**
4276
                     * An initialization handler that creates a new type initializer.
4277
                     */
4278
                    class Creating extends TypeInitializer.Drain.Default implements InitializationHandler {
4279

4280
                        /**
4281
                         * Creates a new creating initialization handler.
4282
                         *
4283
                         * @param instrumentedType             The instrumented type.
4284
                         * @param methodPool                   The method pool to use.
4285
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4286
                         */
4287
                        protected Creating(TypeDescription instrumentedType,
4288
                                           MethodPool methodPool,
4289
                                           AnnotationValueFilter.Factory annotationValueFilterFactory) {
4290
                            super(instrumentedType, methodPool, annotationValueFilterFactory);
1✔
4291
                        }
1✔
4292

4293
                        /**
4294
                         * {@inheritDoc}
4295
                         */
4296
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4297
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4298
                        }
1✔
4299
                    }
4300

4301
                    /**
4302
                     * An initialization handler that appends code to a previously visited type initializer.
4303
                     */
4304
                    abstract class Appending extends MethodVisitor implements InitializationHandler, TypeInitializer.Drain {
4305

4306
                        /**
4307
                         * The instrumented type.
4308
                         */
4309
                        protected final TypeDescription instrumentedType;
4310

4311
                        /**
4312
                         * The method pool record for the type initializer.
4313
                         */
4314
                        protected final MethodPool.Record record;
4315

4316
                        /**
4317
                         * The used annotation value filter factory.
4318
                         */
4319
                        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
4320

4321
                        /**
4322
                         * The frame writer to use.
4323
                         */
4324
                        protected final FrameWriter frameWriter;
4325

4326
                        /**
4327
                         * The currently recorded stack size.
4328
                         */
4329
                        protected int stackSize;
4330

4331
                        /**
4332
                         * The currently recorded local variable length.
4333
                         */
4334
                        protected int localVariableLength;
4335

4336
                        /**
4337
                         * Creates a new appending initialization handler.
4338
                         *
4339
                         * @param methodVisitor                The underlying method visitor.
4340
                         * @param instrumentedType             The instrumented type.
4341
                         * @param record                       The method pool record for the type initializer.
4342
                         * @param annotationValueFilterFactory The used annotation value filter factory.
4343
                         * @param requireFrames                {@code true} if the visitor is required to add frames.
4344
                         * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4345
                         */
4346
                        protected Appending(MethodVisitor methodVisitor,
4347
                                            TypeDescription instrumentedType,
4348
                                            MethodPool.Record record,
4349
                                            AnnotationValueFilter.Factory annotationValueFilterFactory,
4350
                                            boolean requireFrames,
4351
                                            boolean expandFrames) {
4352
                            super(OpenedClassReader.ASM_API, methodVisitor);
1✔
4353
                            this.instrumentedType = instrumentedType;
1✔
4354
                            this.record = record;
1✔
4355
                            this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
4356
                            if (!requireFrames) {
1✔
4357
                                frameWriter = FrameWriter.NoOp.INSTANCE;
1✔
4358
                            } else if (expandFrames) {
1✔
4359
                                frameWriter = FrameWriter.Expanding.INSTANCE;
×
4360
                            } else {
4361
                                frameWriter = new FrameWriter.Active();
1✔
4362
                            }
4363
                        }
1✔
4364

4365
                        /**
4366
                         * Resolves an initialization handler.
4367
                         *
4368
                         * @param enabled                      {@code true} if the implementation context is enabled, i.e. any {@link TypeInitializer} might be active.
4369
                         * @param methodVisitor                The delegation method visitor.
4370
                         * @param instrumentedType             The instrumented type.
4371
                         * @param methodPool                   The method pool to use.
4372
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4373
                         * @param requireFrames                {@code true} if frames must be computed.
4374
                         * @param expandFrames                 {@code true} if frames must be expanded.
4375
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4376
                         */
4377
                        protected static InitializationHandler of(boolean enabled,
4378
                                                                  MethodVisitor methodVisitor,
4379
                                                                  TypeDescription instrumentedType,
4380
                                                                  MethodPool methodPool,
4381
                                                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
4382
                                                                  boolean requireFrames,
4383
                                                                  boolean expandFrames) {
4384
                            return enabled
1✔
4385
                                    ? withDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames)
1✔
4386
                                    : withoutDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4387
                        }
4388

4389
                        /**
4390
                         * Resolves an initialization handler with a drain.
4391
                         *
4392
                         * @param methodVisitor                The delegation method visitor.
4393
                         * @param instrumentedType             The instrumented type.
4394
                         * @param methodPool                   The method pool to use.
4395
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4396
                         * @param requireFrames                {@code true} if frames must be computed.
4397
                         * @param expandFrames                 {@code true} if frames must be expanded.
4398
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4399
                         */
4400
                        private static WithDrain withDrain(MethodVisitor methodVisitor,
4401
                                                           TypeDescription instrumentedType,
4402
                                                           MethodPool methodPool,
4403
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4404
                                                           boolean requireFrames,
4405
                                                           boolean expandFrames) {
4406
                            MethodPool.Record record = methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4407
                            return record.getSort().isImplemented()
1✔
4408
                                    ? new WithDrain.WithActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames)
4409
                                    : new WithDrain.WithoutActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4410
                        }
4411

4412
                        /**
4413
                         * Resolves an initialization handler without a drain.
4414
                         *
4415
                         * @param methodVisitor                The delegation method visitor.
4416
                         * @param instrumentedType             The instrumented type.
4417
                         * @param methodPool                   The method pool to use.
4418
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4419
                         * @param requireFrames                {@code true} if frames must be computed.
4420
                         * @param expandFrames                 {@code true} if frames must be expanded.
4421
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4422
                         */
4423
                        private static WithoutDrain withoutDrain(MethodVisitor methodVisitor,
4424
                                                                 TypeDescription instrumentedType,
4425
                                                                 MethodPool methodPool,
4426
                                                                 AnnotationValueFilter.Factory annotationValueFilterFactory,
4427
                                                                 boolean requireFrames,
4428
                                                                 boolean expandFrames) {
4429
                            MethodPool.Record record = methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4430
                            return record.getSort().isImplemented()
1✔
4431
                                    ? new WithoutDrain.WithActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames)
4432
                                    : new WithoutDrain.WithoutActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory);
4433
                        }
4434

4435
                        @Override
4436
                        public void visitCode() {
4437
                            record.applyAttributes(mv, annotationValueFilterFactory);
1✔
4438
                            super.visitCode();
1✔
4439
                            onStart();
1✔
4440
                        }
1✔
4441

4442
                        /**
4443
                         * Invoked after the user code was visited.
4444
                         */
4445
                        protected abstract void onStart();
4446

4447
                        @Override
4448
                        public void visitFrame(int type, int localVariableLength, @MaybeNull Object[] localVariable, int stackSize, @MaybeNull Object[] stack) {
4449
                            super.visitFrame(type, localVariableLength, localVariable, stackSize, stack);
1✔
4450
                            frameWriter.onFrame(type, localVariableLength);
1✔
4451
                        }
1✔
4452

4453
                        @Override
4454
                        public void visitMaxs(int stackSize, int localVariableLength) {
4455
                            this.stackSize = stackSize;
1✔
4456
                            this.localVariableLength = localVariableLength;
1✔
4457
                        }
1✔
4458

4459
                        @Override
4460
                        public abstract void visitEnd();
4461

4462
                        /**
4463
                         * {@inheritDoc}
4464
                         */
4465
                        public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
4466
                            ByteCodeAppender.Size size = typeInitializer.apply(mv, implementationContext, new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4467
                            stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4468
                            localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4469
                            onComplete(implementationContext);
1✔
4470
                        }
1✔
4471

4472
                        /**
4473
                         * Invoked upon completion of writing the type initializer.
4474
                         *
4475
                         * @param implementationContext The implementation context to use.
4476
                         */
4477
                        protected abstract void onComplete(Implementation.Context implementationContext);
4478

4479
                        /**
4480
                         * {@inheritDoc}
4481
                         */
4482
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4483
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4484
                            mv.visitMaxs(stackSize, localVariableLength);
1✔
4485
                            mv.visitEnd();
1✔
4486
                        }
1✔
4487

4488
                        /**
4489
                         * A frame writer is responsible for adding empty frames on jump instructions.
4490
                         */
4491
                        protected interface FrameWriter {
4492

4493
                            /**
4494
                             * An empty array.
4495
                             */
4496
                            Object[] EMPTY = new Object[0];
1✔
4497

4498
                            /**
4499
                             * Informs this frame writer of an observed frame.
4500
                             *
4501
                             * @param type                The frame type.
4502
                             * @param localVariableLength The length of the local variables array.
4503
                             */
4504
                            void onFrame(int type, int localVariableLength);
4505

4506
                            /**
4507
                             * Emits an empty frame.
4508
                             *
4509
                             * @param methodVisitor The method visitor to write the frame to.
4510
                             */
4511
                            void emitFrame(MethodVisitor methodVisitor);
4512

4513
                            /**
4514
                             * A non-operational frame writer.
4515
                             */
4516
                            enum NoOp implements FrameWriter {
1✔
4517

4518
                                /**
4519
                                 * The singleton instance.
4520
                                 */
4521
                                INSTANCE;
1✔
4522

4523
                                /**
4524
                                 * {@inheritDoc}
4525
                                 */
4526
                                public void onFrame(int type, int localVariableLength) {
4527
                                    /* do nothing */
4528
                                }
1✔
4529

4530
                                /**
4531
                                 * {@inheritDoc}
4532
                                 */
4533
                                public void emitFrame(MethodVisitor methodVisitor) {
4534
                                    /* do nothing */
4535
                                }
1✔
4536
                            }
4537

4538
                            /**
4539
                             * A frame writer that creates an expanded frame.
4540
                             */
4541
                            enum Expanding implements FrameWriter {
1✔
4542

4543
                                /**
4544
                                 * The singleton instance.
4545
                                 */
4546
                                INSTANCE;
1✔
4547

4548
                                /**
4549
                                 * {@inheritDoc}
4550
                                 */
4551
                                public void onFrame(int type, int localVariableLength) {
4552
                                    /* do nothing */
4553
                                }
1✔
4554

4555
                                /**
4556
                                 * {@inheritDoc}
4557
                                 */
4558
                                public void emitFrame(MethodVisitor methodVisitor) {
4559
                                    methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4560
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4561
                                }
1✔
4562
                            }
4563

4564
                            /**
4565
                             * An active frame writer that creates the most efficient frame.
4566
                             */
4567
                            class Active implements FrameWriter {
1✔
4568

4569
                                /**
4570
                                 * The current length of the current local variable array.
4571
                                 */
4572
                                private int currentLocalVariableLength;
4573

4574
                                /**
4575
                                 * {@inheritDoc}
4576
                                 */
4577
                                public void onFrame(int type, int localVariableLength) {
4578
                                    switch (type) {
1✔
4579
                                        case Opcodes.F_SAME:
4580
                                        case Opcodes.F_SAME1:
4581
                                            break;
1✔
4582
                                        case Opcodes.F_APPEND:
4583
                                            currentLocalVariableLength += localVariableLength;
1✔
4584
                                            break;
1✔
4585
                                        case Opcodes.F_CHOP:
4586
                                            currentLocalVariableLength -= localVariableLength;
1✔
4587
                                            break;
1✔
4588
                                        case Opcodes.F_NEW:
4589
                                        case Opcodes.F_FULL:
4590
                                            currentLocalVariableLength = localVariableLength;
1✔
4591
                                            break;
1✔
4592
                                        default:
4593
                                            throw new IllegalStateException("Unexpected frame type: " + type);
1✔
4594
                                    }
4595
                                }
1✔
4596

4597
                                /**
4598
                                 * {@inheritDoc}
4599
                                 */
4600
                                public void emitFrame(MethodVisitor methodVisitor) {
4601
                                    if (currentLocalVariableLength == 0) {
1✔
4602
                                        methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4603
                                    } else if (currentLocalVariableLength > 3) {
1✔
4604
                                        methodVisitor.visitFrame(Opcodes.F_FULL, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4605
                                    } else {
4606
                                        methodVisitor.visitFrame(Opcodes.F_CHOP, currentLocalVariableLength, EMPTY, EMPTY.length, EMPTY);
1✔
4607
                                    }
4608
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4609
                                    currentLocalVariableLength = 0;
1✔
4610
                                }
1✔
4611
                            }
4612
                        }
4613

4614
                        /**
4615
                         * An initialization handler that appends code to a previously visited type initializer without allowing active
4616
                         * {@link TypeInitializer} registrations.
4617
                         */
4618
                        protected abstract static class WithoutDrain extends Appending {
4619

4620
                            /**
4621
                             * Creates a new appending initialization handler without a drain.
4622
                             *
4623
                             * @param methodVisitor                The underlying method visitor.
4624
                             * @param instrumentedType             The instrumented type.
4625
                             * @param record                       The method pool record for the type initializer.
4626
                             * @param annotationValueFilterFactory The used annotation value filter factory.
4627
                             * @param requireFrames                {@code true} if the visitor is required to add frames.
4628
                             * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4629
                             */
4630
                            protected WithoutDrain(MethodVisitor methodVisitor,
4631
                                                   TypeDescription instrumentedType,
4632
                                                   MethodPool.Record record,
4633
                                                   AnnotationValueFilter.Factory annotationValueFilterFactory,
4634
                                                   boolean requireFrames,
4635
                                                   boolean expandFrames) {
4636
                                super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4637
                            }
1✔
4638

4639
                            @Override
4640
                            protected void onStart() {
4641
                                /* do nothing */
4642
                            }
1✔
4643

4644
                            @Override
4645
                            public void visitEnd() {
4646
                                /* do nothing */
4647
                            }
1✔
4648

4649
                            /**
4650
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4651
                             * {@link TypeInitializer} registrations and without an active record.
4652
                             */
4653
                            protected static class WithoutActiveRecord extends WithoutDrain {
4654

4655
                                /**
4656
                                 * Creates a new appending initialization handler without a drain and without an active record.
4657
                                 *
4658
                                 * @param methodVisitor                The underlying method visitor.
4659
                                 * @param instrumentedType             The instrumented type.
4660
                                 * @param record                       The method pool record for the type initializer.
4661
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4662
                                 */
4663
                                protected WithoutActiveRecord(MethodVisitor methodVisitor,
4664
                                                              TypeDescription instrumentedType,
4665
                                                              MethodPool.Record record,
4666
                                                              AnnotationValueFilter.Factory annotationValueFilterFactory) {
4667
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, false, false);
1✔
4668
                                }
1✔
4669

4670
                                @Override
4671
                                protected void onComplete(Implementation.Context implementationContext) {
4672
                                    /* do nothing */
4673
                                }
1✔
4674
                            }
4675

4676
                            /**
4677
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4678
                             * {@link TypeInitializer} registrations and with an active record.
4679
                             */
4680
                            protected static class WithActiveRecord extends WithoutDrain {
4681

4682
                                /**
4683
                                 * The label that indicates the beginning of the active record.
4684
                                 */
4685
                                private final Label label;
4686

4687
                                /**
4688
                                 * Creates a new appending initialization handler without a drain and with an active record.
4689
                                 *
4690
                                 * @param methodVisitor                The underlying method visitor.
4691
                                 * @param instrumentedType             The instrumented type.
4692
                                 * @param record                       The method pool record for the type initializer.
4693
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4694
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4695
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4696
                                 */
4697
                                protected WithActiveRecord(MethodVisitor methodVisitor,
4698
                                                           TypeDescription instrumentedType,
4699
                                                           MethodPool.Record record,
4700
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4701
                                                           boolean requireFrames,
4702
                                                           boolean expandFrames) {
4703
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4704
                                    label = new Label();
1✔
4705
                                }
1✔
4706

4707
                                @Override
4708
                                public void visitInsn(int opcode) {
4709
                                    if (opcode == Opcodes.RETURN) {
1✔
4710
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4711
                                    } else {
4712
                                        super.visitInsn(opcode);
1✔
4713
                                    }
4714
                                }
1✔
4715

4716
                                @Override
4717
                                protected void onComplete(Implementation.Context implementationContext) {
4718
                                    mv.visitLabel(label);
1✔
4719
                                    frameWriter.emitFrame(mv);
1✔
4720
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
4721
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4722
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4723
                                }
1✔
4724

4725
                            }
4726
                        }
4727

4728
                        /**
4729
                         * An initialization handler that appends code to a previously visited type initializer with allowing active
4730
                         * {@link TypeInitializer} registrations.
4731
                         */
4732
                        protected abstract static class WithDrain extends Appending {
4733

4734
                            /**
4735
                             * A label marking the beginning of the appended code.
4736
                             */
4737
                            protected final Label appended;
4738

4739
                            /**
4740
                             * A label marking the beginning og the original type initializer's code.
4741
                             */
4742
                            protected final Label original;
4743

4744
                            /**
4745
                             * Creates a new appending initialization handler with a drain.
4746
                             *
4747
                             * @param methodVisitor                The underlying method visitor.
4748
                             * @param instrumentedType             The instrumented type.
4749
                             * @param record                       The method pool record for the type initializer.
4750
                             * @param annotationValueFilterFactory The used annotation value filter factory.
4751
                             * @param requireFrames                {@code true} if the visitor is required to add frames.
4752
                             * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4753
                             */
4754
                            protected WithDrain(MethodVisitor methodVisitor,
4755
                                                TypeDescription instrumentedType,
4756
                                                MethodPool.Record record,
4757
                                                AnnotationValueFilter.Factory annotationValueFilterFactory,
4758
                                                boolean requireFrames,
4759
                                                boolean expandFrames) {
4760
                                super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4761
                                appended = new Label();
1✔
4762
                                original = new Label();
1✔
4763
                            }
1✔
4764

4765
                            @Override
4766
                            protected void onStart() {
4767
                                mv.visitJumpInsn(Opcodes.GOTO, appended);
1✔
4768
                                mv.visitLabel(original);
1✔
4769
                                frameWriter.emitFrame(mv);
1✔
4770
                            }
1✔
4771

4772
                            @Override
4773
                            public void visitEnd() {
4774
                                mv.visitLabel(appended);
1✔
4775
                                frameWriter.emitFrame(mv);
1✔
4776
                            }
1✔
4777

4778
                            @Override
4779
                            protected void onComplete(Implementation.Context implementationContext) {
4780
                                mv.visitJumpInsn(Opcodes.GOTO, original);
1✔
4781
                                onAfterComplete(implementationContext);
1✔
4782
                            }
1✔
4783

4784
                            /**
4785
                             * Invoked after completion of writing the type initializer.
4786
                             *
4787
                             * @param implementationContext The implementation context to use.
4788
                             */
4789
                            protected abstract void onAfterComplete(Implementation.Context implementationContext);
4790

4791
                            /**
4792
                             * A code appending initialization handler with a drain that does not apply an explicit record.
4793
                             */
4794
                            protected static class WithoutActiveRecord extends WithDrain {
4795

4796
                                /**
4797
                                 * Creates a new appending initialization handler with a drain and without an active record.
4798
                                 *
4799
                                 * @param methodVisitor                The underlying method visitor.
4800
                                 * @param instrumentedType             The instrumented type.
4801
                                 * @param record                       The method pool record for the type initializer.
4802
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4803
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4804
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4805
                                 */
4806
                                protected WithoutActiveRecord(MethodVisitor methodVisitor,
4807
                                                              TypeDescription instrumentedType,
4808
                                                              MethodPool.Record record,
4809
                                                              AnnotationValueFilter.Factory annotationValueFilterFactory,
4810
                                                              boolean requireFrames,
4811
                                                              boolean expandFrames) {
4812
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4813
                                }
1✔
4814

4815
                                @Override
4816
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4817
                                    /* do nothing */
4818
                                }
1✔
4819
                            }
4820

4821
                            /**
4822
                             * A code appending initialization handler with a drain that applies an explicit record.
4823
                             */
4824
                            protected static class WithActiveRecord extends WithDrain {
4825

4826
                                /**
4827
                                 * A label indicating the beginning of the record's code.
4828
                                 */
4829
                                private final Label label;
4830

4831
                                /**
4832
                                 * Creates a new appending initialization handler with a drain and with an active record.
4833
                                 *
4834
                                 * @param methodVisitor                The underlying method visitor.
4835
                                 * @param instrumentedType             The instrumented type.
4836
                                 * @param record                       The method pool record for the type initializer.
4837
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4838
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4839
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4840
                                 */
4841
                                protected WithActiveRecord(MethodVisitor methodVisitor,
4842
                                                           TypeDescription instrumentedType,
4843
                                                           MethodPool.Record record,
4844
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4845
                                                           boolean requireFrames,
4846
                                                           boolean expandFrames) {
4847
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4848
                                    label = new Label();
1✔
4849
                                }
1✔
4850

4851
                                @Override
4852
                                public void visitInsn(int opcode) {
4853
                                    if (opcode == Opcodes.RETURN) {
1✔
4854
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4855
                                    } else {
4856
                                        super.visitInsn(opcode);
1✔
4857
                                    }
4858
                                }
1✔
4859

4860
                                @Override
4861
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4862
                                    mv.visitLabel(label);
1✔
4863
                                    frameWriter.emitFrame(mv);
1✔
4864
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
4865
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4866
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4867
                                }
1✔
4868
                            }
4869
                        }
4870
                    }
4871
                }
4872

4873
                /**
4874
                 * A class visitor which is capable of applying a redefinition of an existing class file.
4875
                 */
4876
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
4877
                protected class RedefinitionClassVisitor extends MetadataAwareClassVisitor {
4878

4879
                    /**
4880
                     * The type initializer to apply.
4881
                     */
4882
                    private final TypeInitializer typeInitializer;
4883

4884
                    /**
4885
                     * A context registry to register the lazily created implementation context to.
4886
                     */
4887
                    private final ContextRegistry contextRegistry;
4888

4889
                    /**
4890
                     * The writer flags being used.
4891
                     */
4892
                    private final int writerFlags;
4893

4894
                    /**
4895
                     * The reader flags being used.
4896
                     */
4897
                    private final int readerFlags;
4898

4899
                    /**
4900
                     * A mapping of fields to write by their unique signature.
4901
                     */
4902
                    private final LinkedHashMap<SignatureKey, FieldDescription> declarableFields;
4903

4904
                    /**
4905
                     * A mapping of methods to write by their unique signature.
4906
                     */
4907
                    private final LinkedHashMap<SignatureKey, MethodDescription> declarableMethods;
4908

4909
                    /**
4910
                     * A mapping of record components to write by their names.
4911
                     */
4912
                    private final LinkedHashMap<String, RecordComponentDescription> declarableRecordComponents;
4913

4914
                    /**
4915
                     * A set of internal names of all nest members not yet defined by this type. If this type is not a nest host, this set is empty.
4916
                     */
4917
                    private final Set<String> nestMembers;
4918

4919
                    /**
4920
                     * A mapping of the internal names of all declared types to their description.
4921
                     */
4922
                    private final LinkedHashMap<String, TypeDescription> declaredTypes;
4923

4924
                    /**
4925
                     * A list of internal names of permitted subclasses to include.
4926
                     */
4927
                    @MaybeNull
4928
                    private final Set<String> permittedSubclasses;
4929

4930
                    /**
4931
                     * The method pool to use or {@code null} if the pool was not yet initialized.
4932
                     */
4933
                    @UnknownNull
4934
                    private MethodPool methodPool;
4935

4936
                    /**
4937
                     * The initialization handler to use or {@code null} if the handler was not yet initialized.
4938
                     */
4939
                    @UnknownNull
4940
                    private InitializationHandler initializationHandler;
4941

4942
                    /**
4943
                     * The implementation context for this class creation or {@code null} if it was not yet created.
4944
                     */
4945
                    @UnknownNull
4946
                    private Implementation.Context.ExtractableView implementationContext;
4947

4948
                    /**
4949
                     * {@code true} if the modifiers for deprecation should be retained.
4950
                     */
4951
                    private boolean retainDeprecationModifiers;
4952

4953
                    /**
4954
                     * Creates a class visitor which is capable of redefining an existent class on the fly.
4955
                     *
4956
                     * @param classVisitor    The underlying class visitor to which writes are delegated.
4957
                     * @param typeInitializer The type initializer to apply.
4958
                     * @param contextRegistry A context registry to register the lazily created implementation context to.
4959
                     * @param writerFlags     The writer flags being used.
4960
                     * @param readerFlags     The reader flags being used.
4961
                     */
4962
                    protected RedefinitionClassVisitor(ClassVisitor classVisitor,
4963
                                                       TypeInitializer typeInitializer,
4964
                                                       ContextRegistry contextRegistry,
4965
                                                       int writerFlags,
4966
                                                       int readerFlags) {
1✔
4967
                        super(OpenedClassReader.ASM_API, classVisitor);
1✔
4968
                        this.typeInitializer = typeInitializer;
1✔
4969
                        this.contextRegistry = contextRegistry;
1✔
4970
                        this.writerFlags = writerFlags;
1✔
4971
                        this.readerFlags = readerFlags;
1✔
4972
                        declarableFields = new LinkedHashMap<SignatureKey, FieldDescription>((int) Math.ceil(fields.size() / 0.75));
1✔
4973
                        for (FieldDescription fieldDescription : fields) {
1✔
4974
                            declarableFields.put(new SignatureKey(fieldDescription.getInternalName(), fieldDescription.getDescriptor()), fieldDescription);
1✔
4975
                        }
1✔
4976
                        declarableMethods = new LinkedHashMap<SignatureKey, MethodDescription>((int) Math.ceil(instrumentedMethods.size() / 0.75));
1✔
4977
                        for (MethodDescription methodDescription : instrumentedMethods) {
1✔
4978
                            declarableMethods.put(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()), methodDescription);
1✔
4979
                        }
1✔
4980
                        declarableRecordComponents = new LinkedHashMap<String, RecordComponentDescription>((int) Math.ceil(recordComponents.size() / 0.75));
1✔
4981
                        for (RecordComponentDescription recordComponentDescription : recordComponents) {
1✔
4982
                            declarableRecordComponents.put(recordComponentDescription.getActualName(), recordComponentDescription);
×
4983
                        }
×
4984
                        if (instrumentedType.isNestHost()) {
1✔
4985
                            nestMembers = new LinkedHashSet<String>((int) Math.ceil(instrumentedType.getNestMembers().size() / 0.75));
1✔
4986
                            for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
1✔
4987
                                nestMembers.add(typeDescription.getInternalName());
×
4988
                            }
1✔
4989
                        } else {
4990
                            nestMembers = Collections.emptySet();
×
4991
                        }
4992
                        declaredTypes = new LinkedHashMap<String, TypeDescription>((int) Math.ceil(instrumentedType.getDeclaredTypes().size() / 0.75));
1✔
4993
                        for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
4994
                            declaredTypes.put(typeDescription.getInternalName(), typeDescription);
1✔
4995
                        }
1✔
4996
                        if (instrumentedType.isSealed()) {
1✔
4997
                            permittedSubclasses = new LinkedHashSet<String>((int) Math.ceil(instrumentedType.getPermittedSubtypes().size() / 0.75));
×
4998
                            for (TypeDescription typeDescription : instrumentedType.getPermittedSubtypes()) {
×
4999
                                permittedSubclasses.add(typeDescription.getInternalName());
×
5000
                            }
×
5001
                        } else {
5002
                            permittedSubclasses = null;
1✔
5003
                        }
5004
                    }
1✔
5005

5006
                    @Override
5007
                    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Relying on correlated type properties.")
5008
                    public void visit(int classFileVersionNumber,
5009
                                      int modifiers,
5010
                                      String internalName,
5011
                                      String genericSignature,
5012
                                      String superClassInternalName,
5013
                                      String[] interfaceTypeInternalName) {
5014
                        ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
1✔
5015
                        methodPool = methodRegistry.compile(implementationTargetFactory, classFileVersion);
1✔
5016
                        initializationHandler = new InitializationHandler.Creating(instrumentedType, methodPool, annotationValueFilterFactory);
1✔
5017
                        implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5018
                                auxiliaryTypeNamingStrategy,
5019
                                typeInitializer,
5020
                                classFileVersion,
5021
                                WithFullProcessing.this.classFileVersion,
5022
                                (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5023
                                        ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5024
                                        : Implementation.Context.FrameGeneration.DISABLED);
5025
                        retainDeprecationModifiers = classFileVersion.isLessThan(ClassFileVersion.JAVA_V5);
1✔
5026
                        contextRegistry.setImplementationContext(implementationContext);
1✔
5027
                        cv = asmVisitorWrapper.wrap(instrumentedType,
1✔
5028
                                cv,
5029
                                implementationContext,
5030
                                typePool,
5031
                                fields,
5032
                                methods,
5033
                                writerFlags,
5034
                                readerFlags);
5035
                        cv.visit(classFileVersionNumber,
1✔
5036
                                instrumentedType.getActualModifiers((modifiers & Opcodes.ACC_SUPER) != 0 && !instrumentedType.isInterface())
1✔
5037
                                        | resolveDeprecationModifiers(modifiers)
1✔
5038
                                        // Anonymous types might not preserve their class file's final modifier via their inner class modifier.
5039
                                        | (((modifiers & Opcodes.ACC_FINAL) != 0 && instrumentedType.isAnonymousType()) ? Opcodes.ACC_FINAL : 0),
1✔
5040
                                instrumentedType.getInternalName(),
1✔
5041
                                TypeDescription.AbstractBase.RAW_TYPES
5042
                                        ? genericSignature
5043
                                        : instrumentedType.getGenericSignature(),
1✔
5044
                                instrumentedType.getSuperClass() == null
1✔
5045
                                        ? (instrumentedType.isInterface() ? TypeDescription.ForLoadedType.of(Object.class).getInternalName() : NO_REFERENCE)
1✔
5046
                                        : instrumentedType.getSuperClass().asErasure().getInternalName(),
1✔
5047
                                instrumentedType.getInterfaces().asErasures().toInternalNames());
1✔
5048
                    }
1✔
5049

5050
                    @Override
5051
                    protected void onVisitNestHost(String nestHost) {
5052
                        onNestHost();
×
5053
                    }
×
5054

5055
                    @Override
5056
                    protected void onNestHost() {
5057
                        if (!instrumentedType.isNestHost()) {
1✔
5058
                            cv.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
5059
                        }
5060
                    }
1✔
5061

5062
                    @Override
5063
                    protected void onVisitPermittedSubclass(String permittedSubclass) {
5064
                        if (permittedSubclasses != null && permittedSubclasses.remove(permittedSubclass)) {
×
5065
                            cv.visitPermittedSubclass(permittedSubclass);
×
5066
                        }
5067
                    }
×
5068

5069
                    @Override
5070
                    protected void onVisitOuterClass(String owner, @MaybeNull String name, @MaybeNull String descriptor) {
5071
                        try { // The Groovy compiler often gets this attribute wrong such that this safety just retains it.
5072
                            onOuterType();
×
5073
                        } catch (Throwable ignored) {
×
5074
                            cv.visitOuterClass(owner, name, descriptor);
×
5075
                        }
×
5076
                    }
×
5077

5078
                    @Override
5079
                    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "Relying on correlated type properties.")
5080
                    protected void onOuterType() {
5081
                        MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
1✔
5082
                        if (enclosingMethod != null) {
1✔
5083
                            cv.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
1✔
5084
                                    enclosingMethod.getInternalName(),
1✔
5085
                                    enclosingMethod.getDescriptor());
1✔
5086
                        } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
1✔
5087
                            cv.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
1✔
5088
                        }
5089
                    }
1✔
5090

5091
                    @Override
5092
                    protected void onAfterAttributes() {
5093
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5094
                    }
1✔
5095

5096
                    @Override
5097
                    @MaybeNull
5098
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5099
                        return annotationRetention.isEnabled()
1✔
5100
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
1✔
5101
                                : IGNORE_ANNOTATION;
×
5102
                    }
5103

5104
                    @Override
5105
                    @MaybeNull
5106
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5107
                        return annotationRetention.isEnabled()
1✔
5108
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5109
                                : IGNORE_ANNOTATION;
1✔
5110
                    }
5111

5112
                    @Override
5113
                    @MaybeNull
5114
                    protected RecordComponentVisitor onVisitRecordComponent(String name, String descriptor, @MaybeNull String genericSignature) {
5115
                        RecordComponentDescription recordComponentDescription = declarableRecordComponents.remove(name);
×
5116
                        if (recordComponentDescription != null) {
×
5117
                            RecordComponentPool.Record record = recordComponentPool.target(recordComponentDescription);
×
5118
                            if (!record.isImplicit()) {
×
5119
                                return redefine(record, genericSignature);
×
5120
                            }
5121
                        }
5122
                        return cv.visitRecordComponent(name, descriptor, genericSignature);
×
5123
                    }
5124

5125
                    /**
5126
                     * Redefines a record component using the given explicit record component pool record.
5127
                     *
5128
                     * @param record           The record component pool record to apply during visitation of the existing record.
5129
                     * @param genericSignature The record component's original generic signature which can be {@code null}.
5130
                     * @return A record component visitor for visiting the existing record component definition.
5131
                     */
5132
                    @MaybeNull
5133
                    protected RecordComponentVisitor redefine(RecordComponentPool.Record record, @MaybeNull String genericSignature) {
5134
                        RecordComponentDescription recordComponentDescription = record.getRecordComponent();
×
5135
                        RecordComponentVisitor recordComponentVisitor = cv.visitRecordComponent(recordComponentDescription.getActualName(),
×
5136
                                recordComponentDescription.getDescriptor(),
×
5137
                                TypeDescription.AbstractBase.RAW_TYPES
5138
                                        ? genericSignature
5139
                                        : recordComponentDescription.getGenericSignature());
×
5140
                        return recordComponentVisitor == null
×
5141
                                ? IGNORE_RECORD_COMPONENT
×
5142
                                : new AttributeObtainingRecordComponentVisitor(recordComponentVisitor, record);
5143
                    }
5144

5145
                    @Override
5146
                    @MaybeNull
5147
                    protected FieldVisitor onVisitField(int modifiers,
5148
                                                        String internalName,
5149
                                                        String descriptor,
5150
                                                        @MaybeNull String genericSignature,
5151
                                                        @MaybeNull Object value) {
5152
                        FieldDescription fieldDescription = declarableFields.remove(new SignatureKey(internalName, descriptor));
1✔
5153
                        if (fieldDescription != null) {
1✔
5154
                            FieldPool.Record record = fieldPool.target(fieldDescription);
1✔
5155
                            if (!record.isImplicit()) {
1✔
5156
                                return redefine(record, value, modifiers, genericSignature);
1✔
5157
                            }
5158
                        }
5159
                        return cv.visitField(modifiers, internalName, descriptor, genericSignature, value);
1✔
5160
                    }
5161

5162
                    /**
5163
                     * Redefines a field using the given explicit field pool record and default value.
5164
                     *
5165
                     * @param record           The field pool value to apply during visitation of the existing field.
5166
                     * @param value            The default value to write onto the field which might be {@code null}.
5167
                     * @param modifiers        The original modifiers of the transformed field.
5168
                     * @param genericSignature The field's original generic signature which can be {@code null}.
5169
                     * @return A field visitor for visiting the existing field definition.
5170
                     */
5171
                    @MaybeNull
5172
                    protected FieldVisitor redefine(FieldPool.Record record, @MaybeNull Object value, int modifiers, @MaybeNull String genericSignature) {
5173
                        FieldDescription instrumentedField = record.getField();
1✔
5174
                        FieldVisitor fieldVisitor = cv.visitField(instrumentedField.getActualModifiers() | resolveDeprecationModifiers(modifiers),
1✔
5175
                                instrumentedField.getInternalName(),
1✔
5176
                                instrumentedField.getDescriptor(),
1✔
5177
                                TypeDescription.AbstractBase.RAW_TYPES
5178
                                        ? genericSignature
5179
                                        : instrumentedField.getGenericSignature(),
1✔
5180
                                record.resolveDefault(value));
1✔
5181
                        return fieldVisitor == null
1✔
5182
                                ? IGNORE_FIELD
1✔
5183
                                : new AttributeObtainingFieldVisitor(fieldVisitor, record);
5184
                    }
5185

5186
                    @Override
5187
                    @MaybeNull
5188
                    protected MethodVisitor onVisitMethod(int modifiers,
5189
                                                          String internalName,
5190
                                                          String descriptor,
5191
                                                          @MaybeNull String genericSignature,
5192
                                                          @MaybeNull String[] exceptionName) {
5193
                        if (internalName.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
5194
                            MethodVisitor methodVisitor = cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName);
1✔
5195
                            return methodVisitor == null
1✔
5196
                                    ? IGNORE_METHOD
1✔
5197
                                    : (MethodVisitor) (initializationHandler = InitializationHandler.Appending.of(implementationContext.isEnabled(),
1✔
5198
                                    methodVisitor,
5199
                                    instrumentedType,
5200
                                    methodPool,
5201
                                    annotationValueFilterFactory,
5202
                                    (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && implementationContext.getClassFileVersion().isAtLeast(ClassFileVersion.JAVA_V6),
1✔
5203
                                    (readerFlags & ClassReader.EXPAND_FRAMES) != 0));
5204
                        } else {
5205
                            MethodDescription methodDescription = declarableMethods.remove(new SignatureKey(internalName, descriptor));
1✔
5206
                            return methodDescription == null
1✔
5207
                                    ? cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName)
1✔
5208
                                    : redefine(methodDescription, (modifiers & Opcodes.ACC_ABSTRACT) != 0, modifiers, genericSignature);
1✔
5209
                        }
5210
                    }
5211

5212
                    /**
5213
                     * Redefines a given method if this is required by looking up a potential implementation from the
5214
                     * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool}.
5215
                     *
5216
                     * @param methodDescription The method being considered for redefinition.
5217
                     * @param abstractOrigin    {@code true} if the original method is abstract, i.e. there is no implementation to preserve.
5218
                     * @param modifiers         The original modifiers of the transformed method.
5219
                     * @param genericSignature  The method's original generic signature which can be {@code null}.
5220
                     * @return A method visitor which is capable of consuming the original method.
5221
                     */
5222
                    @MaybeNull
5223
                    protected MethodVisitor redefine(MethodDescription methodDescription, boolean abstractOrigin, int modifiers, @MaybeNull String genericSignature) {
5224
                        MethodPool.Record record = methodPool.target(methodDescription);
1✔
5225
                        if (!record.getSort().isDefined()) {
1✔
5226
                            return cv.visitMethod(methodDescription.getActualModifiers() | resolveDeprecationModifiers(modifiers),
×
5227
                                    methodDescription.getInternalName(),
×
5228
                                    methodDescription.getDescriptor(),
×
5229
                                    TypeDescription.AbstractBase.RAW_TYPES
5230
                                            ? genericSignature
5231
                                            : methodDescription.getGenericSignature(),
×
5232
                                    methodDescription.getExceptionTypes().asErasures().toInternalNames());
×
5233
                        }
5234
                        MethodDescription implementedMethod = record.getMethod();
1✔
5235
                        MethodVisitor methodVisitor = cv.visitMethod(ModifierContributor.Resolver
1✔
5236
                                        .of(Collections.singleton(record.getVisibility()))
1✔
5237
                                        .resolve(implementedMethod.getActualModifiers(record.getSort().isImplemented())) | resolveDeprecationModifiers(modifiers),
1✔
5238
                                implementedMethod.getInternalName(),
1✔
5239
                                implementedMethod.getDescriptor(),
1✔
5240
                                TypeDescription.AbstractBase.RAW_TYPES
5241
                                        ? genericSignature
5242
                                        : implementedMethod.getGenericSignature(),
1✔
5243
                                implementedMethod.getExceptionTypes().asErasures().toInternalNames());
1✔
5244
                        if (methodVisitor == null) {
1✔
5245
                            return IGNORE_METHOD;
×
5246
                        } else if (abstractOrigin) {
1✔
5247
                            return new AttributeObtainingMethodVisitor(methodVisitor, record);
1✔
5248
                        } else if (methodDescription.isNative()) {
1✔
5249
                            MethodRebaseResolver.Resolution resolution = methodRebaseResolver.resolve(implementedMethod.asDefined());
×
5250
                            if (resolution.isRebased()) {
×
5251
                                MethodVisitor rebasedMethodVisitor = super.visitMethod(resolution.getResolvedMethod().getActualModifiers()
×
5252
                                                | resolveDeprecationModifiers(modifiers),
×
5253
                                        resolution.getResolvedMethod().getInternalName(),
×
5254
                                        resolution.getResolvedMethod().getDescriptor(),
×
5255
                                        TypeDescription.AbstractBase.RAW_TYPES
5256
                                                ? genericSignature
5257
                                                : implementedMethod.getGenericSignature(),
×
5258
                                        resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
×
5259
                                if (rebasedMethodVisitor != null) {
×
5260
                                    rebasedMethodVisitor.visitEnd();
×
5261
                                }
5262
                            }
5263
                            return new AttributeObtainingMethodVisitor(methodVisitor, record);
×
5264
                        } else {
5265
                            return new CodePreservingMethodVisitor(methodVisitor, record, methodRebaseResolver.resolve(implementedMethod.asDefined()));
1✔
5266
                        }
5267
                    }
5268

5269
                    @Override
5270
                    protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
5271
                        if (!internalName.equals(instrumentedType.getInternalName())) {
1✔
5272
                            TypeDescription declaredType = declaredTypes.remove(internalName);
1✔
5273
                            if (declaredType == null) {
1✔
5274
                                cv.visitInnerClass(internalName, outerName, innerName, modifiers);
1✔
5275
                            } else {
5276
                                cv.visitInnerClass(internalName,
1✔
5277
                                        // The second condition is added to retain the structure of some Java 6 compiled classes
5278
                                        declaredType.isMemberType() || outerName != null && innerName == null && declaredType.isAnonymousType()
1✔
5279
                                                ? instrumentedType.getInternalName()
1✔
5280
                                                : NO_REFERENCE,
1✔
5281
                                        declaredType.isAnonymousType()
1✔
5282
                                                ? NO_REFERENCE
1✔
5283
                                                : declaredType.getSimpleName(),
1✔
5284
                                        declaredType.getModifiers());
1✔
5285
                            }
5286
                        }
5287
                    }
1✔
5288

5289
                    @Override
5290
                    protected void onVisitNestMember(String nestMember) {
5291
                        if (instrumentedType.isNestHost() && nestMembers.remove(nestMember)) {
×
5292
                            cv.visitNestMember(nestMember);
×
5293
                        }
5294
                    }
×
5295

5296
                    @Override
5297
                    protected void onVisitEnd() {
5298
                        for (String nestMember : nestMembers) {
1✔
5299
                            cv.visitNestMember(nestMember);
×
5300
                        }
×
5301
                        if (permittedSubclasses != null) {
1✔
5302
                            for (String permittedSubclass : permittedSubclasses) {
×
5303
                                cv.visitPermittedSubclass(permittedSubclass);
×
5304
                            }
×
5305
                        }
5306
                        TypeDescription declaringType = instrumentedType.getDeclaringType();
1✔
5307
                        if (declaringType != null) {
1✔
5308
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5309
                                    declaringType.getInternalName(),
1✔
5310
                                    instrumentedType.getSimpleName(),
1✔
5311
                                    instrumentedType.getModifiers());
1✔
5312
                        } else if (instrumentedType.isLocalType()) {
1✔
5313
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5314
                                    NO_REFERENCE,
1✔
5315
                                    instrumentedType.getSimpleName(),
1✔
5316
                                    instrumentedType.getModifiers());
1✔
5317
                        } else if (instrumentedType.isAnonymousType()) {
1✔
5318
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5319
                                    NO_REFERENCE,
1✔
5320
                                    NO_REFERENCE,
1✔
5321
                                    instrumentedType.getModifiers());
1✔
5322
                        }
5323
                        for (TypeDescription typeDescription : declaredTypes.values()) {
1✔
5324
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
5325
                                    typeDescription.isMemberType()
×
5326
                                            ? instrumentedType.getInternalName()
×
5327
                                            : NO_REFERENCE,
×
5328
                                    typeDescription.isAnonymousType()
×
5329
                                            ? NO_REFERENCE
×
5330
                                            : typeDescription.getSimpleName(),
×
5331
                                    typeDescription.getModifiers());
×
5332
                        }
×
5333
                        for (RecordComponentDescription recordComponent : declarableRecordComponents.values()) {
1✔
5334
                            recordComponentPool.target(recordComponent).apply(cv, annotationValueFilterFactory);
×
5335
                        }
×
5336
                        for (FieldDescription fieldDescription : declarableFields.values()) {
1✔
5337
                            fieldPool.target(fieldDescription).apply(cv, annotationValueFilterFactory);
1✔
5338
                        }
1✔
5339
                        for (MethodDescription methodDescription : declarableMethods.values()) {
1✔
5340
                            methodPool.target(methodDescription).apply(cv, implementationContext, annotationValueFilterFactory);
1✔
5341
                        }
1✔
5342
                        initializationHandler.complete(cv, implementationContext);
1✔
5343
                        cv.visitEnd();
1✔
5344
                    }
1✔
5345

5346
                    /**
5347
                     * Returns {@link Opcodes#ACC_DEPRECATED} if the current class file version only represents deprecated methods using modifiers
5348
                     * that are not exposed in the type description API what is true for class files before Java 5 and if the supplied modifiers indicate
5349
                     * deprecation.
5350
                     *
5351
                     * @param modifiers The original modifiers.
5352
                     * @return {@link Opcodes#ACC_DEPRECATED} if the supplied modifiers imply deprecation.
5353
                     */
5354
                    private int resolveDeprecationModifiers(int modifiers) {
5355
                        return retainDeprecationModifiers && (modifiers & Opcodes.ACC_DEPRECATED) != 0
1✔
5356
                                ? Opcodes.ACC_DEPRECATED
5357
                                : ModifierContributor.EMPTY_MASK;
5358
                    }
5359

5360
                    /**
5361
                     * A field visitor that obtains all attributes and annotations of a field that is found in the
5362
                     * class file but that discards all code.
5363
                     */
5364
                    protected class AttributeObtainingFieldVisitor extends FieldVisitor {
5365

5366
                        /**
5367
                         * The field pool record to apply onto the field visitor.
5368
                         */
5369
                        private final FieldPool.Record record;
5370

5371
                        /**
5372
                         * Creates a new attribute obtaining field visitor.
5373
                         *
5374
                         * @param fieldVisitor The field visitor to delegate to.
5375
                         * @param record       The field pool record to apply onto the field visitor.
5376
                         */
5377
                        protected AttributeObtainingFieldVisitor(FieldVisitor fieldVisitor, FieldPool.Record record) {
1✔
5378
                            super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
5379
                            this.record = record;
1✔
5380
                        }
1✔
5381

5382
                        @Override
5383
                        @MaybeNull
5384
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5385
                            return annotationRetention.isEnabled()
×
5386
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5387
                                    : IGNORE_ANNOTATION;
×
5388
                        }
5389

5390
                        @Override
5391
                        @MaybeNull
5392
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5393
                            return annotationRetention.isEnabled()
1✔
5394
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5395
                                    : IGNORE_ANNOTATION;
1✔
5396
                        }
5397

5398
                        @Override
5399
                        public void visitEnd() {
5400
                            record.apply(fv, annotationValueFilterFactory);
1✔
5401
                            super.visitEnd();
1✔
5402
                        }
1✔
5403
                    }
5404

5405
                    /**
5406
                     * A record component visitor that obtains all attributes and annotations of a record component that is found
5407
                     * in the class file but discards all code.
5408
                     */
5409
                    protected class AttributeObtainingRecordComponentVisitor extends RecordComponentVisitor {
5410

5411
                        /**
5412
                         * The record component pool record to apply onto the record component visitor.
5413
                         */
5414
                        private final RecordComponentPool.Record record;
5415

5416
                        /**
5417
                         * Creates a new attribute obtaining record component visitor.
5418
                         *
5419
                         * @param recordComponentVisitor The record component visitor to delegate to.
5420
                         * @param record                 The record component pool record to apply onto the record component visitor.
5421
                         */
5422
                        protected AttributeObtainingRecordComponentVisitor(RecordComponentVisitor recordComponentVisitor, RecordComponentPool.Record record) {
×
5423
                            super(OpenedClassReader.ASM_API, recordComponentVisitor);
×
5424
                            this.record = record;
×
5425
                        }
×
5426

5427
                        @Override
5428
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5429
                            return annotationRetention.isEnabled()
×
5430
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5431
                                    : IGNORE_ANNOTATION;
×
5432
                        }
5433

5434
                        @Override
5435
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5436
                            return annotationRetention.isEnabled()
×
5437
                                    ? super.visitAnnotation(descriptor, visible)
×
5438
                                    : IGNORE_ANNOTATION;
×
5439
                        }
5440

5441
                        @Override
5442
                        public void visitEnd() {
5443
                            record.apply(getDelegate(), annotationValueFilterFactory);
×
5444
                            super.visitEnd();
×
5445
                        }
×
5446
                    }
5447

5448
                    /**
5449
                     * A method visitor that preserves the code of a method in the class file by copying it into a rebased
5450
                     * method while copying all attributes and annotations to the actual method.
5451
                     */
5452
                    protected class CodePreservingMethodVisitor extends MethodVisitor {
5453

5454
                        /**
5455
                         * The method visitor of the actual method.
5456
                         */
5457
                        private final MethodVisitor actualMethodVisitor;
5458

5459
                        /**
5460
                         * The method pool entry to apply.
5461
                         */
5462
                        private final MethodPool.Record record;
5463

5464
                        /**
5465
                         * The resolution of a potential rebased method.
5466
                         */
5467
                        private final MethodRebaseResolver.Resolution resolution;
5468

5469
                        /**
5470
                         * Creates a new code preserving method visitor.
5471
                         *
5472
                         * @param actualMethodVisitor The method visitor of the actual method.
5473
                         * @param record              The method pool entry to apply.
5474
                         * @param resolution          The resolution of the method rebase resolver in use.
5475
                         */
5476
                        protected CodePreservingMethodVisitor(MethodVisitor actualMethodVisitor,
5477
                                                              MethodPool.Record record,
5478
                                                              MethodRebaseResolver.Resolution resolution) {
1✔
5479
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5480
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5481
                            this.record = record;
1✔
5482
                            this.resolution = resolution;
1✔
5483
                            record.applyHead(actualMethodVisitor);
1✔
5484
                        }
1✔
5485

5486
                        @Override
5487
                        @MaybeNull
5488
                        public AnnotationVisitor visitAnnotationDefault() {
5489
                            return IGNORE_ANNOTATION; // Annotation types can never be rebased.
×
5490
                        }
5491

5492
                        @Override
5493
                        @MaybeNull
5494
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5495
                            return annotationRetention.isEnabled()
×
5496
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5497
                                    : IGNORE_ANNOTATION;
×
5498
                        }
5499

5500
                        @Override
5501
                        @MaybeNull
5502
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5503
                            return annotationRetention.isEnabled()
1✔
5504
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5505
                                    : IGNORE_ANNOTATION;
1✔
5506
                        }
5507

5508
                        @Override
5509
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5510
                            if (annotationRetention.isEnabled()) {
1✔
5511
                                super.visitAnnotableParameterCount(count, visible);
1✔
5512
                            }
5513
                        }
1✔
5514

5515
                        @Override
5516
                        @MaybeNull
5517
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5518
                            return annotationRetention.isEnabled()
1✔
5519
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
1✔
5520
                                    : IGNORE_ANNOTATION;
1✔
5521
                        }
5522

5523
                        @Override
5524
                        public void visitCode() {
5525
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5526
                            actualMethodVisitor.visitEnd();
1✔
5527
                            if (resolution.isRebased()) {
1✔
5528
                                mv = cv.visitMethod(resolution.getResolvedMethod().getActualModifiers(),
1✔
5529
                                        resolution.getResolvedMethod().getInternalName(),
1✔
5530
                                        resolution.getResolvedMethod().getDescriptor(),
1✔
5531
                                        resolution.getResolvedMethod().getGenericSignature(),
1✔
5532
                                        resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
1✔
5533
                                super.visitCode();
1✔
5534
                                if (!resolution.getAppendedParameters().isEmpty() && implementationContext.getFrameGeneration().isActive()) {
1✔
5535
                                    if (implementationContext.getFrameGeneration() == Implementation.Context.FrameGeneration.GENERATE && resolution.getAppendedParameters().size() < 4) {
1✔
5536
                                        super.visitFrame(Opcodes.F_CHOP, resolution.getAppendedParameters().size(), EMPTY, EMPTY.length, EMPTY);
1✔
5537
                                    } else {
5538
                                        Object[] frame = new Object[resolution.getResolvedMethod().getParameters().size()
1✔
5539
                                                - resolution.getAppendedParameters().size()
1✔
5540
                                                + 1];
5541
                                        frame[0] = Opcodes.UNINITIALIZED_THIS;
1✔
5542
                                        for (int index = 1; index < frame.length; index++) {
1✔
5543
                                            TypeDefinition typeDefinition = resolution.getResolvedMethod()
1✔
5544
                                                    .getParameters()
1✔
5545
                                                    .get(index - 1)
1✔
5546
                                                    .getType();
1✔
5547
                                            if (typeDefinition.represents(boolean.class)
1✔
5548
                                                    || typeDefinition.represents(byte.class)
1✔
5549
                                                    || typeDefinition.represents(short.class)
1✔
5550
                                                    || typeDefinition.represents(char.class)
1✔
5551
                                                    || typeDefinition.represents(int.class)) {
1✔
5552
                                                frame[index] = Opcodes.INTEGER;
×
5553
                                            } else if (typeDefinition.represents(long.class)) {
1✔
5554
                                                frame[index] = Opcodes.LONG;
×
5555
                                            } else if (typeDefinition.represents(float.class)) {
1✔
5556
                                                frame[index] = Opcodes.FLOAT;
×
5557
                                            } else if (typeDefinition.represents(double.class)) {
1✔
5558
                                                frame[index] = Opcodes.DOUBLE;
×
5559
                                            } else {
5560
                                                frame[index] = typeDefinition.asErasure().getInternalName();
1✔
5561
                                            }
5562
                                        }
5563
                                        super.visitFrame((readerFlags & ClassReader.EXPAND_FRAMES) == 0
1✔
5564
                                                ? Opcodes.F_FULL
5565
                                                : Opcodes.F_NEW, frame.length, frame, EMPTY.length, EMPTY);
1✔
5566
                                    }
5567
                                    super.visitInsn(Opcodes.NOP);
1✔
5568
                                }
5569
                            } else {
5570
                                mv = IGNORE_METHOD;
1✔
5571
                                super.visitCode();
1✔
5572
                            }
5573
                        }
1✔
5574

5575
                        @Override
5576
                        public void visitMaxs(int stackSize, int localVariableLength) {
5577
                            super.visitMaxs(stackSize, Math.max(localVariableLength, resolution.getResolvedMethod().getStackSize()));
1✔
5578
                        }
1✔
5579
                    }
5580

5581
                    /**
5582
                     * A method visitor that obtains all attributes and annotations of a method that is found in the
5583
                     * class file but that discards all code.
5584
                     */
5585
                    protected class AttributeObtainingMethodVisitor extends MethodVisitor {
5586

5587
                        /**
5588
                         * The method visitor to which the actual method is to be written to.
5589
                         */
5590
                        private final MethodVisitor actualMethodVisitor;
5591

5592
                        /**
5593
                         * The method pool entry to apply.
5594
                         */
5595
                        private final MethodPool.Record record;
5596

5597
                        /**
5598
                         * Creates a new attribute obtaining method visitor.
5599
                         *
5600
                         * @param actualMethodVisitor The method visitor of the actual method.
5601
                         * @param record              The method pool entry to apply.
5602
                         */
5603
                        protected AttributeObtainingMethodVisitor(MethodVisitor actualMethodVisitor, MethodPool.Record record) {
1✔
5604
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5605
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5606
                            this.record = record;
1✔
5607
                            record.applyHead(actualMethodVisitor);
1✔
5608
                        }
1✔
5609

5610
                        @Override
5611
                        @MaybeNull
5612
                        public AnnotationVisitor visitAnnotationDefault() {
5613
                            return IGNORE_ANNOTATION;
×
5614
                        }
5615

5616
                        @Override
5617
                        @MaybeNull
5618
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5619
                            return annotationRetention.isEnabled()
×
5620
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5621
                                    : IGNORE_ANNOTATION;
×
5622
                        }
5623

5624
                        @Override
5625
                        @MaybeNull
5626
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5627
                            return annotationRetention.isEnabled()
×
5628
                                    ? super.visitAnnotation(descriptor, visible)
×
5629
                                    : IGNORE_ANNOTATION;
×
5630
                        }
5631

5632
                        @Override
5633
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5634
                            if (annotationRetention.isEnabled()) {
×
5635
                                super.visitAnnotableParameterCount(count, visible);
×
5636
                            }
5637
                        }
×
5638

5639
                        @Override
5640
                        @MaybeNull
5641
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5642
                            return annotationRetention.isEnabled()
×
5643
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
×
5644
                                    : IGNORE_ANNOTATION;
×
5645
                        }
5646

5647
                        @Override
5648
                        public void visitCode() {
5649
                            mv = IGNORE_METHOD;
×
5650
                        }
×
5651

5652
                        @Override
5653
                        public void visitEnd() {
5654
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5655
                            actualMethodVisitor.visitEnd();
1✔
5656
                        }
1✔
5657
                    }
5658
                }
5659
            }
5660

5661
            /**
5662
             * A default type writer that only applies a type decoration.
5663
             *
5664
             * @param <V> The best known loaded type for the dynamically created type.
5665
             */
5666
            protected static class WithDecorationOnly<V> extends ForInlining<V> {
5667

5668
                /**
5669
                 * Creates a new inlining type writer that only applies a decoration.
5670
                 *
5671
                 * @param instrumentedType             The instrumented type to be created.
5672
                 * @param classFileVersion             The class file specified by the user.
5673
                 * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
5674
                 * @param methods                      The instrumented type's declared and virtually inherited methods.
5675
                 * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
5676
                 * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
5677
                 * @param annotationValueFilterFactory The annotation value filter factory to apply.
5678
                 * @param annotationRetention          The annotation retention to apply.
5679
                 * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
5680
                 * @param implementationContextFactory The implementation context factory to apply.
5681
                 * @param typeValidation               Determines if a type should be explicitly validated.
5682
                 * @param classReaderFactory           The class reader factory to use.
5683
                 * @param classWriterFactory           The class writer factory to use.
5684
                 * @param typePool                     The type pool to use for computing stack map frames, if required.
5685
                 * @param classFileLocator             The class file locator for locating the original type's class file.
5686
                 */
5687
                protected WithDecorationOnly(TypeDescription instrumentedType,
5688
                                             ClassFileVersion classFileVersion,
5689
                                             List<? extends DynamicType> auxiliaryTypes,
5690
                                             MethodList<?> methods,
5691
                                             TypeAttributeAppender typeAttributeAppender,
5692
                                             AsmVisitorWrapper asmVisitorWrapper,
5693
                                             AnnotationValueFilter.Factory annotationValueFilterFactory,
5694
                                             AnnotationRetention annotationRetention,
5695
                                             AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
5696
                                             Implementation.Context.Factory implementationContextFactory,
5697
                                             TypeValidation typeValidation,
5698
                                             AsmClassReader.Factory classReaderFactory,
5699
                                             AsmClassWriter.Factory classWriterFactory,
5700
                                             TypePool typePool,
5701
                                             ClassFileLocator classFileLocator) {
5702
                    super(instrumentedType,
1✔
5703
                            classFileVersion,
5704
                            FieldPool.Disabled.INSTANCE,
5705
                            RecordComponentPool.Disabled.INSTANCE,
5706
                            auxiliaryTypes,
5707
                            new LazyFieldList(instrumentedType),
5708
                            methods,
5709
                            new MethodList.Empty<MethodDescription>(),
5710
                            new RecordComponentList.Empty<RecordComponentDescription.InDefinedShape>(),
5711
                            LoadedTypeInitializer.NoOp.INSTANCE,
5712
                            TypeInitializer.None.INSTANCE,
5713
                            typeAttributeAppender,
5714
                            asmVisitorWrapper,
5715
                            annotationValueFilterFactory,
5716
                            annotationRetention,
5717
                            auxiliaryTypeNamingStrategy,
5718
                            implementationContextFactory,
5719
                            typeValidation,
5720
                            classReaderFactory,
5721
                            classWriterFactory,
5722
                            typePool,
5723
                            instrumentedType,
5724
                            classFileLocator);
5725
                }
1✔
5726

5727
                /**
5728
                 * {@inheritDoc}
5729
                 */
5730
                protected ClassVisitor writeTo(ClassVisitor classVisitor,
5731
                                               TypeInitializer typeInitializer,
5732
                                               ContextRegistry contextRegistry,
5733
                                               int writerFlags,
5734
                                               int readerFlags) {
5735
                    if (typeInitializer.isDefined()) {
1✔
5736
                        throw new UnsupportedOperationException("Cannot apply a type initializer for a decoration");
×
5737
                    }
5738
                    return new DecorationClassVisitor(classVisitor, contextRegistry, writerFlags, readerFlags);
1✔
5739
                }
5740

5741
                /**
5742
                 * A field list that only reads fields lazy to avoid an eager lookup since fields are often not required.
5743
                 */
5744
                protected static class LazyFieldList extends FieldList.AbstractBase<FieldDescription.InDefinedShape> {
5745

5746
                    /**
5747
                     * The instrumented type.
5748
                     */
5749
                    private final TypeDescription instrumentedType;
5750

5751
                    /**
5752
                     * Creates a lazy field list.
5753
                     *
5754
                     * @param instrumentedType The instrumented type.
5755
                     */
5756
                    protected LazyFieldList(TypeDescription instrumentedType) {
1✔
5757
                        this.instrumentedType = instrumentedType;
1✔
5758
                    }
1✔
5759

5760
                    /**
5761
                     * {@inheritDoc}
5762
                     */
5763
                    public FieldDescription.InDefinedShape get(int index) {
5764
                        return instrumentedType.getDeclaredFields().get(index);
×
5765
                    }
5766

5767
                    /**
5768
                     * {@inheritDoc}
5769
                     */
5770
                    public int size() {
5771
                        return instrumentedType.getDeclaredFields().size();
×
5772
                    }
5773
                }
5774

5775
                /**
5776
                 * A class visitor that decorates an existing type.
5777
                 */
5778
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
5779
                protected class DecorationClassVisitor extends MetadataAwareClassVisitor implements TypeInitializer.Drain {
5780

5781
                    /**
5782
                     * A context registry to register the lazily created implementation context to.
5783
                     */
5784
                    private final ContextRegistry contextRegistry;
5785

5786
                    /**
5787
                     * The writer flags being used.
5788
                     */
5789
                    private final int writerFlags;
5790

5791
                    /**
5792
                     * The reader flags being used.
5793
                     */
5794
                    private final int readerFlags;
5795

5796
                    /**
5797
                     * The implementation context to use or {@code null} if the context is not yet initialized.
5798
                     */
5799
                    @UnknownNull
5800
                    private Implementation.Context.ExtractableView implementationContext;
5801

5802
                    /**
5803
                     * Creates a class visitor which is capable of decorating an existent class on the fly.
5804
                     *
5805
                     * @param classVisitor    The underlying class visitor to which writes are delegated.
5806
                     * @param contextRegistry A context registry to register the lazily created implementation context to.
5807
                     * @param writerFlags     The writer flags being used.
5808
                     * @param readerFlags     The reader flags being used.
5809
                     */
5810
                    protected DecorationClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
1✔
5811
                        super(OpenedClassReader.ASM_API, classVisitor);
1✔
5812
                        this.contextRegistry = contextRegistry;
1✔
5813
                        this.writerFlags = writerFlags;
1✔
5814
                        this.readerFlags = readerFlags;
1✔
5815
                    }
1✔
5816

5817
                    @Override
5818
                    public void visit(int classFileVersionNumber,
5819
                                      int modifiers,
5820
                                      String internalName,
5821
                                      String genericSignature,
5822
                                      String superClassInternalName,
5823
                                      String[] interfaceTypeInternalName) {
5824
                        ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
1✔
5825
                        implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5826
                                auxiliaryTypeNamingStrategy,
5827
                                typeInitializer,
5828
                                classFileVersion,
5829
                                WithDecorationOnly.this.classFileVersion,
5830
                                (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5831
                                        ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5832
                                        : Implementation.Context.FrameGeneration.DISABLED);
5833
                        contextRegistry.setImplementationContext(implementationContext);
1✔
5834
                        cv = asmVisitorWrapper.wrap(instrumentedType,
1✔
5835
                                cv,
5836
                                implementationContext,
5837
                                typePool,
5838
                                fields,
5839
                                methods,
5840
                                writerFlags,
5841
                                readerFlags);
5842
                        cv.visit(classFileVersionNumber, modifiers, internalName, genericSignature, superClassInternalName, interfaceTypeInternalName);
1✔
5843
                    }
1✔
5844

5845
                    @Override
5846
                    @MaybeNull
5847
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5848
                        return annotationRetention.isEnabled()
×
5849
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5850
                                : IGNORE_ANNOTATION;
×
5851
                    }
5852

5853
                    @Override
5854
                    @MaybeNull
5855
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5856
                        return annotationRetention.isEnabled()
1✔
5857
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5858
                                : IGNORE_ANNOTATION;
1✔
5859
                    }
5860

5861
                    @Override
5862
                    protected void onAfterAttributes() {
5863
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5864
                    }
1✔
5865

5866
                    @Override
5867
                    protected void onVisitEnd() {
5868
                        implementationContext.drain(this, cv, annotationValueFilterFactory);
1✔
5869
                        cv.visitEnd();
1✔
5870
                    }
1✔
5871

5872
                    /**
5873
                     * {@inheritDoc}
5874
                     */
5875
                    public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
5876
                        /* do nothing */
5877
                    }
1✔
5878
                }
5879
            }
5880
        }
5881

5882
        /**
5883
         * A type writer that creates a class file that is not based upon another, existing class.
5884
         *
5885
         * @param <U> The best known loaded type for the dynamically created type.
5886
         */
5887
        @HashCodeAndEqualsPlugin.Enhance
5888
        public static class ForCreation<U> extends Default<U> {
5889

5890
            /**
5891
             * The method pool to use.
5892
             */
5893
            private final MethodPool methodPool;
5894

5895
            /**
5896
             * Creates a new default type writer for creating a new type that is not based on an existing class file.
5897
             *
5898
             * @param instrumentedType             The instrumented type to be created.
5899
             * @param classFileVersion             The class file version to write the instrumented type in and to apply when creating auxiliary types.
5900
             * @param fieldPool                    The field pool to use.
5901
             * @param methodPool                   The method pool to use.
5902
             * @param recordComponentPool          The record component pool to use.
5903
             * @param auxiliaryTypes               A list of auxiliary types to add to the created type.
5904
             * @param fields                       The instrumented type's declared fields.
5905
             * @param methods                      The instrumented type's declared and virtually inherited methods.
5906
             * @param instrumentedMethods          The instrumented methods relevant to this type creation.
5907
             * @param recordComponents             The instrumented type's record components.
5908
             * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
5909
             * @param typeInitializer              The type initializer to include in the created type's type initializer.
5910
             * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
5911
             * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
5912
             * @param annotationValueFilterFactory The annotation value filter factory to apply.
5913
             * @param annotationRetention          The annotation retention to apply.
5914
             * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
5915
             * @param implementationContextFactory The implementation context factory to apply.
5916
             * @param typeValidation               Determines if a type should be explicitly validated.
5917
             * @param classReaderFactory           The class reader factory to use.
5918
             * @param classWriterFactory           The class writer factory to use.
5919
             * @param typePool                     The type pool to use for computing stack map frames, if required.
5920
             */
5921
            protected ForCreation(TypeDescription instrumentedType,
5922
                                  ClassFileVersion classFileVersion,
5923
                                  FieldPool fieldPool,
5924
                                  MethodPool methodPool,
5925
                                  RecordComponentPool recordComponentPool,
5926
                                  List<? extends DynamicType> auxiliaryTypes,
5927
                                  FieldList<FieldDescription.InDefinedShape> fields,
5928
                                  MethodList<?> methods,
5929
                                  MethodList<?> instrumentedMethods,
5930
                                  RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
5931
                                  LoadedTypeInitializer loadedTypeInitializer,
5932
                                  TypeInitializer typeInitializer,
5933
                                  TypeAttributeAppender typeAttributeAppender,
5934
                                  AsmVisitorWrapper asmVisitorWrapper,
5935
                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
5936
                                  AnnotationRetention annotationRetention,
5937
                                  AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
5938
                                  Implementation.Context.Factory implementationContextFactory,
5939
                                  TypeValidation typeValidation,
5940
                                  AsmClassReader.Factory classReaderFactory,
5941
                                  AsmClassWriter.Factory classWriterFactory,
5942
                                  TypePool typePool) {
5943
                super(instrumentedType,
1✔
5944
                        classFileVersion,
5945
                        fieldPool,
5946
                        recordComponentPool,
5947
                        auxiliaryTypes,
5948
                        fields,
5949
                        methods,
5950
                        instrumentedMethods,
5951
                        recordComponents,
5952
                        loadedTypeInitializer,
5953
                        typeInitializer,
5954
                        typeAttributeAppender,
5955
                        asmVisitorWrapper,
5956
                        annotationValueFilterFactory,
5957
                        annotationRetention,
5958
                        auxiliaryTypeNamingStrategy,
5959
                        implementationContextFactory,
5960
                        typeValidation,
5961
                        classReaderFactory,
5962
                        classWriterFactory,
5963
                        typePool);
5964
                this.methodPool = methodPool;
1✔
5965
            }
1✔
5966

5967
            /**
5968
             * {@inheritDoc}
5969
             */
5970
            public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags) {
5971
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5972
                        auxiliaryTypeNamingStrategy,
5973
                        typeInitializer,
5974
                        classFileVersion,
5975
                        classFileVersion,
5976
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5977
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5978
                                : Implementation.Context.FrameGeneration.DISABLED);
5979
                return new ImplementationContextClassVisitor(new CreationClassVisitor(asmVisitorWrapper.wrap(instrumentedType,
1✔
5980
                        ValidatingClassVisitor.of(classVisitor, typeValidation),
1✔
5981
                        implementationContext,
5982
                        typePool,
5983
                        fields,
5984
                        methods,
5985
                        asmVisitorWrapper.mergeWriter(writerFlags),
1✔
5986
                        asmVisitorWrapper.mergeReader(readerFlags)), implementationContext), implementationContext);
1✔
5987
            }
5988

5989
            @Override
5990
            @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Relying on correlated type properties.")
5991
            protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
5992
                int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS), readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
1✔
5993
                AsmClassWriter classWriter = classWriterFactory.make(writerFlags, typePool);
1✔
5994
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5995
                        auxiliaryTypeNamingStrategy,
5996
                        typeInitializer,
5997
                        classFileVersion,
5998
                        classFileVersion,
5999
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
6000
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
6001
                                : Implementation.Context.FrameGeneration.DISABLED);
6002
                ClassVisitor classVisitor = asmVisitorWrapper.wrap(instrumentedType,
1✔
6003
                        ValidatingClassVisitor.of(classWriter.getVisitor(), typeValidation),
1✔
6004
                        implementationContext,
6005
                        typePool,
6006
                        fields,
6007
                        methods,
6008
                        writerFlags,
6009
                        readerFlags);
6010
                classVisitor.visit(classFileVersion.getMinorMajorVersion(),
1✔
6011
                        instrumentedType.getActualModifiers(!instrumentedType.isInterface()),
1✔
6012
                        instrumentedType.getInternalName(),
1✔
6013
                        instrumentedType.getGenericSignature(),
1✔
6014
                        (instrumentedType.getSuperClass() == null
1✔
6015
                                ? TypeDescription.ForLoadedType.of(Object.class)
1✔
6016
                                : instrumentedType.getSuperClass().asErasure()).getInternalName(),
1✔
6017
                        instrumentedType.getInterfaces().asErasures().toInternalNames());
1✔
6018
                if (!instrumentedType.isNestHost()) {
1✔
6019
                    classVisitor.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
6020
                }
6021
                MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
1✔
6022
                if (enclosingMethod != null) {
1✔
6023
                    classVisitor.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
1✔
6024
                            enclosingMethod.getInternalName(),
1✔
6025
                            enclosingMethod.getDescriptor());
1✔
6026
                } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
1✔
6027
                    classVisitor.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
1✔
6028
                }
6029
                typeAttributeAppender.apply(classVisitor, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6030
                if (instrumentedType.isNestHost()) {
1✔
6031
                    for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
1✔
6032
                        classVisitor.visitNestMember(typeDescription.getInternalName());
×
6033
                    }
×
6034
                }
6035
                for (TypeDescription typeDescription : instrumentedType.getPermittedSubtypes()) {
1✔
6036
                    classVisitor.visitPermittedSubclass(typeDescription.getInternalName());
×
6037
                }
×
6038
                TypeDescription declaringType = instrumentedType.getDeclaringType();
1✔
6039
                if (declaringType != null) {
1✔
6040
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6041
                            declaringType.getInternalName(),
1✔
6042
                            instrumentedType.getSimpleName(),
1✔
6043
                            instrumentedType.getModifiers());
1✔
6044
                } else if (instrumentedType.isLocalType()) {
1✔
6045
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6046
                            NO_REFERENCE,
1✔
6047
                            instrumentedType.getSimpleName(),
1✔
6048
                            instrumentedType.getModifiers());
1✔
6049
                } else if (instrumentedType.isAnonymousType()) {
1✔
6050
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6051
                            NO_REFERENCE,
1✔
6052
                            NO_REFERENCE,
1✔
6053
                            instrumentedType.getModifiers());
1✔
6054
                }
6055
                for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6056
                    classVisitor.visitInnerClass(typeDescription.getInternalName(),
1✔
6057
                            typeDescription.isMemberType()
1✔
6058
                                    ? instrumentedType.getInternalName()
1✔
6059
                                    : NO_REFERENCE,
1✔
6060
                            typeDescription.isAnonymousType()
1✔
6061
                                    ? NO_REFERENCE
1✔
6062
                                    : typeDescription.getSimpleName(),
1✔
6063
                            typeDescription.getModifiers());
1✔
6064
                }
1✔
6065
                for (RecordComponentDescription recordComponentDescription : recordComponents) {
1✔
6066
                    recordComponentPool.target(recordComponentDescription).apply(classVisitor, annotationValueFilterFactory);
×
6067
                }
×
6068
                for (FieldDescription fieldDescription : fields) {
1✔
6069
                    fieldPool.target(fieldDescription).apply(classVisitor, annotationValueFilterFactory);
1✔
6070
                }
1✔
6071
                for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6072
                    methodPool.target(methodDescription).apply(classVisitor, implementationContext, annotationValueFilterFactory);
1✔
6073
                }
1✔
6074
                implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6075
                        methodPool,
6076
                        annotationValueFilterFactory), classVisitor, annotationValueFilterFactory);
6077
                classVisitor.visitEnd();
1✔
6078
                return new UnresolvedType(classWriter.getBinaryRepresentation(), implementationContext.getAuxiliaryTypes());
1✔
6079
            }
6080

6081
            /**
6082
             * A class visitor that applies the subclass creation as a wrapper.
6083
             */
6084
            protected class CreationClassVisitor extends MetadataAwareClassVisitor {
6085

6086
                /**
6087
                 * The implementation context to apply.
6088
                 */
6089
                private final Implementation.Context.ExtractableView implementationContext;
6090

6091
                /**
6092
                 * The declared types that have been visited.
6093
                 */
6094
                private final Set<String> declaredTypes = new HashSet<String>();
1✔
6095

6096
                /**
6097
                 * The signatures of all fields that were explicitly visited.
6098
                 */
6099
                private final Set<SignatureKey> visitedFields = new HashSet<SignatureKey>();
1✔
6100

6101
                /**
6102
                 * The signature of all methods that were explicitly visited.
6103
                 */
6104
                private final Set<SignatureKey> visitedMethods = new HashSet<SignatureKey>();
1✔
6105

6106
                /**
6107
                 * Creates a new wrapper visitor.
6108
                 *
6109
                 * @param classVisitor          The class visitor being wrapped.
6110
                 * @param implementationContext The implementation context to apply.
6111
                 */
6112
                protected CreationClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6113
                    super(OpenedClassReader.ASM_API, classVisitor);
1✔
6114
                    this.implementationContext = implementationContext;
1✔
6115
                }
1✔
6116

6117
                @Override
6118
                protected void onAfterAttributes() {
6119
                    typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6120
                }
1✔
6121

6122
                @Override
6123
                protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
6124
                    declaredTypes.add(internalName);
×
6125
                    super.onVisitInnerClass(internalName, outerName, innerName, modifiers);
×
6126
                }
×
6127

6128
                @Override
6129
                @MaybeNull
6130
                protected FieldVisitor onVisitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
6131
                    visitedFields.add(new SignatureKey(name, descriptor));
×
UNCOV
6132
                    return super.onVisitField(modifiers, name, descriptor, signature, value);
×
6133
                }
6134

6135
                @Override
6136
                @MaybeNull
6137
                protected MethodVisitor onVisitMethod(int modifiers, String internalName, String descriptor, @MaybeNull String signature, @MaybeNull String[] exception) {
UNCOV
6138
                    visitedMethods.add(new SignatureKey(internalName, descriptor));
×
UNCOV
6139
                    return super.onVisitMethod(modifiers, internalName, descriptor, signature, exception);
×
6140
                }
6141

6142
                @Override
6143
                protected void onVisitEnd() {
6144
                    for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6145
                        if (!declaredTypes.contains(typeDescription.getInternalName())) {
×
6146
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
6147
                                    typeDescription.isMemberType()
×
6148
                                            ? instrumentedType.getInternalName()
×
6149
                                            : NO_REFERENCE,
×
6150
                                    typeDescription.isAnonymousType()
×
6151
                                            ? NO_REFERENCE
×
UNCOV
6152
                                            : typeDescription.getSimpleName(),
×
6153
                                    typeDescription.getModifiers());
×
6154
                        }
6155
                    }
×
6156
                    for (FieldDescription fieldDescription : fields) {
1✔
UNCOV
6157
                        if (!visitedFields.contains(new SignatureKey(fieldDescription.getName(), fieldDescription.getDescriptor()))) {
×
6158
                            fieldPool.target(fieldDescription).apply(cv, annotationValueFilterFactory);
×
6159
                        }
UNCOV
6160
                    }
×
6161
                    for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6162
                        if (!visitedMethods.contains(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()))) {
1✔
6163
                            methodPool.target(methodDescription).apply(cv, implementationContext, annotationValueFilterFactory);
1✔
6164
                        }
6165
                    }
1✔
6166
                    implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6167
                            methodPool,
1✔
6168
                            annotationValueFilterFactory), cv, annotationValueFilterFactory);
6169
                    super.onVisitEnd();
1✔
6170
                }
1✔
6171
            }
6172

6173
            /**
6174
             * A context class visitor based on an {@link Implementation.Context}.
6175
             */
6176
            protected class ImplementationContextClassVisitor extends ContextClassVisitor {
6177

6178
                /**
6179
                 * The implementation context to use.
6180
                 */
6181
                private final Implementation.Context.ExtractableView implementationContext;
6182

6183
                /**
6184
                 * Creates a context class loader based on an {@link Implementation.Context}.
6185
                 *
6186
                 * @param classVisitor          The class visitor to delegate to.
6187
                 * @param implementationContext The implementation context to use.
6188
                 */
6189
                protected ImplementationContextClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6190
                    super(classVisitor);
1✔
6191
                    this.implementationContext = implementationContext;
1✔
6192
                }
1✔
6193

6194
                @Override
6195
                public List<DynamicType> getAuxiliaryTypes() {
6196
                    return CompoundList.of(auxiliaryTypes, implementationContext.getAuxiliaryTypes());
1✔
6197
                }
6198

6199
                @Override
6200
                public LoadedTypeInitializer getLoadedTypeInitializer() {
6201
                    return loadedTypeInitializer;
1✔
6202
                }
6203
            }
6204
        }
6205

6206
        /**
6207
         * An action to write a class file to the dumping location.
6208
         */
6209
        @HashCodeAndEqualsPlugin.Enhance
6210
        protected static class ClassDumpAction implements PrivilegedExceptionAction<Void> {
6211

6212
            /**
6213
             * Indicates that nothing is returned from this action.
6214
             */
6215
            @AlwaysNull
6216
            private static final Void NOTHING = null;
1✔
6217

6218
            /**
6219
             * The target folder for writing the class file to.
6220
             */
6221
            private final String target;
6222

6223
            /**
6224
             * The instrumented type.
6225
             */
6226
            private final TypeDescription instrumentedType;
6227

6228
            /**
6229
             * {@code true} if the dumped class file is an input to a class transformation.
6230
             */
6231
            private final boolean original;
6232

6233
            /**
6234
             * The suffix to append to the dumped class file.
6235
             */
6236
            private final long suffix;
6237

6238
            /**
6239
             * The type's binary representation.
6240
             */
6241
            private final byte[] binaryRepresentation;
6242

6243
            /**
6244
             * Creates a new class dump action.
6245
             *
6246
             * @param target               The target folder for writing the class file to.
6247
             * @param instrumentedType     The instrumented type.
6248
             * @param original             {@code true} if the dumped class file is an input to a class transformation.
6249
             * @param suffix               The suffix to append to the dumped class file.
6250
             * @param binaryRepresentation The type's binary representation.
6251
             */
6252
            protected ClassDumpAction(String target, TypeDescription instrumentedType, boolean original, long suffix, byte[] binaryRepresentation) {
1✔
6253
                this.target = target;
1✔
6254
                this.instrumentedType = instrumentedType;
1✔
6255
                this.original = original;
1✔
6256
                this.suffix = suffix;
1✔
6257
                this.binaryRepresentation = binaryRepresentation;
1✔
6258
            }
1✔
6259

6260
            /**
6261
             * {@inheritDoc}
6262
             */
6263
            public Void run() throws Exception {
6264
                OutputStream outputStream = new FileOutputStream(new File(target, instrumentedType.getName()
1✔
6265
                        + (original ? "-original." : ".")
6266
                        + suffix
6267
                        + ".class"));
6268
                try {
6269
                    outputStream.write(binaryRepresentation);
1✔
6270
                    return NOTHING;
1✔
6271
                } finally {
6272
                    outputStream.close();
1✔
6273
                }
6274
            }
6275

6276
            /**
6277
             * A dispatcher for dumping class files to the file system.
6278
             */
6279
            protected interface Dispatcher {
6280

6281
                /**
6282
                 * Dumps a class file to the file system.
6283
                 *
6284
                 * @param instrumentedType     The type to dump.
6285
                 * @param original             {@code true} if the class file is in its original state.
6286
                 * @param binaryRepresentation The class file's binary representation.
6287
                 */
6288
                void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation);
6289

6290
                /**
6291
                 * A disabled dispatcher that does not dump any class files.
6292
                 */
6293
                enum Disabled implements Dispatcher {
1✔
6294

6295
                    /**
6296
                     * The singleton instance.
6297
                     */
6298
                    INSTANCE;
1✔
6299

6300
                    /**
6301
                     * {@inheritDoc}
6302
                     */
6303
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6304
                        /* do nothing */
6305
                    }
1✔
6306
                }
6307

6308
                /**
6309
                 * An enabled dispatcher that dumps class files to a given folder.
6310
                 */
6311
                @HashCodeAndEqualsPlugin.Enhance
6312
                class Enabled implements Dispatcher {
6313

6314
                    /**
6315
                     * The folder to write class files to.
6316
                     */
6317
                    private final String folder;
6318

6319
                    /**
6320
                     * The timestamp to append.
6321
                     */
6322
                    private final long timestamp;
6323

6324
                    /**
6325
                     * Creates a new dispatcher for dumping class files.
6326
                     *
6327
                     * @param folder    The folder to write class files to.
6328
                     * @param timestamp The timestamp to append.
6329
                     */
6330
                    protected Enabled(String folder, long timestamp) {
1✔
6331
                        this.folder = folder;
1✔
6332
                        this.timestamp = timestamp;
1✔
6333
                    }
1✔
6334

6335
                    /**
6336
                     * {@inheritDoc}
6337
                     */
6338
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6339
                        try {
6340
                            doPrivileged(new ClassDumpAction(folder, instrumentedType, original, timestamp, binaryRepresentation));
1✔
UNCOV
6341
                        } catch (Exception exception) {
×
UNCOV
6342
                            exception.printStackTrace();
×
6343
                        }
1✔
6344
                    }
1✔
6345
                }
6346
            }
6347
        }
6348
    }
6349
}
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