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

raphw / byte-buddy / #818

07 Nov 2025 11:24AM UTC coverage: 83.01% (+0.05%) from 82.964%
#818

push

raphw
[release] Release new version.

29613 of 35674 relevant lines covered (83.01%)

0.83 hits per line

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

75.57
/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.module.ModuleDescription;
34
import net.bytebuddy.description.type.PackageDescription;
35
import net.bytebuddy.description.type.RecordComponentDescription;
36
import net.bytebuddy.description.type.RecordComponentList;
37
import net.bytebuddy.description.type.TypeDefinition;
38
import net.bytebuddy.description.type.TypeDescription;
39
import net.bytebuddy.description.type.TypeList;
40
import net.bytebuddy.dynamic.ClassFileLocator;
41
import net.bytebuddy.dynamic.DynamicType;
42
import net.bytebuddy.dynamic.TypeResolutionStrategy;
43
import net.bytebuddy.dynamic.scaffold.inline.MethodRebaseResolver;
44
import net.bytebuddy.dynamic.scaffold.inline.RebaseImplementationTarget;
45
import net.bytebuddy.dynamic.scaffold.subclass.SubclassImplementationTarget;
46
import net.bytebuddy.implementation.Implementation;
47
import net.bytebuddy.implementation.LoadedTypeInitializer;
48
import net.bytebuddy.implementation.attribute.AnnotationAppender;
49
import net.bytebuddy.implementation.attribute.AnnotationRetention;
50
import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
51
import net.bytebuddy.implementation.attribute.FieldAttributeAppender;
52
import net.bytebuddy.implementation.attribute.MethodAttributeAppender;
53
import net.bytebuddy.implementation.attribute.RecordComponentAttributeAppender;
54
import net.bytebuddy.implementation.attribute.TypeAttributeAppender;
55
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
56
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
57
import net.bytebuddy.implementation.bytecode.StackManipulation;
58
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
59
import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
60
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
61
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
62
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
63
import net.bytebuddy.pool.TypePool;
64
import net.bytebuddy.utility.AsmClassReader;
65
import net.bytebuddy.utility.AsmClassWriter;
66
import net.bytebuddy.utility.CompoundList;
67
import net.bytebuddy.utility.OpenedClassReader;
68
import net.bytebuddy.utility.nullability.AlwaysNull;
69
import net.bytebuddy.utility.nullability.MaybeNull;
70
import net.bytebuddy.utility.nullability.UnknownNull;
71
import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
72
import net.bytebuddy.utility.visitor.ContextClassVisitor;
73
import net.bytebuddy.utility.visitor.MetadataAwareClassVisitor;
74
import org.objectweb.asm.AnnotationVisitor;
75
import org.objectweb.asm.ClassReader;
76
import org.objectweb.asm.ClassVisitor;
77
import org.objectweb.asm.ClassWriter;
78
import org.objectweb.asm.ConstantDynamic;
79
import org.objectweb.asm.FieldVisitor;
80
import org.objectweb.asm.Handle;
81
import org.objectweb.asm.Label;
82
import org.objectweb.asm.MethodVisitor;
83
import org.objectweb.asm.ModuleVisitor;
84
import org.objectweb.asm.Opcodes;
85
import org.objectweb.asm.RecordComponentVisitor;
86
import org.objectweb.asm.Type;
87
import org.objectweb.asm.TypePath;
88
import org.objectweb.asm.commons.ClassRemapper;
89
import org.objectweb.asm.commons.Remapper;
90
import org.objectweb.asm.commons.SimpleRemapper;
91

92
import javax.annotation.Nonnull;
93
import java.io.File;
94
import java.io.FileOutputStream;
95
import java.io.IOException;
96
import java.io.OutputStream;
97
import java.security.PrivilegedAction;
98
import java.security.PrivilegedExceptionAction;
99
import java.util.ArrayList;
100
import java.util.Collections;
101
import java.util.HashSet;
102
import java.util.LinkedHashMap;
103
import java.util.LinkedHashSet;
104
import java.util.List;
105
import java.util.Map;
106
import java.util.Set;
107

108
import static net.bytebuddy.matcher.ElementMatchers.is;
109
import static net.bytebuddy.matcher.ElementMatchers.isSubTypeOf;
110
import static net.bytebuddy.matcher.ElementMatchers.not;
111

112
/**
113
 * A type writer is a utility for writing an actual class file using the ASM library.
114
 *
115
 * @param <T> The best known loaded type for the dynamically created type.
116
 */
117
public interface TypeWriter<T> {
118

119
    /**
120
     * A system property that indicates a folder for Byte Buddy to dump class files of all types that it creates.
121
     * If this property is not set, Byte Buddy does not dump any class files. This property is only read a single
122
     * time which is why it must be set on application start-up.
123
     */
124
    String DUMP_PROPERTY = "net.bytebuddy.dump";
125

126
    /**
127
     * Creates the dynamic type that is described by this type writer.
128
     *
129
     * @param typeResolver The type resolution strategy to use.
130
     * @return An unloaded dynamic type that describes the created type.
131
     */
132
    DynamicType.Unloaded<T> make(TypeResolutionStrategy.Resolved typeResolver);
133

134
    /**
135
     * Wraps another ASM class visitor with a visitor that represents this ASM class writer.
136
     *
137
     * @param classVisitor The class visitor to wrap.
138
     * @param writerFlags  The ASM writer flags to consider.
139
     * @param readerFlags  The ASM reader flags to consider.
140
     * @return The supplied class visitor wrapped by this type writer.
141
     */
142
    ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags);
143

144
    /**
145
     * An field pool that allows a lookup for how to implement a field.
146
     */
147
    interface FieldPool {
148

149
        /**
150
         * Looks up a handler entry for a given field.
151
         *
152
         * @param fieldDescription The field being processed.
153
         * @return A handler entry for the given field.
154
         */
155
        Record target(FieldDescription fieldDescription);
156

157
        /**
158
         * An entry of a field pool that describes how a field is implemented.
159
         *
160
         * @see net.bytebuddy.dynamic.scaffold.TypeWriter.FieldPool
161
         */
162
        interface Record {
163

164
            /**
165
             * Determines if this record is implicit, i.e is not defined by a {@link FieldPool}.
166
             *
167
             * @return {@code true} if this record is implicit.
168
             */
169
            boolean isImplicit();
170

171
            /**
172
             * Returns the field that this record represents.
173
             *
174
             * @return The field that this record represents.
175
             */
176
            FieldDescription getField();
177

178
            /**
179
             * Returns the field attribute appender for a given field.
180
             *
181
             * @return The attribute appender to be applied on the given field.
182
             */
183
            FieldAttributeAppender getFieldAppender();
184

185
            /**
186
             * Resolves the default value that this record represents. This is not possible for implicit records.
187
             *
188
             * @param defaultValue The default value that was defined previously or {@code null} if no default value is defined.
189
             * @return The default value for the represented field or {@code null} if no default value is to be defined.
190
             */
191
            @MaybeNull
192
            Object resolveDefault(@MaybeNull Object defaultValue);
193

194
            /**
195
             * Writes this entry to a given class visitor.
196
             *
197
             * @param classVisitor                 The class visitor to which this entry is to be written to.
198
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
199
             */
200
            void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
201

202
            /**
203
             * Applies this record to a field visitor. This is not possible for implicit records.
204
             *
205
             * @param fieldVisitor                 The field visitor onto which this record is to be applied.
206
             * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
207
             */
208
            void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
209

210
            /**
211
             * A record for a simple field without a default value where all of the field's declared annotations are appended.
212
             */
213
            @HashCodeAndEqualsPlugin.Enhance
214
            class ForImplicitField implements Record {
215

216
                /**
217
                 * The implemented field.
218
                 */
219
                private final FieldDescription fieldDescription;
220

221
                /**
222
                 * Creates a new record for a simple field.
223
                 *
224
                 * @param fieldDescription The described field.
225
                 */
226
                public ForImplicitField(FieldDescription fieldDescription) {
1✔
227
                    this.fieldDescription = fieldDescription;
1✔
228
                }
1✔
229

230
                /**
231
                 * {@inheritDoc}
232
                 */
233
                public boolean isImplicit() {
234
                    return true;
1✔
235
                }
236

237
                /**
238
                 * {@inheritDoc}
239
                 */
240
                public FieldDescription getField() {
241
                    return fieldDescription;
1✔
242
                }
243

244
                /**
245
                 * {@inheritDoc}
246
                 */
247
                public FieldAttributeAppender getFieldAppender() {
248
                    throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
1✔
249
                }
250

251
                /**
252
                 * {@inheritDoc}
253
                 */
254
                public Object resolveDefault(@MaybeNull Object defaultValue) {
255
                    throw new IllegalStateException("An implicit field record does not expose a default value: " + this);
1✔
256
                }
257

258
                /**
259
                 * {@inheritDoc}
260
                 */
261
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
262
                    FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
1✔
263
                            fieldDescription.getInternalName(),
1✔
264
                            fieldDescription.getDescriptor(),
1✔
265
                            fieldDescription.getGenericSignature(),
1✔
266
                            FieldDescription.NO_DEFAULT_VALUE);
267
                    if (fieldVisitor != null) {
1✔
268
                        FieldAttributeAppender.ForInstrumentedField.INSTANCE.apply(fieldVisitor,
1✔
269
                                fieldDescription,
270
                                annotationValueFilterFactory.on(fieldDescription));
1✔
271
                        fieldVisitor.visitEnd();
1✔
272
                    }
273
                }
1✔
274

275
                /**
276
                 * {@inheritDoc}
277
                 */
278
                public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
279
                    throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
1✔
280
                }
281
            }
282

283
            /**
284
             * A record for a rich field with attributes and a potential default value.
285
             */
286
            @HashCodeAndEqualsPlugin.Enhance
287
            class ForExplicitField implements Record {
288

289
                /**
290
                 * The attribute appender for the field.
291
                 */
292
                private final FieldAttributeAppender attributeAppender;
293

294
                /**
295
                 * The field's default value.
296
                 */
297
                @MaybeNull
298
                @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
299
                private final Object defaultValue;
300

301
                /**
302
                 * The implemented field.
303
                 */
304
                private final FieldDescription fieldDescription;
305

306
                /**
307
                 * Creates a record for a rich field.
308
                 *
309
                 * @param attributeAppender The attribute appender for the field.
310
                 * @param defaultValue      The field's default value.
311
                 * @param fieldDescription  The implemented field.
312
                 */
313
                public ForExplicitField(FieldAttributeAppender attributeAppender,
314
                                        @MaybeNull Object defaultValue,
315
                                        FieldDescription fieldDescription) {
1✔
316
                    this.attributeAppender = attributeAppender;
1✔
317
                    this.defaultValue = defaultValue;
1✔
318
                    this.fieldDescription = fieldDescription;
1✔
319
                }
1✔
320

321
                /**
322
                 * {@inheritDoc}
323
                 */
324
                public boolean isImplicit() {
325
                    return false;
1✔
326
                }
327

328
                /**
329
                 * {@inheritDoc}
330
                 */
331
                public FieldDescription getField() {
332
                    return fieldDescription;
1✔
333
                }
334

335
                /**
336
                 * {@inheritDoc}
337
                 */
338
                public FieldAttributeAppender getFieldAppender() {
339
                    return attributeAppender;
1✔
340
                }
341

342
                /**
343
                 * {@inheritDoc}
344
                 */
345
                @MaybeNull
346
                public Object resolveDefault(@MaybeNull Object defaultValue) {
347
                    return this.defaultValue == null
1✔
348
                            ? defaultValue
349
                            : this.defaultValue;
350
                }
351

352
                /**
353
                 * {@inheritDoc}
354
                 */
355
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
356
                    FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
1✔
357
                            fieldDescription.getInternalName(),
1✔
358
                            fieldDescription.getDescriptor(),
1✔
359
                            fieldDescription.getGenericSignature(),
1✔
360
                            resolveDefault(FieldDescription.NO_DEFAULT_VALUE));
1✔
361
                    if (fieldVisitor != null) {
1✔
362
                        attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
1✔
363
                        fieldVisitor.visitEnd();
1✔
364
                    }
365
                }
1✔
366

367
                /**
368
                 * {@inheritDoc}
369
                 */
370
                public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
371
                    attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
1✔
372
                }
1✔
373
            }
374
        }
375

376
        /**
377
         * A field pool that does not allow any look ups.
378
         */
379
        enum Disabled implements FieldPool {
1✔
380

381
            /**
382
             * The singleton instance.
383
             */
384
            INSTANCE;
1✔
385

386
            /**
387
             * {@inheritDoc}
388
             */
389
            public Record target(FieldDescription fieldDescription) {
390
                throw new IllegalStateException("Cannot look up field from disabled pool");
1✔
391
            }
392
        }
393
    }
394

395
    /**
396
     * An method pool that allows a lookup for how to implement a method.
397
     */
398
    interface MethodPool {
399

400
        /**
401
         * Looks up a handler entry for a given method.
402
         *
403
         * @param methodDescription The method being processed.
404
         * @return A handler entry for the given method.
405
         */
406
        Record target(MethodDescription methodDescription);
407

408
        /**
409
         * An entry of a method pool that describes how a method is implemented.
410
         *
411
         * @see net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool
412
         */
413
        interface Record {
414

415
            /**
416
             * Returns the sort of this method instrumentation.
417
             *
418
             * @return The sort of this method instrumentation.
419
             */
420
            Sort getSort();
421

422
            /**
423
             * Returns the method that is implemented where the returned method resembles a potential transformation. An implemented
424
             * method is only defined if a method is not {@link Record.Sort#SKIPPED}.
425
             *
426
             * @return The implemented method.
427
             */
428
            MethodDescription getMethod();
429

430
            /**
431
             * The visibility to enforce for this method.
432
             *
433
             * @return The visibility to enforce for this method.
434
             */
435
            Visibility getVisibility();
436

437
            /**
438
             * Prepends the given method appender to this entry.
439
             *
440
             * @param byteCodeAppender The byte code appender to prepend.
441
             * @return This entry with the given code prepended.
442
             */
443
            Record prepend(ByteCodeAppender byteCodeAppender);
444

445
            /**
446
             * Applies this method entry. This method can always be called and might be a no-op.
447
             *
448
             * @param classVisitor                 The class visitor to which this entry should be applied.
449
             * @param implementationContext        The implementation context to which this entry should be applied.
450
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
451
             */
452
            void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
453

454
            /**
455
             * 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
456
             * {@link Record.Sort#SKIPPED}.
457
             *
458
             * @param methodVisitor The method visitor to which this entry should be applied.
459
             */
460
            void applyHead(MethodVisitor methodVisitor);
461

462
            /**
463
             * 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
464
             * entry is {@link Record.Sort#IMPLEMENTED}.
465
             *
466
             * @param methodVisitor                The method visitor to which this entry should be applied.
467
             * @param implementationContext        The implementation context to which this entry should be applied.
468
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
469
             */
470
            void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
471

472
            /**
473
             * 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
474
             * entry is {@link Record.Sort#DEFINED}.
475
             *
476
             * @param methodVisitor                The method visitor to which this entry should be applied.
477
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
478
             */
479
            void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
480

481
            /**
482
             * 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
483
             * entry is {@link Record.Sort#IMPLEMENTED}.
484
             *
485
             * @param methodVisitor         The method visitor to which this entry should be applied.
486
             * @param implementationContext The implementation context to which this entry should be applied.
487
             * @return The size requirements of the implemented code.
488
             */
489
            ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext);
490

491
            /**
492
             * The sort of an entry.
493
             */
494
            enum Sort {
1✔
495

496
                /**
497
                 * Describes a method that should not be implemented or retained in its original state.
498
                 */
499
                SKIPPED(false, false),
1✔
500

501
                /**
502
                 * Describes a method that should be defined but is abstract or native, i.e. does not define any byte code.
503
                 */
504
                DEFINED(true, false),
1✔
505

506
                /**
507
                 * Describes a method that is implemented in byte code.
508
                 */
509
                IMPLEMENTED(true, true);
1✔
510

511
                /**
512
                 * Indicates if this sort defines a method, with or without byte code.
513
                 */
514
                private final boolean define;
515

516
                /**
517
                 * Indicates if this sort defines byte code.
518
                 */
519
                private final boolean implement;
520

521
                /**
522
                 * Creates a new sort.
523
                 *
524
                 * @param define    Indicates if this sort defines a method, with or without byte code.
525
                 * @param implement Indicates if this sort defines byte code.
526
                 */
527
                Sort(boolean define, boolean implement) {
1✔
528
                    this.define = define;
1✔
529
                    this.implement = implement;
1✔
530
                }
1✔
531

532
                /**
533
                 * Indicates if this sort defines a method, with or without byte code.
534
                 *
535
                 * @return {@code true} if this sort defines a method, with or without byte code.
536
                 */
537
                public boolean isDefined() {
538
                    return define;
1✔
539
                }
540

541
                /**
542
                 * Indicates if this sort defines byte code.
543
                 *
544
                 * @return {@code true} if this sort defines byte code.
545
                 */
546
                public boolean isImplemented() {
547
                    return implement;
1✔
548
                }
549
            }
550

551
            /**
552
             * A canonical implementation of a method that is not declared but inherited by the instrumented type.
553
             */
554
            @HashCodeAndEqualsPlugin.Enhance
555
            class ForNonImplementedMethod implements Record {
556

557
                /**
558
                 * The undefined method.
559
                 */
560
                private final MethodDescription methodDescription;
561

562
                /**
563
                 * Creates a new undefined record.
564
                 *
565
                 * @param methodDescription The undefined method.
566
                 */
567
                public ForNonImplementedMethod(MethodDescription methodDescription) {
1✔
568
                    this.methodDescription = methodDescription;
1✔
569
                }
1✔
570

571
                /**
572
                 * {@inheritDoc}
573
                 */
574
                public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
575
                    /* do nothing */
576
                }
1✔
577

578
                /**
579
                 * {@inheritDoc}
580
                 */
581
                public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
582
                    throw new IllegalStateException("Cannot apply body for non-implemented method on " + methodDescription);
1✔
583
                }
584

585
                /**
586
                 * {@inheritDoc}
587
                 */
588
                public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
589
                    /* do nothing */
590
                }
1✔
591

592
                /**
593
                 * {@inheritDoc}
594
                 */
595
                public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
596
                    throw new IllegalStateException("Cannot apply code for non-implemented method on " + methodDescription);
×
597
                }
598

599
                /**
600
                 * {@inheritDoc}
601
                 */
602
                public void applyHead(MethodVisitor methodVisitor) {
603
                    throw new IllegalStateException("Cannot apply head for non-implemented method on " + methodDescription);
1✔
604
                }
605

606
                /**
607
                 * {@inheritDoc}
608
                 */
609
                public MethodDescription getMethod() {
610
                    return methodDescription;
1✔
611
                }
612

613
                /**
614
                 * {@inheritDoc}
615
                 */
616
                public Visibility getVisibility() {
617
                    return methodDescription.getVisibility();
×
618
                }
619

620
                /**
621
                 * {@inheritDoc}
622
                 */
623
                public Sort getSort() {
624
                    return Sort.SKIPPED;
1✔
625
                }
626

627
                /**
628
                 * {@inheritDoc}
629
                 */
630
                public Record prepend(ByteCodeAppender byteCodeAppender) {
631
                    return new ForDefinedMethod.WithBody(methodDescription, new ByteCodeAppender.Compound(byteCodeAppender,
1✔
632
                            new ByteCodeAppender.Simple(DefaultValue.of(methodDescription.getReturnType()), MethodReturn.of(methodDescription.getReturnType()))));
1✔
633
                }
634
            }
635

636
            /**
637
             * A base implementation of an abstract entry that defines a method.
638
             */
639
            abstract class ForDefinedMethod implements Record {
1✔
640

641
                /**
642
                 * {@inheritDoc}
643
                 */
644
                public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
645
                    MethodVisitor methodVisitor = classVisitor.visitMethod(getMethod().getActualModifiers(getSort().isImplemented(), getVisibility()),
1✔
646
                            getMethod().getInternalName(),
1✔
647
                            getMethod().getDescriptor(),
1✔
648
                            getMethod().getGenericSignature(),
1✔
649
                            getMethod().getExceptionTypes().asErasures().toInternalNames());
1✔
650
                    if (methodVisitor != null) {
1✔
651
                        ParameterList<?> parameterList = getMethod().getParameters();
1✔
652
                        if (parameterList.hasExplicitMetaData()) {
1✔
653
                            for (ParameterDescription parameterDescription : parameterList) {
1✔
654
                                methodVisitor.visitParameter(parameterDescription.getName(), parameterDescription.getModifiers());
1✔
655
                            }
1✔
656
                        }
657
                        applyHead(methodVisitor);
1✔
658
                        applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
1✔
659
                        methodVisitor.visitEnd();
1✔
660
                    }
661
                }
1✔
662

663
                /**
664
                 * Describes an entry that defines a method as byte code.
665
                 */
666
                @HashCodeAndEqualsPlugin.Enhance
667
                public static class WithBody extends ForDefinedMethod {
668

669
                    /**
670
                     * The implemented method.
671
                     */
672
                    private final MethodDescription methodDescription;
673

674
                    /**
675
                     * The byte code appender to apply.
676
                     */
677
                    private final ByteCodeAppender byteCodeAppender;
678

679
                    /**
680
                     * The method attribute appender to apply.
681
                     */
682
                    private final MethodAttributeAppender methodAttributeAppender;
683

684
                    /**
685
                     * The represented method's minimum visibility.
686
                     */
687
                    private final Visibility visibility;
688

689
                    /**
690
                     * Creates a new record for an implemented method without attributes or a modifier resolver.
691
                     *
692
                     * @param methodDescription The implemented method.
693
                     * @param byteCodeAppender  The byte code appender to apply.
694
                     */
695
                    public WithBody(MethodDescription methodDescription, ByteCodeAppender byteCodeAppender) {
696
                        this(methodDescription, byteCodeAppender, MethodAttributeAppender.NoOp.INSTANCE, methodDescription.getVisibility());
1✔
697
                    }
1✔
698

699
                    /**
700
                     * Creates a new entry for a method that defines a method as byte code.
701
                     *
702
                     * @param methodDescription       The implemented method.
703
                     * @param byteCodeAppender        The byte code appender to apply.
704
                     * @param methodAttributeAppender The method attribute appender to apply.
705
                     * @param visibility              The represented method's minimum visibility.
706
                     */
707
                    public WithBody(MethodDescription methodDescription,
708
                                    ByteCodeAppender byteCodeAppender,
709
                                    MethodAttributeAppender methodAttributeAppender,
710
                                    Visibility visibility) {
1✔
711
                        this.methodDescription = methodDescription;
1✔
712
                        this.byteCodeAppender = byteCodeAppender;
1✔
713
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
714
                        this.visibility = visibility;
1✔
715
                    }
1✔
716

717
                    /**
718
                     * {@inheritDoc}
719
                     */
720
                    public MethodDescription getMethod() {
721
                        return methodDescription;
1✔
722
                    }
723

724
                    /**
725
                     * {@inheritDoc}
726
                     */
727
                    public Sort getSort() {
728
                        return Sort.IMPLEMENTED;
1✔
729
                    }
730

731
                    /**
732
                     * {@inheritDoc}
733
                     */
734
                    public Visibility getVisibility() {
735
                        return visibility;
1✔
736
                    }
737

738
                    /**
739
                     * {@inheritDoc}
740
                     */
741
                    public void applyHead(MethodVisitor methodVisitor) {
742
                        /* do nothing */
743
                    }
1✔
744

745
                    /**
746
                     * {@inheritDoc}
747
                     */
748
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
749
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
750
                        methodVisitor.visitCode();
1✔
751
                        ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
1✔
752
                        methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
753
                    }
1✔
754

755
                    /**
756
                     * {@inheritDoc}
757
                     */
758
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
759
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
760
                    }
1✔
761

762
                    /**
763
                     * {@inheritDoc}
764
                     */
765
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
766
                        return byteCodeAppender.apply(methodVisitor, implementationContext, methodDescription);
1✔
767
                    }
768

769
                    /**
770
                     * {@inheritDoc}
771
                     */
772
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
773
                        return new WithBody(methodDescription,
1✔
774
                                new ByteCodeAppender.Compound(byteCodeAppender, this.byteCodeAppender),
775
                                methodAttributeAppender,
776
                                visibility);
777
                    }
778
                }
779

780
                /**
781
                 * Describes an entry that defines a method but without byte code and without an annotation value.
782
                 */
783
                @HashCodeAndEqualsPlugin.Enhance
784
                public static class WithoutBody extends ForDefinedMethod {
785

786
                    /**
787
                     * The implemented method.
788
                     */
789
                    private final MethodDescription methodDescription;
790

791
                    /**
792
                     * The method attribute appender to apply.
793
                     */
794
                    private final MethodAttributeAppender methodAttributeAppender;
795

796
                    /**
797
                     * The represented method's minimum visibility.
798
                     */
799
                    private final Visibility visibility;
800

801
                    /**
802
                     * Creates a new entry for a method that is defines but does not append byte code, i.e. is native or abstract.
803
                     *
804
                     * @param methodDescription       The implemented method.
805
                     * @param methodAttributeAppender The method attribute appender to apply.
806
                     * @param visibility              The represented method's minimum visibility.
807
                     */
808
                    public WithoutBody(MethodDescription methodDescription, MethodAttributeAppender methodAttributeAppender, Visibility visibility) {
1✔
809
                        this.methodDescription = methodDescription;
1✔
810
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
811
                        this.visibility = visibility;
1✔
812
                    }
1✔
813

814
                    /**
815
                     * {@inheritDoc}
816
                     */
817
                    public MethodDescription getMethod() {
818
                        return methodDescription;
1✔
819
                    }
820

821
                    /**
822
                     * {@inheritDoc}
823
                     */
824
                    public Sort getSort() {
825
                        return Sort.DEFINED;
1✔
826
                    }
827

828
                    /**
829
                     * {@inheritDoc}
830
                     */
831
                    public Visibility getVisibility() {
832
                        return visibility;
1✔
833
                    }
834

835
                    /**
836
                     * {@inheritDoc}
837
                     */
838
                    public void applyHead(MethodVisitor methodVisitor) {
839
                        /* do nothing */
840
                    }
1✔
841

842
                    /**
843
                     * {@inheritDoc}
844
                     */
845
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
846
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
847
                    }
1✔
848

849
                    /**
850
                     * {@inheritDoc}
851
                     */
852
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
853
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
854
                    }
1✔
855

856
                    /**
857
                     * {@inheritDoc}
858
                     */
859
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
860
                        throw new IllegalStateException("Cannot apply code for abstract method on " + methodDescription);
1✔
861
                    }
862

863
                    /**
864
                     * {@inheritDoc}
865
                     */
866
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
867
                        throw new IllegalStateException("Cannot prepend code for abstract method on " + methodDescription);
1✔
868
                    }
869
                }
870

871
                /**
872
                 * Describes an entry that defines a method with a default annotation value.
873
                 */
874
                @HashCodeAndEqualsPlugin.Enhance
875
                public static class WithAnnotationDefaultValue extends ForDefinedMethod {
876

877
                    /**
878
                     * The implemented method.
879
                     */
880
                    private final MethodDescription methodDescription;
881

882
                    /**
883
                     * The annotation value to define.
884
                     */
885
                    private final AnnotationValue<?, ?> annotationValue;
886

887
                    /**
888
                     * The method attribute appender to apply.
889
                     */
890
                    private final MethodAttributeAppender methodAttributeAppender;
891

892
                    /**
893
                     * Creates a new entry for defining a method with a default annotation value.
894
                     *
895
                     * @param methodDescription       The implemented method.
896
                     * @param annotationValue         The annotation value to define.
897
                     * @param methodAttributeAppender The method attribute appender to apply.
898
                     */
899
                    public WithAnnotationDefaultValue(MethodDescription methodDescription,
900
                                                      AnnotationValue<?, ?> annotationValue,
901
                                                      MethodAttributeAppender methodAttributeAppender) {
1✔
902
                        this.methodDescription = methodDescription;
1✔
903
                        this.annotationValue = annotationValue;
1✔
904
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
905
                    }
1✔
906

907
                    /**
908
                     * {@inheritDoc}
909
                     */
910
                    public MethodDescription getMethod() {
911
                        return methodDescription;
1✔
912
                    }
913

914
                    /**
915
                     * {@inheritDoc}
916
                     */
917
                    public Sort getSort() {
918
                        return Sort.DEFINED;
1✔
919
                    }
920

921
                    /**
922
                     * {@inheritDoc}
923
                     */
924
                    public Visibility getVisibility() {
925
                        return methodDescription.getVisibility();
1✔
926
                    }
927

928
                    /**
929
                     * {@inheritDoc}
930
                     */
931
                    public void applyHead(MethodVisitor methodVisitor) {
932
                        if (!methodDescription.isDefaultValue(annotationValue)) {
1✔
933
                            throw new IllegalStateException("Cannot set " + annotationValue + " as default for " + methodDescription);
1✔
934
                        }
935
                        AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
1✔
936
                        AnnotationAppender.Default.apply(annotationVisitor,
1✔
937
                                methodDescription.getReturnType().asErasure(),
1✔
938
                                AnnotationAppender.NO_NAME,
939
                                annotationValue.resolve());
1✔
940
                        annotationVisitor.visitEnd();
1✔
941
                    }
1✔
942

943
                    /**
944
                     * {@inheritDoc}
945
                     */
946
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
947
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
948
                    }
1✔
949

950
                    /**
951
                     * {@inheritDoc}
952
                     */
953
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
954
                        throw new IllegalStateException("Cannot apply attributes for default value on " + methodDescription);
1✔
955
                    }
956

957
                    /**
958
                     * {@inheritDoc}
959
                     */
960
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
961
                        throw new IllegalStateException("Cannot apply code for default value on " + methodDescription);
1✔
962
                    }
963

964
                    /**
965
                     * {@inheritDoc}
966
                     */
967
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
968
                        throw new IllegalStateException("Cannot prepend code for default value on " + methodDescription);
1✔
969
                    }
970
                }
971

972
                /**
973
                 * A record for a visibility bridge.
974
                 */
975
                @HashCodeAndEqualsPlugin.Enhance
976
                public static class OfVisibilityBridge extends ForDefinedMethod implements ByteCodeAppender {
977

978
                    /**
979
                     * The visibility bridge.
980
                     */
981
                    private final MethodDescription visibilityBridge;
982

983
                    /**
984
                     * The method the visibility bridge invokes.
985
                     */
986
                    private final MethodDescription bridgeTarget;
987

988
                    /**
989
                     * The type on which the bridge method is invoked.
990
                     */
991
                    private final TypeDescription bridgeType;
992

993
                    /**
994
                     * The attribute appender to apply to the visibility bridge.
995
                     */
996
                    private final MethodAttributeAppender attributeAppender;
997

998
                    /**
999
                     * Creates a new record for a visibility bridge.
1000
                     *
1001
                     * @param visibilityBridge  The visibility bridge.
1002
                     * @param bridgeTarget      The method the visibility bridge invokes.
1003
                     * @param bridgeType        The type of the instrumented type.
1004
                     * @param attributeAppender The attribute appender to apply to the visibility bridge.
1005
                     */
1006
                    protected OfVisibilityBridge(MethodDescription visibilityBridge,
1007
                                                 MethodDescription bridgeTarget,
1008
                                                 TypeDescription bridgeType,
1009
                                                 MethodAttributeAppender attributeAppender) {
1✔
1010
                        this.visibilityBridge = visibilityBridge;
1✔
1011
                        this.bridgeTarget = bridgeTarget;
1✔
1012
                        this.bridgeType = bridgeType;
1✔
1013
                        this.attributeAppender = attributeAppender;
1✔
1014
                    }
1✔
1015

1016
                    /**
1017
                     * Creates a record for a visibility bridge.
1018
                     *
1019
                     * @param instrumentedType  The instrumented type.
1020
                     * @param bridgeTarget      The target method of the visibility bridge.
1021
                     * @param attributeAppender The attribute appender to apply to the visibility bridge.
1022
                     * @return A record describing the visibility bridge.
1023
                     */
1024
                    public static Record of(TypeDescription instrumentedType, MethodDescription bridgeTarget, MethodAttributeAppender attributeAppender) {
1025
                        // Default method bridges must be dispatched on an implemented interface type, not considering the declaring type.
1026
                        TypeDefinition bridgeType = null;
1✔
1027
                        if (bridgeTarget.isDefaultMethod()) {
1✔
1028
                            TypeDescription declaringType = bridgeTarget.getDeclaringType().asErasure();
1✔
1029
                            for (TypeDescription interfaceType : instrumentedType.getInterfaces().asErasures().filter(isSubTypeOf(declaringType))) {
1✔
1030
                                if (bridgeType == null || declaringType.isAssignableTo(bridgeType.asErasure())) {
1✔
1031
                                    bridgeType = interfaceType;
1✔
1032
                                }
1033
                            }
1✔
1034
                        }
1035
                        // Non-default method or default method that is inherited by a super class.
1036
                        if (bridgeType == null) {
1✔
1037
                            bridgeType = instrumentedType.getSuperClass();
1✔
1038
                            if (bridgeType == null) {
1✔
1039
                                bridgeType = TypeDescription.ForLoadedType.of(Object.class);
×
1040
                            }
1041
                        }
1042
                        return new OfVisibilityBridge(new VisibilityBridge(instrumentedType, bridgeTarget),
1✔
1043
                                bridgeTarget,
1044
                                bridgeType.asErasure(),
1✔
1045
                                attributeAppender);
1046
                    }
1047

1048
                    /**
1049
                     * {@inheritDoc}
1050
                     */
1051
                    public MethodDescription getMethod() {
1052
                        return visibilityBridge;
1✔
1053
                    }
1054

1055
                    /**
1056
                     * {@inheritDoc}
1057
                     */
1058
                    public Sort getSort() {
1059
                        return Sort.IMPLEMENTED;
1✔
1060
                    }
1061

1062
                    /**
1063
                     * {@inheritDoc}
1064
                     */
1065
                    public Visibility getVisibility() {
1066
                        return bridgeTarget.getVisibility();
1✔
1067
                    }
1068

1069
                    /**
1070
                     * {@inheritDoc}
1071
                     */
1072
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
1073
                        return new ForDefinedMethod.WithBody(visibilityBridge,
1✔
1074
                                new ByteCodeAppender.Compound(this, byteCodeAppender),
1075
                                attributeAppender,
1076
                                bridgeTarget.getVisibility());
1✔
1077
                    }
1078

1079
                    /**
1080
                     * {@inheritDoc}
1081
                     */
1082
                    public void applyHead(MethodVisitor methodVisitor) {
1083
                        /* do nothing */
1084
                    }
1✔
1085

1086
                    /**
1087
                     * {@inheritDoc}
1088
                     */
1089
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1090
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
1091
                        methodVisitor.visitCode();
1✔
1092
                        ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
1✔
1093
                        methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
1094
                    }
1✔
1095

1096
                    /**
1097
                     * {@inheritDoc}
1098
                     */
1099
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1100
                        attributeAppender.apply(methodVisitor, visibilityBridge, annotationValueFilterFactory.on(visibilityBridge));
1✔
1101
                    }
1✔
1102

1103
                    /**
1104
                     * {@inheritDoc}
1105
                     */
1106
                    public Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1107
                        return apply(methodVisitor, implementationContext, visibilityBridge);
1✔
1108
                    }
1109

1110
                    /**
1111
                     * {@inheritDoc}
1112
                     */
1113
                    public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1114
                        return new ByteCodeAppender.Simple(
1✔
1115
                                MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
1✔
1116
                                MethodInvocation.invoke(bridgeTarget).special(bridgeType),
1✔
1117
                                MethodReturn.of(instrumentedMethod.getReturnType())
1✔
1118
                        ).apply(methodVisitor, implementationContext, instrumentedMethod);
1✔
1119
                    }
1120

1121
                    /**
1122
                     * A method describing a visibility bridge.
1123
                     */
1124
                    protected static class VisibilityBridge extends MethodDescription.InDefinedShape.AbstractBase {
1125

1126
                        /**
1127
                         * The instrumented type.
1128
                         */
1129
                        private final TypeDescription instrumentedType;
1130

1131
                        /**
1132
                         * The method that is the target of the bridge.
1133
                         */
1134
                        private final MethodDescription bridgeTarget;
1135

1136
                        /**
1137
                         * Creates a new visibility bridge.
1138
                         *
1139
                         * @param instrumentedType The instrumented type.
1140
                         * @param bridgeTarget     The method that is the target of the bridge.
1141
                         */
1142
                        protected VisibilityBridge(TypeDescription instrumentedType, MethodDescription bridgeTarget) {
1✔
1143
                            this.instrumentedType = instrumentedType;
1✔
1144
                            this.bridgeTarget = bridgeTarget;
1✔
1145
                        }
1✔
1146

1147
                        /**
1148
                         * {@inheritDoc}
1149
                         */
1150
                        @Nonnull
1151
                        public TypeDescription getDeclaringType() {
1152
                            return instrumentedType;
1✔
1153
                        }
1154

1155
                        /**
1156
                         * {@inheritDoc}
1157
                         */
1158
                        public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1159
                            return new ParameterList.Explicit.ForTypes(this, bridgeTarget.getParameters().asTypeList().asRawTypes());
1✔
1160
                        }
1161

1162
                        /**
1163
                         * {@inheritDoc}
1164
                         */
1165
                        public TypeDescription.Generic getReturnType() {
1166
                            return bridgeTarget.getReturnType().asRawType();
1✔
1167
                        }
1168

1169
                        /**
1170
                         * {@inheritDoc}
1171
                         */
1172
                        public TypeList.Generic getExceptionTypes() {
1173
                            return bridgeTarget.getExceptionTypes().asRawTypes();
1✔
1174
                        }
1175

1176
                        /**
1177
                         * {@inheritDoc}
1178
                         */
1179
                        @MaybeNull
1180
                        public AnnotationValue<?, ?> getDefaultValue() {
1181
                            return AnnotationValue.UNDEFINED;
×
1182
                        }
1183

1184
                        /**
1185
                         * {@inheritDoc}
1186
                         */
1187
                        public TypeList.Generic getTypeVariables() {
1188
                            return new TypeList.Generic.Empty();
1✔
1189
                        }
1190

1191
                        /**
1192
                         * {@inheritDoc}
1193
                         */
1194
                        public AnnotationList getDeclaredAnnotations() {
1195
                            return bridgeTarget.getDeclaredAnnotations();
1✔
1196
                        }
1197

1198
                        /**
1199
                         * {@inheritDoc}
1200
                         */
1201
                        public int getModifiers() {
1202
                            return (bridgeTarget.getModifiers() | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_BRIDGE) & ~Opcodes.ACC_NATIVE;
1✔
1203
                        }
1204

1205
                        /**
1206
                         * {@inheritDoc}
1207
                         */
1208
                        public String getInternalName() {
1209
                            return bridgeTarget.getName();
1✔
1210
                        }
1211
                    }
1212
                }
1213
            }
1214

1215
            /**
1216
             * A wrapper that appends accessor bridges for a method's implementation. The bridges are only added if
1217
             * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool.Record#apply(ClassVisitor, Implementation.Context, AnnotationValueFilter.Factory)}
1218
             * is invoked such that bridges are not appended for methods that are rebased or redefined as such types already have bridge methods in place.
1219
             */
1220
            @HashCodeAndEqualsPlugin.Enhance
1221
            class AccessBridgeWrapper implements Record {
1222

1223
                /**
1224
                 * The delegate for implementing the bridge's target.
1225
                 */
1226
                private final Record delegate;
1227

1228
                /**
1229
                 * The instrumented type that defines the bridge methods and the bridge target.
1230
                 */
1231
                private final TypeDescription instrumentedType;
1232

1233
                /**
1234
                 * The target of the bridge method.
1235
                 */
1236
                private final MethodDescription bridgeTarget;
1237

1238
                /**
1239
                 * A collection of all tokens representing all bridge methods.
1240
                 */
1241
                private final Set<MethodDescription.TypeToken> bridgeTypes;
1242

1243
                /**
1244
                 * The attribute appender being applied for the bridge target.
1245
                 */
1246
                private final MethodAttributeAppender attributeAppender;
1247

1248
                /**
1249
                 * Creates a wrapper for adding accessor bridges.
1250
                 *
1251
                 * @param delegate          The delegate for implementing the bridge's target.
1252
                 * @param instrumentedType  The instrumented type that defines the bridge methods and the bridge target.
1253
                 * @param bridgeTarget      The target of the bridge method.
1254
                 * @param bridgeTypes       A collection of all tokens representing all bridge methods.
1255
                 * @param attributeAppender The attribute appender being applied for the bridge target.
1256
                 */
1257
                protected AccessBridgeWrapper(Record delegate,
1258
                                              TypeDescription instrumentedType,
1259
                                              MethodDescription bridgeTarget,
1260
                                              Set<MethodDescription.TypeToken> bridgeTypes,
1261
                                              MethodAttributeAppender attributeAppender) {
1✔
1262
                    this.delegate = delegate;
1✔
1263
                    this.instrumentedType = instrumentedType;
1✔
1264
                    this.bridgeTarget = bridgeTarget;
1✔
1265
                    this.bridgeTypes = bridgeTypes;
1✔
1266
                    this.attributeAppender = attributeAppender;
1✔
1267
                }
1✔
1268

1269
                /**
1270
                 * Wraps the given record in an accessor bridge wrapper if necessary.
1271
                 *
1272
                 * @param delegate          The delegate for implementing the bridge's target.
1273
                 * @param instrumentedType  The instrumented type that defines the bridge methods and the bridge target.
1274
                 * @param bridgeTarget      The bridge methods' target methods.
1275
                 * @param bridgeTypes       A collection of all tokens representing all bridge methods.
1276
                 * @param attributeAppender The attribute appender being applied for the bridge target.
1277
                 * @return The given record wrapped by a bridge method wrapper if necessary.
1278
                 */
1279
                public static Record of(Record delegate,
1280
                                        TypeDescription instrumentedType,
1281
                                        MethodDescription bridgeTarget,
1282
                                        Set<MethodDescription.TypeToken> bridgeTypes,
1283
                                        MethodAttributeAppender attributeAppender) {
1284
                    Set<MethodDescription.TypeToken> compatibleBridgeTypes = new HashSet<MethodDescription.TypeToken>();
1✔
1285
                    for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1✔
1286
                        if (bridgeTarget.isBridgeCompatible(bridgeType)) {
1✔
1287
                            compatibleBridgeTypes.add(bridgeType);
1✔
1288
                        }
1289
                    }
1✔
1290
                    return compatibleBridgeTypes.isEmpty() || (instrumentedType.isInterface() && !delegate.getSort().isImplemented())
1✔
1291
                            ? delegate
1292
                            : new AccessBridgeWrapper(delegate, instrumentedType, bridgeTarget, compatibleBridgeTypes, attributeAppender);
1293
                }
1294

1295
                /**
1296
                 * {@inheritDoc}
1297
                 */
1298
                public Sort getSort() {
1299
                    return delegate.getSort();
1✔
1300
                }
1301

1302
                /**
1303
                 * {@inheritDoc}
1304
                 */
1305
                public MethodDescription getMethod() {
1306
                    return bridgeTarget;
×
1307
                }
1308

1309
                /**
1310
                 * {@inheritDoc}
1311
                 */
1312
                public Visibility getVisibility() {
1313
                    return delegate.getVisibility();
1✔
1314
                }
1315

1316
                /**
1317
                 * {@inheritDoc}
1318
                 */
1319
                public Record prepend(ByteCodeAppender byteCodeAppender) {
1320
                    return new AccessBridgeWrapper(delegate.prepend(byteCodeAppender), instrumentedType, bridgeTarget, bridgeTypes, attributeAppender);
1✔
1321
                }
1322

1323
                /**
1324
                 * {@inheritDoc}
1325
                 */
1326
                public void apply(ClassVisitor classVisitor,
1327
                                  Implementation.Context implementationContext,
1328
                                  AnnotationValueFilter.Factory annotationValueFilterFactory) {
1329
                    delegate.apply(classVisitor, implementationContext, annotationValueFilterFactory);
1✔
1330
                    for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1✔
1331
                        MethodDescription.InDefinedShape bridgeMethod = new AccessorBridge(bridgeTarget, bridgeType, instrumentedType);
1✔
1332
                        MethodDescription.InDefinedShape bridgeTarget = new BridgeTarget(this.bridgeTarget, instrumentedType);
1✔
1333
                        MethodVisitor methodVisitor = classVisitor.visitMethod(bridgeMethod.getActualModifiers(true, getVisibility()),
1✔
1334
                                bridgeMethod.getInternalName(),
1✔
1335
                                bridgeMethod.getDescriptor(),
1✔
1336
                                MethodDescription.NON_GENERIC_SIGNATURE,
1337
                                bridgeMethod.getExceptionTypes().asErasures().toInternalNames());
1✔
1338
                        if (methodVisitor != null) {
1✔
1339
                            attributeAppender.apply(methodVisitor, bridgeMethod, annotationValueFilterFactory.on(instrumentedType));
1✔
1340
                            methodVisitor.visitCode();
1✔
1341
                            ByteCodeAppender.Size size = new ByteCodeAppender.Simple(
1✔
1342
                                    MethodVariableAccess.allArgumentsOf(bridgeMethod).asBridgeOf(bridgeTarget).prependThisReference(),
1✔
1343
                                    MethodInvocation.invoke(bridgeTarget).virtual(instrumentedType),
1✔
1344
                                    bridgeTarget.getReturnType().asErasure().isAssignableTo(bridgeMethod.getReturnType().asErasure())
1✔
1345
                                            ? StackManipulation.Trivial.INSTANCE
1346
                                            : TypeCasting.to(bridgeMethod.getReturnType().asErasure()),
1✔
1347
                                    MethodReturn.of(bridgeMethod.getReturnType())
1✔
1348
                            ).apply(methodVisitor, implementationContext, bridgeMethod);
1✔
1349
                            methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
1350
                            methodVisitor.visitEnd();
1✔
1351
                        }
1352
                    }
1✔
1353
                }
1✔
1354

1355
                /**
1356
                 * {@inheritDoc}
1357
                 */
1358
                public void applyHead(MethodVisitor methodVisitor) {
1359
                    delegate.applyHead(methodVisitor);
1✔
1360
                }
1✔
1361

1362
                /**
1363
                 * {@inheritDoc}
1364
                 */
1365
                public void applyBody(MethodVisitor methodVisitor,
1366
                                      Implementation.Context implementationContext,
1367
                                      AnnotationValueFilter.Factory annotationValueFilterFactory) {
1368
                    delegate.applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
1✔
1369
                }
1✔
1370

1371
                /**
1372
                 * {@inheritDoc}
1373
                 */
1374
                public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1375
                    delegate.applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
1376
                }
1✔
1377

1378
                /**
1379
                 * {@inheritDoc}
1380
                 */
1381
                public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1382
                    return delegate.applyCode(methodVisitor, implementationContext);
1✔
1383
                }
1384

1385
                /**
1386
                 * A method representing an accessor bridge method.
1387
                 */
1388
                protected static class AccessorBridge extends MethodDescription.InDefinedShape.AbstractBase {
1389

1390
                    /**
1391
                     * The target method of the bridge.
1392
                     */
1393
                    private final MethodDescription bridgeTarget;
1394

1395
                    /**
1396
                     * The bridge's type token.
1397
                     */
1398
                    private final MethodDescription.TypeToken bridgeType;
1399

1400
                    /**
1401
                     * The instrumented type defining the bridge target.
1402
                     */
1403
                    private final TypeDescription instrumentedType;
1404

1405
                    /**
1406
                     * Creates a new accessor bridge method.
1407
                     *
1408
                     * @param bridgeTarget     The target method of the bridge.
1409
                     * @param bridgeType       The bridge's type token.
1410
                     * @param instrumentedType The instrumented type defining the bridge target.
1411
                     */
1412
                    protected AccessorBridge(MethodDescription bridgeTarget, TypeToken bridgeType, TypeDescription instrumentedType) {
1✔
1413
                        this.bridgeTarget = bridgeTarget;
1✔
1414
                        this.bridgeType = bridgeType;
1✔
1415
                        this.instrumentedType = instrumentedType;
1✔
1416
                    }
1✔
1417

1418
                    /**
1419
                     * {@inheritDoc}
1420
                     */
1421
                    @Nonnull
1422
                    public TypeDescription getDeclaringType() {
1423
                        return instrumentedType;
1✔
1424
                    }
1425

1426
                    /**
1427
                     * {@inheritDoc}
1428
                     */
1429
                    public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1430
                        return new ParameterList.Explicit.ForTypes(this, bridgeType.getParameterTypes());
1✔
1431
                    }
1432

1433
                    /**
1434
                     * {@inheritDoc}
1435
                     */
1436
                    public TypeDescription.Generic getReturnType() {
1437
                        return bridgeType.getReturnType().asGenericType();
1✔
1438
                    }
1439

1440
                    /**
1441
                     * {@inheritDoc}
1442
                     */
1443
                    public TypeList.Generic getExceptionTypes() {
1444
                        return bridgeTarget.getExceptionTypes().accept(TypeDescription.Generic.Visitor.TypeErasing.INSTANCE);
1✔
1445
                    }
1446

1447
                    /**
1448
                     * {@inheritDoc}
1449
                     */
1450
                    @MaybeNull
1451
                    public AnnotationValue<?, ?> getDefaultValue() {
1452
                        return AnnotationValue.UNDEFINED;
×
1453
                    }
1454

1455
                    /**
1456
                     * {@inheritDoc}
1457
                     */
1458
                    public TypeList.Generic getTypeVariables() {
1459
                        return new TypeList.Generic.Empty();
1✔
1460
                    }
1461

1462
                    /**
1463
                     * {@inheritDoc}
1464
                     */
1465
                    public AnnotationList getDeclaredAnnotations() {
1466
                        return new AnnotationList.Empty();
1✔
1467
                    }
1468

1469
                    /**
1470
                     * {@inheritDoc}
1471
                     */
1472
                    public int getModifiers() {
1473
                        return (bridgeTarget.getModifiers() | Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC) & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE);
1✔
1474
                    }
1475

1476
                    /**
1477
                     * {@inheritDoc}
1478
                     */
1479
                    public String getInternalName() {
1480
                        return bridgeTarget.getInternalName();
1✔
1481
                    }
1482
                }
1483

1484
                /**
1485
                 * A method representing a bridge's target method in its defined shape.
1486
                 */
1487
                protected static class BridgeTarget extends MethodDescription.InDefinedShape.AbstractBase {
1488

1489
                    /**
1490
                     * The target method of the bridge.
1491
                     */
1492
                    private final MethodDescription bridgeTarget;
1493

1494
                    /**
1495
                     * The instrumented type defining the bridge target.
1496
                     */
1497
                    private final TypeDescription instrumentedType;
1498

1499
                    /**
1500
                     * Creates a new bridge target.
1501
                     *
1502
                     * @param bridgeTarget     The target method of the bridge.
1503
                     * @param instrumentedType The instrumented type defining the bridge target.
1504
                     */
1505
                    protected BridgeTarget(MethodDescription bridgeTarget, TypeDescription instrumentedType) {
1✔
1506
                        this.bridgeTarget = bridgeTarget;
1✔
1507
                        this.instrumentedType = instrumentedType;
1✔
1508
                    }
1✔
1509

1510
                    /**
1511
                     * {@inheritDoc}
1512
                     */
1513
                    @Nonnull
1514
                    public TypeDescription getDeclaringType() {
1515
                        return instrumentedType;
1✔
1516
                    }
1517

1518
                    /**
1519
                     * {@inheritDoc}
1520
                     */
1521
                    public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1522
                        return new ParameterList.ForTokens(this, bridgeTarget.getParameters().asTokenList(is(instrumentedType)));
1✔
1523
                    }
1524

1525
                    /**
1526
                     * {@inheritDoc}
1527
                     */
1528
                    public TypeDescription.Generic getReturnType() {
1529
                        return bridgeTarget.getReturnType();
1✔
1530
                    }
1531

1532
                    /**
1533
                     * {@inheritDoc}
1534
                     */
1535
                    public TypeList.Generic getExceptionTypes() {
1536
                        return bridgeTarget.getExceptionTypes();
×
1537
                    }
1538

1539
                    /**
1540
                     * {@inheritDoc}
1541
                     */
1542
                    @MaybeNull
1543
                    public AnnotationValue<?, ?> getDefaultValue() {
1544
                        return bridgeTarget.getDefaultValue();
×
1545
                    }
1546

1547
                    /**
1548
                     * {@inheritDoc}
1549
                     */
1550
                    public TypeList.Generic getTypeVariables() {
1551
                        return bridgeTarget.getTypeVariables();
×
1552
                    }
1553

1554
                    /**
1555
                     * {@inheritDoc}
1556
                     */
1557
                    public AnnotationList getDeclaredAnnotations() {
1558
                        return bridgeTarget.getDeclaredAnnotations();
×
1559
                    }
1560

1561
                    /**
1562
                     * {@inheritDoc}
1563
                     */
1564
                    public int getModifiers() {
1565
                        return bridgeTarget.getModifiers();
1✔
1566
                    }
1567

1568
                    /**
1569
                     * {@inheritDoc}
1570
                     */
1571
                    public String getInternalName() {
1572
                        return bridgeTarget.getInternalName();
1✔
1573
                    }
1574
                }
1575
            }
1576
        }
1577
    }
1578

1579
    /**
1580
     * An record component pool that allows a lookup for how to implement a record component.
1581
     */
1582
    interface RecordComponentPool {
1583

1584
        /**
1585
         * Looks up a handler entry for a given record component.
1586
         *
1587
         * @param recordComponentDescription The record component being processed.
1588
         * @return A handler entry for the given record component.
1589
         */
1590
        Record target(RecordComponentDescription recordComponentDescription);
1591

1592
        /**
1593
         * An entry of a record component pool that describes how a record component is implemented.
1594
         *
1595
         * @see RecordComponentPool
1596
         */
1597
        interface Record {
1598

1599
            /**
1600
             * Determines if this record is implicit, i.e is not defined by a {@link RecordComponentPool}.
1601
             *
1602
             * @return {@code true} if this record is implicit.
1603
             */
1604
            boolean isImplicit();
1605

1606
            /**
1607
             * Returns the record component that this record represents.
1608
             *
1609
             * @return The record component that this record represents.
1610
             */
1611
            RecordComponentDescription getRecordComponent();
1612

1613
            /**
1614
             * Returns the record component attribute appender for a given record component.
1615
             *
1616
             * @return The record component appender to be applied on the given field.
1617
             */
1618
            RecordComponentAttributeAppender getRecordComponentAppender();
1619

1620
            /**
1621
             * Writes this record to a given class visitor.
1622
             *
1623
             * @param classVisitor                 The class visitor to which this record is to be written to.
1624
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
1625
             */
1626
            void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1627

1628
            /**
1629
             * Applies this record to a record component visitor. This is not possible for implicit records.
1630
             *
1631
             * @param recordComponentVisitor       The record component visitor onto which this record is to be applied.
1632
             * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
1633
             */
1634
            void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1635

1636
            /**
1637
             * A record for a simple field without a default value where all of the record component's declared annotations are appended.
1638
             */
1639
            @HashCodeAndEqualsPlugin.Enhance
1640
            class ForImplicitRecordComponent implements Record {
1641

1642
                /**
1643
                 * The implemented record component.
1644
                 */
1645
                private final RecordComponentDescription recordComponentDescription;
1646

1647
                /**
1648
                 * Creates a new record for a simple record component.
1649
                 *
1650
                 * @param recordComponentDescription The described record component.
1651
                 */
1652
                public ForImplicitRecordComponent(RecordComponentDescription recordComponentDescription) {
1✔
1653
                    this.recordComponentDescription = recordComponentDescription;
1✔
1654
                }
1✔
1655

1656
                /**
1657
                 * {@inheritDoc}
1658
                 */
1659
                public boolean isImplicit() {
1660
                    return true;
1✔
1661
                }
1662

1663
                /**
1664
                 * {@inheritDoc}
1665
                 */
1666
                public RecordComponentDescription getRecordComponent() {
1667
                    return recordComponentDescription;
×
1668
                }
1669

1670
                /**
1671
                 * {@inheritDoc}
1672
                 */
1673
                public RecordComponentAttributeAppender getRecordComponentAppender() {
1674
                    throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
×
1675
                }
1676

1677
                /**
1678
                 * {@inheritDoc}
1679
                 */
1680
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1681
                    RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1✔
1682
                            recordComponentDescription.getDescriptor(),
1✔
1683
                            recordComponentDescription.getGenericSignature());
1✔
1684
                    if (recordComponentVisitor != null) {
1✔
1685
                        RecordComponentAttributeAppender.ForInstrumentedRecordComponent.INSTANCE.apply(recordComponentVisitor,
1✔
1686
                                recordComponentDescription,
1687
                                annotationValueFilterFactory.on(recordComponentDescription));
1✔
1688
                        recordComponentVisitor.visitEnd();
1✔
1689
                    }
1690
                }
1✔
1691

1692
                /**
1693
                 * {@inheritDoc}
1694
                 */
1695
                public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1696
                    throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
1✔
1697
                }
1698
            }
1699

1700
            /**
1701
             * A record for a rich record component with attributes.
1702
             */
1703
            @HashCodeAndEqualsPlugin.Enhance
1704
            class ForExplicitRecordComponent implements Record {
1705

1706
                /**
1707
                 * The attribute appender for the record component.
1708
                 */
1709
                private final RecordComponentAttributeAppender attributeAppender;
1710

1711
                /**
1712
                 * The implemented record component.
1713
                 */
1714
                private final RecordComponentDescription recordComponentDescription;
1715

1716
                /**
1717
                 * Creates a record for a rich record component.
1718
                 *
1719
                 * @param attributeAppender          The attribute appender for the record component.
1720
                 * @param recordComponentDescription The implemented record component.
1721
                 */
1722
                public ForExplicitRecordComponent(RecordComponentAttributeAppender attributeAppender, RecordComponentDescription recordComponentDescription) {
1✔
1723
                    this.attributeAppender = attributeAppender;
1✔
1724
                    this.recordComponentDescription = recordComponentDescription;
1✔
1725
                }
1✔
1726

1727
                /**
1728
                 * {@inheritDoc}
1729
                 */
1730
                public boolean isImplicit() {
1731
                    return false;
1✔
1732
                }
1733

1734
                /**
1735
                 * {@inheritDoc}
1736
                 */
1737
                public RecordComponentDescription getRecordComponent() {
1738
                    return recordComponentDescription;
×
1739
                }
1740

1741
                /**
1742
                 * {@inheritDoc}
1743
                 */
1744
                public RecordComponentAttributeAppender getRecordComponentAppender() {
1745
                    return attributeAppender;
1✔
1746
                }
1747

1748
                /**
1749
                 * {@inheritDoc}
1750
                 */
1751
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1752
                    RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1✔
1753
                            recordComponentDescription.getDescriptor(),
1✔
1754
                            recordComponentDescription.getGenericSignature());
1✔
1755
                    if (recordComponentVisitor != null) {
1✔
1756
                        attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1✔
1757
                        recordComponentVisitor.visitEnd();
1✔
1758
                    }
1759
                }
1✔
1760

1761
                /**
1762
                 * {@inheritDoc}
1763
                 */
1764
                public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1765
                    attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1✔
1766
                }
1✔
1767
            }
1768
        }
1769

1770
        /**
1771
         * A record component pool that does not allow any look ups.
1772
         */
1773
        enum Disabled implements RecordComponentPool {
1✔
1774

1775
            /**
1776
             * The singleton instance.
1777
             */
1778
            INSTANCE;
1✔
1779

1780
            /**
1781
             * {@inheritDoc}
1782
             */
1783
            public Record target(RecordComponentDescription recordComponentDescription) {
1784
                throw new IllegalStateException("Cannot look up record component from disabled pool");
1✔
1785
            }
1786
        }
1787
    }
1788

1789
    /**
1790
     * A default implementation of a {@link net.bytebuddy.dynamic.scaffold.TypeWriter}.
1791
     *
1792
     * @param <S> The best known loaded type for the dynamically created type.
1793
     */
1794
    @HashCodeAndEqualsPlugin.Enhance
1795
    abstract class Default<S> implements TypeWriter<S> {
1796

1797
        /**
1798
         * Indicates an empty reference in a class file which is expressed by {@code null}.
1799
         */
1800
        @AlwaysNull
1801
        private static final String NO_REFERENCE = null;
1✔
1802

1803
        /**
1804
         * A folder for dumping class files or {@code null} if no dump should be generated.
1805
         */
1806
        @MaybeNull
1807
        protected static final String DUMP_FOLDER;
1808

1809
        /*
1810
         * Reads the dumping property that is set at program start up. This might cause an error because of security constraints.
1811
         */
1812
        static {
1813
            String dumpFolder;
1814
            try {
1815
                dumpFolder = doPrivileged(new GetSystemPropertyAction(DUMP_PROPERTY));
1✔
1816
            } catch (RuntimeException exception) {
×
1817
                dumpFolder = null;
×
1818
            }
1✔
1819
            DUMP_FOLDER = dumpFolder;
1✔
1820
        }
1✔
1821

1822
        /**
1823
         * The instrumented type to be created.
1824
         */
1825
        protected final TypeDescription instrumentedType;
1826

1827
        /**
1828
         * The class file specified by the user.
1829
         */
1830
        protected final ClassFileVersion classFileVersion;
1831

1832
        /**
1833
         * The field pool to use.
1834
         */
1835
        protected final FieldPool fieldPool;
1836

1837
        /**
1838
         * The record component pool to use.
1839
         */
1840
        protected final RecordComponentPool recordComponentPool;
1841

1842
        /**
1843
         * The explicit auxiliary types to add to the created type.
1844
         */
1845
        protected final List<? extends DynamicType> auxiliaryTypes;
1846

1847
        /**
1848
         * The instrumented type's declared fields.
1849
         */
1850
        protected final FieldList<FieldDescription.InDefinedShape> fields;
1851

1852
        /**
1853
         * The instrumented type's methods that are declared or inherited.
1854
         */
1855
        protected final MethodList<?> methods;
1856

1857
        /**
1858
         * The instrumented methods relevant to this type creation.
1859
         */
1860
        protected final MethodList<?> instrumentedMethods;
1861

1862
        /**
1863
         * The instrumented type's record components.
1864
         */
1865
        protected final RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents;
1866

1867
        /**
1868
         * The loaded type initializer to apply onto the created type after loading.
1869
         */
1870
        protected final LoadedTypeInitializer loadedTypeInitializer;
1871

1872
        /**
1873
         * The type initializer to include in the created type's type initializer.
1874
         */
1875
        protected final TypeInitializer typeInitializer;
1876

1877
        /**
1878
         * The type attribute appender to apply onto the instrumented type.
1879
         */
1880
        protected final TypeAttributeAppender typeAttributeAppender;
1881

1882
        /**
1883
         * The ASM visitor wrapper to apply onto the class writer.
1884
         */
1885
        protected final AsmVisitorWrapper asmVisitorWrapper;
1886

1887
        /**
1888
         * The annotation value filter factory to apply.
1889
         */
1890
        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
1891

1892
        /**
1893
         * The annotation retention to apply.
1894
         */
1895
        protected final AnnotationRetention annotationRetention;
1896

1897
        /**
1898
         * The naming strategy for auxiliary types to apply.
1899
         */
1900
        protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
1901

1902
        /**
1903
         * The implementation context factory to apply.
1904
         */
1905
        protected final Implementation.Context.Factory implementationContextFactory;
1906

1907
        /**
1908
         * Determines if a type should be explicitly validated.
1909
         */
1910
        protected final TypeValidation typeValidation;
1911

1912
        /**
1913
         * The class reader factory to use.
1914
         */
1915
        protected final AsmClassReader.Factory classReaderFactory;
1916

1917
        /**
1918
         * The class writer factory to use.
1919
         */
1920
        protected final AsmClassWriter.Factory classWriterFactory;
1921

1922
        /**
1923
         * The type pool to use for computing stack map frames, if required.
1924
         */
1925
        protected final TypePool typePool;
1926

1927
        /**
1928
         * Creates a new default type writer.
1929
         *
1930
         * @param instrumentedType             The instrumented type to be created.
1931
         * @param classFileVersion             The class file specified by the user.
1932
         * @param fieldPool                    The field pool to use.
1933
         * @param recordComponentPool          The record component pool to use.
1934
         * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
1935
         * @param fields                       The instrumented type's declared fields.
1936
         * @param methods                      The instrumented type's declared and virtually inherited methods.
1937
         * @param instrumentedMethods          The instrumented methods relevant to this type creation.
1938
         * @param recordComponents             The instrumented type's record components.
1939
         * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
1940
         * @param typeInitializer              The type initializer to include in the created type's type initializer.
1941
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
1942
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
1943
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
1944
         * @param annotationRetention          The annotation retention to apply.
1945
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
1946
         * @param implementationContextFactory The implementation context factory to apply.
1947
         * @param typeValidation               Determines if a type should be explicitly validated.
1948
         * @param classReaderFactory           The class reader factory to use.
1949
         * @param classWriterFactory           The class writer factory to use.
1950
         * @param typePool                     The type pool to use for computing stack map frames, if required.
1951
         */
1952
        protected Default(TypeDescription instrumentedType,
1953
                          ClassFileVersion classFileVersion,
1954
                          FieldPool fieldPool,
1955
                          RecordComponentPool recordComponentPool,
1956
                          List<? extends DynamicType> auxiliaryTypes,
1957
                          FieldList<FieldDescription.InDefinedShape> fields,
1958
                          MethodList<?> methods,
1959
                          MethodList<?> instrumentedMethods,
1960
                          RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
1961
                          LoadedTypeInitializer loadedTypeInitializer,
1962
                          TypeInitializer typeInitializer,
1963
                          TypeAttributeAppender typeAttributeAppender,
1964
                          AsmVisitorWrapper asmVisitorWrapper,
1965
                          AnnotationValueFilter.Factory annotationValueFilterFactory,
1966
                          AnnotationRetention annotationRetention,
1967
                          AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1968
                          Implementation.Context.Factory implementationContextFactory,
1969
                          TypeValidation typeValidation,
1970
                          AsmClassReader.Factory classReaderFactory,
1971
                          AsmClassWriter.Factory classWriterFactory,
1972
                          TypePool typePool) {
1✔
1973
            this.instrumentedType = instrumentedType;
1✔
1974
            this.classFileVersion = classFileVersion;
1✔
1975
            this.fieldPool = fieldPool;
1✔
1976
            this.recordComponentPool = recordComponentPool;
1✔
1977
            this.auxiliaryTypes = auxiliaryTypes;
1✔
1978
            this.fields = fields;
1✔
1979
            this.methods = methods;
1✔
1980
            this.instrumentedMethods = instrumentedMethods;
1✔
1981
            this.recordComponents = recordComponents;
1✔
1982
            this.loadedTypeInitializer = loadedTypeInitializer;
1✔
1983
            this.typeInitializer = typeInitializer;
1✔
1984
            this.typeAttributeAppender = typeAttributeAppender;
1✔
1985
            this.asmVisitorWrapper = asmVisitorWrapper;
1✔
1986
            this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
1✔
1987
            this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
1988
            this.annotationRetention = annotationRetention;
1✔
1989
            this.implementationContextFactory = implementationContextFactory;
1✔
1990
            this.typeValidation = typeValidation;
1✔
1991
            this.classReaderFactory = classReaderFactory;
1✔
1992
            this.classWriterFactory = classWriterFactory;
1✔
1993
            this.typePool = typePool;
1✔
1994
        }
1✔
1995

1996
        /**
1997
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
1998
         *
1999
         * @param action The action to execute from a privileged context.
2000
         * @param <T>    The type of the action's resolved value.
2001
         * @return The action's resolved value.
2002
         */
2003
        @AccessControllerPlugin.Enhance
2004
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
2005
            return action.run();
×
2006
        }
2007

2008
        /**
2009
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
2010
         *
2011
         * @param action The action to execute from a privileged context.
2012
         * @param <T>    The type of the action's resolved value.
2013
         * @return The action's resolved value.
2014
         * @throws Exception If an exception occurs.
2015
         */
2016
        @AccessControllerPlugin.Enhance
2017
        private static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws Exception {
2018
            return action.run();
×
2019
        }
2020

2021
        /**
2022
         * Creates a type writer for creating a new type.
2023
         *
2024
         * @param methodRegistry               The compiled method registry to use.
2025
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2026
         * @param fieldPool                    The field pool to use.
2027
         * @param recordComponentPool          The record component pool to use.
2028
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2029
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2030
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2031
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2032
         * @param annotationRetention          The annotation retention to apply.
2033
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2034
         * @param implementationContextFactory The implementation context factory to apply.
2035
         * @param typeValidation               Determines if a type should be explicitly validated.
2036
         * @param classReaderFactory           The class reader factory to use.
2037
         * @param classWriterFactory           The class writer factory to use.
2038
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2039
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2040
         * @return A suitable type writer.
2041
         */
2042
        public static <U> TypeWriter<U> forCreation(MethodRegistry.Compiled methodRegistry,
2043
                                                    List<? extends DynamicType> auxiliaryTypes,
2044
                                                    FieldPool fieldPool,
2045
                                                    RecordComponentPool recordComponentPool,
2046
                                                    TypeAttributeAppender typeAttributeAppender,
2047
                                                    AsmVisitorWrapper asmVisitorWrapper,
2048
                                                    ClassFileVersion classFileVersion,
2049
                                                    AnnotationValueFilter.Factory annotationValueFilterFactory,
2050
                                                    AnnotationRetention annotationRetention,
2051
                                                    AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2052
                                                    Implementation.Context.Factory implementationContextFactory,
2053
                                                    TypeValidation typeValidation,
2054
                                                    AsmClassReader.Factory classReaderFactory,
2055
                                                    AsmClassWriter.Factory classWriterFactory,
2056
                                                    TypePool typePool) {
2057
            return new ForCreation<U>(methodRegistry.getInstrumentedType(),
1✔
2058
                    classFileVersion,
2059
                    fieldPool,
2060
                    methodRegistry,
2061
                    recordComponentPool,
2062
                    auxiliaryTypes,
2063
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2064
                    methodRegistry.getMethods(),
1✔
2065
                    methodRegistry.getInstrumentedMethods(),
1✔
2066
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2067
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2068
                    methodRegistry.getTypeInitializer(),
1✔
2069
                    typeAttributeAppender,
2070
                    asmVisitorWrapper,
2071
                    annotationValueFilterFactory,
2072
                    annotationRetention,
2073
                    auxiliaryTypeNamingStrategy,
2074
                    implementationContextFactory,
2075
                    typeValidation,
2076
                    classReaderFactory,
2077
                    classWriterFactory,
2078
                    typePool);
2079
        }
2080

2081
        /**
2082
         * Creates a type writer for redefining a type.
2083
         *
2084
         * @param methodRegistry               The compiled method registry to use.
2085
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2086
         * @param fieldPool                    The field pool to use.
2087
         * @param recordComponentPool          The record component pool to use.
2088
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2089
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2090
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2091
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2092
         * @param annotationRetention          The annotation retention to apply.
2093
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2094
         * @param implementationContextFactory The implementation context factory to apply.
2095
         * @param typeValidation               Determines if a type should be explicitly validated.
2096
         * @param classReaderFactory           The class reader factory to use.
2097
         * @param classWriterFactory           The class writer factory to use.
2098
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2099
         * @param originalType                 The original type that is being redefined or rebased.
2100
         * @param classFileLocator             The class file locator for locating the original type's class file.
2101
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2102
         * @return A suitable type writer.
2103
         */
2104
        public static <U> TypeWriter<U> forRedefinition(MethodRegistry.Prepared methodRegistry,
2105
                                                        List<? extends DynamicType> auxiliaryTypes,
2106
                                                        FieldPool fieldPool,
2107
                                                        RecordComponentPool recordComponentPool,
2108
                                                        TypeAttributeAppender typeAttributeAppender,
2109
                                                        AsmVisitorWrapper asmVisitorWrapper,
2110
                                                        ClassFileVersion classFileVersion,
2111
                                                        AnnotationValueFilter.Factory annotationValueFilterFactory,
2112
                                                        AnnotationRetention annotationRetention,
2113
                                                        AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2114
                                                        Implementation.Context.Factory implementationContextFactory,
2115
                                                        TypeValidation typeValidation,
2116
                                                        AsmClassReader.Factory classReaderFactory,
2117
                                                        AsmClassWriter.Factory classWriterFactory,
2118
                                                        TypePool typePool,
2119
                                                        TypeDescription originalType,
2120
                                                        ClassFileLocator classFileLocator) {
2121
            return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
1✔
2122
                    classFileVersion,
2123
                    fieldPool,
2124
                    recordComponentPool,
2125
                    auxiliaryTypes,
2126
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2127
                    methodRegistry.getMethods(),
1✔
2128
                    methodRegistry.getInstrumentedMethods(),
1✔
2129
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2130
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2131
                    methodRegistry.getTypeInitializer(),
1✔
2132
                    typeAttributeAppender,
2133
                    asmVisitorWrapper,
2134
                    annotationValueFilterFactory,
2135
                    annotationRetention,
2136
                    auxiliaryTypeNamingStrategy,
2137
                    implementationContextFactory,
2138
                    typeValidation,
2139
                    classReaderFactory,
2140
                    classWriterFactory,
2141
                    typePool,
2142
                    originalType,
2143
                    classFileLocator,
2144
                    methodRegistry,
2145
                    SubclassImplementationTarget.Factory.LEVEL_TYPE,
2146
                    MethodRebaseResolver.Disabled.INSTANCE);
2147
        }
2148

2149
        /**
2150
         * Creates a type writer for rebasing a type.
2151
         *
2152
         * @param methodRegistry               The compiled method registry to use.
2153
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2154
         * @param fieldPool                    The field pool to use.
2155
         * @param recordComponentPool          The record component pool to use.
2156
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2157
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2158
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2159
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2160
         * @param annotationRetention          The annotation retention to apply.
2161
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2162
         * @param implementationContextFactory The implementation context factory to apply.
2163
         * @param typeValidation               Determines if a type should be explicitly validated.
2164
         * @param classReaderFactory           The class reader factory to use.
2165
         * @param classWriterFactory           The class writer factory to use.
2166
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2167
         * @param originalType                 The original type that is being redefined or rebased.
2168
         * @param classFileLocator             The class file locator for locating the original type's class file.
2169
         * @param methodRebaseResolver         The method rebase resolver to use for rebasing names.
2170
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2171
         * @return A suitable type writer.
2172
         */
2173
        public static <U> TypeWriter<U> forRebasing(MethodRegistry.Prepared methodRegistry,
2174
                                                    List<? extends DynamicType> auxiliaryTypes,
2175
                                                    FieldPool fieldPool,
2176
                                                    RecordComponentPool recordComponentPool,
2177
                                                    TypeAttributeAppender typeAttributeAppender,
2178
                                                    AsmVisitorWrapper asmVisitorWrapper,
2179
                                                    ClassFileVersion classFileVersion,
2180
                                                    AnnotationValueFilter.Factory annotationValueFilterFactory,
2181
                                                    AnnotationRetention annotationRetention,
2182
                                                    AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2183
                                                    Implementation.Context.Factory implementationContextFactory,
2184
                                                    TypeValidation typeValidation,
2185
                                                    AsmClassReader.Factory classReaderFactory,
2186
                                                    AsmClassWriter.Factory classWriterFactory,
2187
                                                    TypePool typePool,
2188
                                                    TypeDescription originalType,
2189
                                                    ClassFileLocator classFileLocator,
2190
                                                    MethodRebaseResolver methodRebaseResolver) {
2191
            return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
1✔
2192
                    classFileVersion,
2193
                    fieldPool,
2194
                    recordComponentPool,
2195
                    CompoundList.of(auxiliaryTypes, methodRebaseResolver.getAuxiliaryTypes()),
1✔
2196
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2197
                    methodRegistry.getMethods(),
1✔
2198
                    methodRegistry.getInstrumentedMethods(),
1✔
2199
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2200
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2201
                    methodRegistry.getTypeInitializer(),
1✔
2202
                    typeAttributeAppender,
2203
                    asmVisitorWrapper,
2204
                    annotationValueFilterFactory,
2205
                    annotationRetention,
2206
                    auxiliaryTypeNamingStrategy,
2207
                    implementationContextFactory,
2208
                    typeValidation,
2209
                    classReaderFactory,
2210
                    classWriterFactory,
2211
                    typePool,
2212
                    originalType,
2213
                    classFileLocator,
2214
                    methodRegistry,
2215
                    new RebaseImplementationTarget.Factory(methodRebaseResolver),
2216
                    methodRebaseResolver);
2217
        }
2218

2219
        /**
2220
         * Creates a type writer for decorating a type.
2221
         *
2222
         * @param instrumentedType             The instrumented type.
2223
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2224
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2225
         * @param methods                      The methods to instrument.
2226
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2227
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2228
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2229
         * @param annotationRetention          The annotation retention to apply.
2230
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2231
         * @param implementationContextFactory The implementation context factory to apply.
2232
         * @param typeValidation               Determines if a type should be explicitly validated.
2233
         * @param classReaderFactory           The class reader factory to use.
2234
         * @param classWriterFactory           The class writer factory to use.
2235
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2236
         * @param classFileLocator             The class file locator for locating the original type's class file.
2237
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2238
         * @return A suitable type writer.
2239
         */
2240
        public static <U> TypeWriter<U> forDecoration(TypeDescription instrumentedType,
2241
                                                      ClassFileVersion classFileVersion,
2242
                                                      List<? extends DynamicType> auxiliaryTypes,
2243
                                                      List<? extends MethodDescription> methods,
2244
                                                      TypeAttributeAppender typeAttributeAppender,
2245
                                                      AsmVisitorWrapper asmVisitorWrapper,
2246
                                                      AnnotationValueFilter.Factory annotationValueFilterFactory,
2247
                                                      AnnotationRetention annotationRetention,
2248
                                                      AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2249
                                                      Implementation.Context.Factory implementationContextFactory,
2250
                                                      TypeValidation typeValidation,
2251
                                                      AsmClassReader.Factory classReaderFactory,
2252
                                                      AsmClassWriter.Factory classWriterFactory,
2253
                                                      TypePool typePool,
2254
                                                      ClassFileLocator classFileLocator) {
2255
            return new ForInlining.WithDecorationOnly<U>(instrumentedType,
1✔
2256
                    classFileVersion,
2257
                    auxiliaryTypes,
2258
                    new MethodList.Explicit<MethodDescription>(methods),
2259
                    typeAttributeAppender,
2260
                    asmVisitorWrapper,
2261
                    annotationValueFilterFactory,
2262
                    annotationRetention,
2263
                    auxiliaryTypeNamingStrategy,
2264
                    implementationContextFactory,
2265
                    typeValidation,
2266
                    classReaderFactory,
2267
                    classWriterFactory,
2268
                    typePool,
2269
                    classFileLocator);
2270
        }
2271

2272
        /**
2273
         * {@inheritDoc}
2274
         */
2275
        @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Setting a debugging property should never change the program outcome.")
2276
        public DynamicType.Unloaded<S> make(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2277
            ClassDumpAction.Dispatcher dispatcher = DUMP_FOLDER == null
1✔
2278
                    ? ClassDumpAction.Dispatcher.Disabled.INSTANCE
2279
                    : new ClassDumpAction.Dispatcher.Enabled(DUMP_FOLDER, System.currentTimeMillis());
1✔
2280
            UnresolvedType unresolvedType = create(typeResolutionStrategy.injectedInto(typeInitializer), dispatcher);
1✔
2281
            dispatcher.dump(instrumentedType, false, unresolvedType.getBinaryRepresentation());
1✔
2282
            return unresolvedType.toDynamicType(typeResolutionStrategy);
1✔
2283
        }
2284

2285
        /**
2286
         * Creates an unresolved version of the dynamic type.
2287
         *
2288
         * @param typeInitializer The type initializer to use.
2289
         * @param dispatcher      A dispatcher for dumping class files.
2290
         * @return An unresolved type.
2291
         */
2292
        protected abstract UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher);
2293

2294
        /**
2295
         * An unresolved type.
2296
         */
2297
        @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
2298
        protected class UnresolvedType {
2299

2300
            /**
2301
             * The type's binary representation.
2302
             */
2303
            private final byte[] binaryRepresentation;
2304

2305
            /**
2306
             * A list of auxiliary types for this unresolved type.
2307
             */
2308
            private final List<? extends DynamicType> auxiliaryTypes;
2309

2310
            /**
2311
             * Creates a new unresolved type.
2312
             *
2313
             * @param binaryRepresentation The type's binary representation.
2314
             * @param auxiliaryTypes       A list of auxiliary types for this unresolved type.
2315
             */
2316
            protected UnresolvedType(byte[] binaryRepresentation, List<? extends DynamicType> auxiliaryTypes) {
1✔
2317
                this.binaryRepresentation = binaryRepresentation;
1✔
2318
                this.auxiliaryTypes = auxiliaryTypes;
1✔
2319
            }
1✔
2320

2321
            /**
2322
             * Resolves this type to a dynamic type.
2323
             *
2324
             * @param typeResolutionStrategy The type resolution strategy to apply.
2325
             * @return A dynamic type representing the inlined type.
2326
             */
2327
            protected DynamicType.Unloaded<S> toDynamicType(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2328
                return new DynamicType.Default.Unloaded<S>(instrumentedType,
1✔
2329
                        binaryRepresentation,
2330
                        loadedTypeInitializer,
2331
                        CompoundList.of(Default.this.auxiliaryTypes, auxiliaryTypes),
1✔
2332
                        typeResolutionStrategy);
2333
            }
2334

2335
            /**
2336
             * Returns the binary representation of this unresolved type.
2337
             *
2338
             * @return The binary representation of this unresolved type.
2339
             */
2340
            protected byte[] getBinaryRepresentation() {
2341
                return binaryRepresentation;
1✔
2342
            }
2343
        }
2344

2345
        /**
2346
         * A key to represent a unique signature.
2347
         */
2348
        protected static class SignatureKey {
2349

2350
            /**
2351
             * The represented internal name.
2352
             */
2353
            private final String internalName;
2354

2355
            /**
2356
             * The represented descriptor.
2357
             */
2358
            private final String descriptor;
2359

2360
            /**
2361
             * Creates a new signature key.
2362
             *
2363
             * @param internalName The represented internal name.
2364
             * @param descriptor   The represented descriptor.
2365
             */
2366
            public SignatureKey(String internalName, String descriptor) {
1✔
2367
                this.internalName = internalName;
1✔
2368
                this.descriptor = descriptor;
1✔
2369
            }
1✔
2370

2371
            @Override
2372
            public boolean equals(@MaybeNull Object other) {
2373
                if (this == other) return true;
1✔
2374
                if (other == null || getClass() != other.getClass()) return false;
1✔
2375
                SignatureKey that = (SignatureKey) other;
1✔
2376
                return internalName.equals(that.internalName) && descriptor.equals(that.descriptor);
1✔
2377
            }
2378

2379
            @Override
2380
            public int hashCode() {
2381
                return 17 + internalName.hashCode() + 31 * descriptor.hashCode();
1✔
2382
            }
2383
        }
2384

2385
        /**
2386
         * A class validator that validates that a class only defines members that are appropriate for the sort of the generated class.
2387
         */
2388
        protected static class ValidatingClassVisitor extends ClassVisitor {
2389

2390
            /**
2391
             * Indicates that a method has no method parameters.
2392
             */
2393
            private static final String NO_PARAMETERS = "()";
2394

2395
            /**
2396
             * Indicates that a method returns void.
2397
             */
2398
            private static final String RETURNS_VOID = "V";
2399

2400
            /**
2401
             * The descriptor of the {@link String} type.
2402
             */
2403
            private static final String STRING_DESCRIPTOR = "Ljava/lang/String;";
2404

2405
            /**
2406
             * Indicates that a field is ignored.
2407
             */
2408
            @AlwaysNull
2409
            private static final FieldVisitor IGNORE_FIELD = null;
1✔
2410

2411
            /**
2412
             * Indicates that a method is ignored.
2413
             */
2414
            @AlwaysNull
2415
            private static final MethodVisitor IGNORE_METHOD = null;
1✔
2416

2417
            /**
2418
             * The constraint to assert the members against. The constraint is first defined when the general class information is visited.
2419
             */
2420
            @UnknownNull
2421
            private Constraint constraint;
2422

2423
            /**
2424
             * Creates a validating class visitor.
2425
             *
2426
             * @param classVisitor The class visitor to which any calls are delegated to.
2427
             */
2428
            protected ValidatingClassVisitor(ClassVisitor classVisitor) {
2429
                super(OpenedClassReader.ASM_API, classVisitor);
1✔
2430
            }
1✔
2431

2432
            /**
2433
             * Adds a validating visitor if type validation is enabled.
2434
             *
2435
             * @param classVisitor   The original class visitor.
2436
             * @param typeValidation The type validation state.
2437
             * @return A class visitor that applies type validation if this is required.
2438
             */
2439
            protected static ClassVisitor of(ClassVisitor classVisitor, TypeValidation typeValidation) {
2440
                return typeValidation.isEnabled()
1✔
2441
                        ? new ValidatingClassVisitor(classVisitor)
2442
                        : classVisitor;
2443
            }
2444

2445
            @Override
2446
            public void visit(int version, int modifiers, String name, @MaybeNull String signature, @MaybeNull String superName, @MaybeNull String[] interfaceInternalName) {
2447
                ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(version);
1✔
2448
                List<Constraint> constraints = new ArrayList<Constraint>();
1✔
2449
                constraints.add(new Constraint.ForClassFileVersion(classFileVersion));
1✔
2450
                if (name.equals(ModuleDescription.MODULE_CLASS_NAME)) {
1✔
2451
                    constraints.add(Constraint.ForModuleType.INSTANCE);
1✔
2452
                } else if (name.endsWith('/' + PackageDescription.PACKAGE_CLASS_NAME)) {
1✔
2453
                    constraints.add(Constraint.ForPackageType.INSTANCE);
1✔
2454
                } else if ((modifiers & Opcodes.ACC_ANNOTATION) != 0) {
1✔
2455
                    if (!classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
1✔
2456
                        throw new IllegalStateException("Cannot define an annotation type for class file version " + classFileVersion);
1✔
2457
                    }
2458
                    constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
1✔
2459
                            ? Constraint.ForAnnotation.JAVA_8
2460
                            : Constraint.ForAnnotation.CLASSIC);
2461
                } else if ((modifiers & Opcodes.ACC_INTERFACE) != 0) {
1✔
2462
                    constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
1✔
2463
                            ? Constraint.ForInterface.JAVA_8
2464
                            : Constraint.ForInterface.CLASSIC);
2465
                } else if ((modifiers & Opcodes.ACC_ABSTRACT) != 0) {
1✔
2466
                    constraints.add(Constraint.ForClass.ABSTRACT);
1✔
2467
                } else {
2468
                    constraints.add(Constraint.ForClass.MANIFEST);
1✔
2469
                }
2470
                boolean record;
2471
                if ((modifiers & Opcodes.ACC_RECORD) != 0) {
1✔
2472
                    constraints.add(Constraint.ForRecord.INSTANCE);
1✔
2473
                    record = true;
1✔
2474
                } else {
2475
                    record = false;
1✔
2476
                }
2477
                constraint = new Constraint.Compound(constraints);
1✔
2478
                constraint.assertType(modifiers,
1✔
2479
                        superName,
2480
                        interfaceInternalName != null,
2481
                        signature != null);
2482
                if (record) {
1✔
2483
                    constraint.assertRecord();
×
2484
                }
2485
                super.visit(version, modifiers, name, signature, superName, interfaceInternalName);
1✔
2486
            }
1✔
2487

2488
            @Override
2489
            public void visitPermittedSubclass(String permittedSubclass) {
2490
                constraint.assertPermittedSubclass();
×
2491
                super.visitPermittedSubclass(permittedSubclass);
×
2492
            }
×
2493

2494
            @Override
2495
            @MaybeNull
2496
            public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
2497
                constraint.assertAnnotation();
1✔
2498
                return super.visitAnnotation(descriptor, visible);
1✔
2499
            }
2500

2501
            @Override
2502
            @MaybeNull
2503
            public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
2504
                constraint.assertTypeAnnotation();
1✔
2505
                return super.visitTypeAnnotation(typeReference, typePath, descriptor, visible);
1✔
2506
            }
2507

2508
            @Override
2509
            public void visitNestHost(String nestHost) {
2510
                constraint.assertNestMate();
×
2511
                super.visitNestHost(nestHost);
×
2512
            }
×
2513

2514
            @Override
2515
            public void visitNestMember(String nestMember) {
2516
                constraint.assertNestMate();
×
2517
                super.visitNestMember(nestMember);
×
2518
            }
×
2519

2520
            @Override
2521
            @MaybeNull
2522
            public FieldVisitor visitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
2523
                if (value != null) {
1✔
2524
                    Class<?> type;
2525
                    switch (descriptor.charAt(0)) {
1✔
2526
                        case 'Z':
2527
                        case 'B':
2528
                        case 'C':
2529
                        case 'S':
2530
                        case 'I':
2531
                            type = Integer.class;
1✔
2532
                            break;
1✔
2533
                        case 'J':
2534
                            type = Long.class;
1✔
2535
                            break;
1✔
2536
                        case 'F':
2537
                            type = Float.class;
1✔
2538
                            break;
1✔
2539
                        case 'D':
2540
                            type = Double.class;
1✔
2541
                            break;
1✔
2542
                        default:
2543
                            if (!descriptor.equals(STRING_DESCRIPTOR)) {
1✔
2544
                                throw new IllegalStateException("Cannot define a default value for type of field " + name);
1✔
2545
                            }
2546
                            type = String.class;
1✔
2547
                    }
2548
                    if (!type.isInstance(value)) {
1✔
2549
                        throw new IllegalStateException("Field " + name + " defines an incompatible default value " + value + " (" + value.getClass().getName() + ")");
1✔
2550
                    } else if (type == Integer.class) {
1✔
2551
                        boolean outOfRange;
2552
                        switch (descriptor.charAt(0)) {
1✔
2553
                            case 'Z':
2554
                                outOfRange = (Integer) value < 0 || (Integer) value > 1;
1✔
2555
                                break;
1✔
2556
                            case 'B':
2557
                                outOfRange = (Integer) value < Byte.MIN_VALUE || (Integer) value > Byte.MAX_VALUE;
1✔
2558
                                break;
1✔
2559
                            case 'S':
2560
                                outOfRange = (Integer) value < Short.MIN_VALUE || (Integer) value > Short.MAX_VALUE;
1✔
2561
                                break;
1✔
2562
                            case 'C':
2563
                                outOfRange = (Integer) value < Character.MIN_VALUE || (Integer) value > Character.MAX_VALUE;
1✔
2564
                                break;
1✔
2565
                            default:
2566
                                outOfRange = false;
1✔
2567
                        }
2568
                        if (outOfRange) {
1✔
2569
                            throw new IllegalStateException("Field " + name + " defines an incompatible default value " + value);
1✔
2570
                        }
2571
                    }
2572
                }
2573
                constraint.assertField(name,
1✔
2574
                        (modifiers & Opcodes.ACC_PUBLIC) != 0,
2575
                        (modifiers & Opcodes.ACC_STATIC) != 0,
2576
                        (modifiers & Opcodes.ACC_FINAL) != 0,
2577
                        signature != null);
2578
                FieldVisitor fieldVisitor = super.visitField(modifiers, name, descriptor, signature, value);
1✔
2579
                return fieldVisitor == null
1✔
2580
                        ? IGNORE_FIELD
2581
                        : new ValidatingFieldVisitor(fieldVisitor);
2582
            }
2583

2584
            @Override
2585
            @MaybeNull
2586
            public MethodVisitor visitMethod(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull String[] exceptionInternalName) {
2587
                constraint.assertMethod(name,
1✔
2588
                        (modifiers & Opcodes.ACC_ABSTRACT) != 0,
2589
                        (modifiers & Opcodes.ACC_PUBLIC) != 0,
2590
                        (modifiers & Opcodes.ACC_PRIVATE) != 0,
2591
                        (modifiers & Opcodes.ACC_STATIC) != 0,
2592
                        !name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME)
1✔
2593
                                && !name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)
1✔
2594
                                && (modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)) == 0,
2595
                        name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME),
1✔
2596
                        !descriptor.startsWith(NO_PARAMETERS) || descriptor.endsWith(RETURNS_VOID),
1✔
2597
                        signature != null);
2598
                MethodVisitor methodVisitor = super.visitMethod(modifiers, name, descriptor, signature, exceptionInternalName);
1✔
2599
                return methodVisitor == null
1✔
2600
                        ? IGNORE_METHOD
2601
                        : new ValidatingMethodVisitor(methodVisitor, name);
2602
            }
2603

2604
            /**
2605
             * A constraint for members that are legal for a given type.
2606
             */
2607
            protected interface Constraint {
2608

2609
                /**
2610
                 * Asserts if the type can legally represent a package description.
2611
                 *
2612
                 * @param modifier               The modifier that is to be written to the type.
2613
                 * @param superClassInternalName The internal name of the super class or {@code null} if none.
2614
                 * @param definesInterfaces      {@code true} if this type implements at least one interface.
2615
                 * @param isGeneric              {@code true} if this type defines a generic type signature.
2616
                 */
2617
                void assertType(int modifier, @MaybeNull String superClassInternalName, boolean definesInterfaces, boolean isGeneric);
2618

2619
                /**
2620
                 * Asserts a field for being valid.
2621
                 *
2622
                 * @param name      The name of the field.
2623
                 * @param isPublic  {@code true} if this field is public.
2624
                 * @param isStatic  {@code true} if this field is static.
2625
                 * @param isFinal   {@code true} if this field is final.
2626
                 * @param isGeneric {@code true} if this field defines a generic signature.
2627
                 */
2628
                void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric);
2629

2630
                /**
2631
                 * Asserts a method for being valid.
2632
                 *
2633
                 * @param name                       The name of the method.
2634
                 * @param isAbstract                 {@code true} if the method is abstract.
2635
                 * @param isPublic                   {@code true} if this method is public.
2636
                 * @param isPrivate                  {@code true} if this method is private.
2637
                 * @param isStatic                   {@code true} if this method is static.
2638
                 * @param isVirtual                  {@code true} if this method is virtual.
2639
                 * @param isConstructor              {@code true} if this method is a constructor.
2640
                 * @param isDefaultValueIncompatible {@code true} if a method's signature cannot describe an annotation property method.
2641
                 * @param isGeneric                  {@code true} if this method defines a generic signature.
2642
                 */
2643
                void assertMethod(String name,
2644
                                  boolean isAbstract,
2645
                                  boolean isPublic,
2646
                                  boolean isPrivate,
2647
                                  boolean isStatic,
2648
                                  boolean isVirtual,
2649
                                  boolean isConstructor,
2650
                                  boolean isDefaultValueIncompatible,
2651
                                  boolean isGeneric);
2652

2653
                /**
2654
                 * Asserts the legitimacy of an annotation for the instrumented type.
2655
                 */
2656
                void assertAnnotation();
2657

2658
                /**
2659
                 * Asserts the legitimacy of a type annotation for the instrumented type.
2660
                 */
2661
                void assertTypeAnnotation();
2662

2663
                /**
2664
                 * Asserts if a default value is legal for a method.
2665
                 *
2666
                 * @param name The name of the method.
2667
                 */
2668
                void assertDefaultValue(String name);
2669

2670
                /**
2671
                 * Asserts if it is legal to invoke a default method from a type.
2672
                 */
2673
                void assertDefaultMethodCall();
2674

2675
                /**
2676
                 * Asserts the capability to store a type constant in the class's constant pool.
2677
                 */
2678
                void assertTypeInConstantPool();
2679

2680
                /**
2681
                 * Asserts the capability to store a method type constant in the class's constant pool.
2682
                 */
2683
                void assertMethodTypeInConstantPool();
2684

2685
                /**
2686
                 * Asserts the capability to store a method handle in the class's constant pool.
2687
                 */
2688
                void assertHandleInConstantPool();
2689

2690
                /**
2691
                 * Asserts the capability to invoke a method dynamically.
2692
                 */
2693
                void assertInvokeDynamic();
2694

2695
                /**
2696
                 * Asserts the capability of executing a subroutine.
2697
                 */
2698
                void assertSubRoutine();
2699

2700
                /**
2701
                 * Asserts the capability of storing a dynamic value in the constant pool.
2702
                 */
2703
                void assertDynamicValueInConstantPool();
2704

2705
                /**
2706
                 * Asserts the capability of storing nest mate information.
2707
                 */
2708
                void assertNestMate();
2709

2710
                /**
2711
                 * Asserts the presence of a record component.
2712
                 */
2713
                void assertRecord();
2714

2715
                /**
2716
                 * Asserts the presence of a permitted subclass.
2717
                 */
2718
                void assertPermittedSubclass();
2719

2720
                /**
2721
                 * Represents the constraint of a class type.
2722
                 */
2723
                enum ForClass implements Constraint {
1✔
2724

2725
                    /**
2726
                     * Represents the constraints of a non-abstract class.
2727
                     */
2728
                    MANIFEST(true),
1✔
2729

2730
                    /**
2731
                     * Represents the constraints of an abstract class.
2732
                     */
2733
                    ABSTRACT(false);
1✔
2734

2735
                    /**
2736
                     * {@code true} if this instance represents the constraints a non-abstract class.
2737
                     */
2738
                    private final boolean manifestType;
2739

2740
                    /**
2741
                     * Creates a new constraint for a class.
2742
                     *
2743
                     * @param manifestType {@code true} if this instance represents a non-abstract class.
2744
                     */
2745
                    ForClass(boolean manifestType) {
1✔
2746
                        this.manifestType = manifestType;
1✔
2747
                    }
1✔
2748

2749
                    /**
2750
                     * {@inheritDoc}
2751
                     */
2752
                    public void assertType(int modifier, @MaybeNull String superClassInternalName, boolean definesInterfaces, boolean isGeneric) {
2753
                        /* do nothing */
2754
                    }
1✔
2755

2756
                    /**
2757
                     * {@inheritDoc}
2758
                     */
2759
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2760
                        /* do nothing */
2761
                    }
1✔
2762

2763
                    /**
2764
                     * {@inheritDoc}
2765
                     */
2766
                    public void assertMethod(String name,
2767
                                             boolean isAbstract,
2768
                                             boolean isPublic,
2769
                                             boolean isPrivate,
2770
                                             boolean isStatic,
2771
                                             boolean isVirtual,
2772
                                             boolean isConstructor,
2773
                                             boolean isDefaultValueIncompatible,
2774
                                             boolean isGeneric) {
2775
                        if (isAbstract && manifestType) {
1✔
2776
                            throw new IllegalStateException("Cannot define abstract method '" + name + "' for non-abstract class");
1✔
2777
                        }
2778
                    }
1✔
2779

2780
                    /**
2781
                     * {@inheritDoc}
2782
                     */
2783
                    public void assertAnnotation() {
2784
                        /* do nothing */
2785
                    }
1✔
2786

2787
                    /**
2788
                     * {@inheritDoc}
2789
                     */
2790
                    public void assertTypeAnnotation() {
2791
                        /* do nothing */
2792
                    }
1✔
2793

2794
                    /**
2795
                     * {@inheritDoc}
2796
                     */
2797
                    public void assertDefaultValue(String name) {
2798
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
1✔
2799
                    }
2800

2801
                    /**
2802
                     * {@inheritDoc}
2803
                     */
2804
                    public void assertDefaultMethodCall() {
2805
                        /* do nothing */
2806
                    }
1✔
2807

2808
                    /**
2809
                     * {@inheritDoc}
2810
                     */
2811
                    public void assertTypeInConstantPool() {
2812
                        /* do nothing */
2813
                    }
1✔
2814

2815
                    /**
2816
                     * {@inheritDoc}
2817
                     */
2818
                    public void assertMethodTypeInConstantPool() {
2819
                        /* do nothing */
2820
                    }
1✔
2821

2822
                    /**
2823
                     * {@inheritDoc}
2824
                     */
2825
                    public void assertHandleInConstantPool() {
2826
                        /* do nothing */
2827
                    }
1✔
2828

2829
                    /**
2830
                     * {@inheritDoc}
2831
                     */
2832
                    public void assertInvokeDynamic() {
2833
                        /* do nothing */
2834
                    }
1✔
2835

2836
                    /**
2837
                     * {@inheritDoc}
2838
                     */
2839
                    public void assertSubRoutine() {
2840
                        /* do nothing */
2841
                    }
1✔
2842

2843
                    /**
2844
                     * {@inheritDoc}
2845
                     */
2846
                    public void assertDynamicValueInConstantPool() {
2847
                        /* do nothing */
2848
                    }
×
2849

2850
                    /**
2851
                     * {@inheritDoc}
2852
                     */
2853
                    public void assertNestMate() {
2854
                        /* do nothing */
2855
                    }
×
2856

2857
                    /**
2858
                     * {@inheritDoc}
2859
                     */
2860
                    public void assertRecord() {
2861
                        /* do nothing */
2862
                    }
×
2863

2864
                    /**
2865
                     * {@inheritDoc}
2866
                     */
2867
                    public void assertPermittedSubclass() {
2868
                        /* do nothing */
2869
                    }
×
2870
                }
2871

2872
                /**
2873
                 * Represents the constraint of a module type.
2874
                 */
2875
                enum ForModuleType implements Constraint {
1✔
2876

2877
                    /**
2878
                     * The singleton instance.
2879
                     */
2880
                    INSTANCE;
1✔
2881

2882
                    /**
2883
                     * {@inheritDoc}
2884
                     */
2885
                    public void assertType(int modifier, String superClassInternalName, boolean definesInterfaces, boolean isGeneric) {
2886
                        if (modifier != Opcodes.ACC_MODULE) {
1✔
2887
                            throw new IllegalStateException("Module must only define module modifier");
×
2888
                        } else if (superClassInternalName != null) {
1✔
2889
                            throw new IllegalStateException("A module cannot define a super class");
×
2890
                        }
2891
                    }
1✔
2892

2893
                    /**
2894
                     * {@inheritDoc}
2895
                     */
2896
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2897
                        throw new IllegalStateException("Cannot define a field for a module description type");
×
2898
                    }
2899

2900
                    /**
2901
                     * {@inheritDoc}
2902
                     */
2903
                    public void assertMethod(String name, boolean isAbstract, boolean isPublic, boolean isPrivate, boolean isStatic, boolean isVirtual, boolean isConstructor, boolean isDefaultValueIncompatible, boolean isGeneric) {
2904
                        throw new IllegalStateException("Cannot define a method for a module description type");
×
2905
                    }
2906

2907
                    /**
2908
                     * {@inheritDoc}
2909
                     */
2910
                    public void assertAnnotation() {
2911
                    }
×
2912

2913
                    /**
2914
                     * {@inheritDoc}
2915
                     */
2916
                    public void assertTypeAnnotation() {
2917
                        throw new IllegalStateException("Cannot define a type annotation for a module description type");
×
2918
                    }
2919

2920
                    /**
2921
                     * {@inheritDoc}
2922
                     */
2923
                    public void assertDefaultValue(String name) {
2924
                    }
×
2925

2926
                    /**
2927
                     * {@inheritDoc}
2928
                     */
2929
                    public void assertDefaultMethodCall() {
2930
                    }
×
2931

2932
                    /**
2933
                     * {@inheritDoc}
2934
                     */
2935
                    public void assertTypeInConstantPool() {
2936
                    }
×
2937

2938
                    /**
2939
                     * {@inheritDoc}
2940
                     */
2941
                    public void assertMethodTypeInConstantPool() {
2942
                    }
×
2943

2944
                    /**
2945
                     * {@inheritDoc}
2946
                     */
2947
                    public void assertHandleInConstantPool() {
2948
                    }
×
2949

2950
                    /**
2951
                     * {@inheritDoc}
2952
                     */
2953
                    public void assertInvokeDynamic() {
2954
                    }
×
2955

2956
                    /**
2957
                     * {@inheritDoc}
2958
                     */
2959
                    public void assertSubRoutine() {
2960
                    }
×
2961

2962
                    /**
2963
                     * {@inheritDoc}
2964
                     */
2965
                    public void assertDynamicValueInConstantPool() {
2966
                    }
×
2967

2968
                    /**
2969
                     * {@inheritDoc}
2970
                     */
2971
                    public void assertNestMate() {
2972
                        throw new IllegalStateException("Cannot define a nest mate for a module description type");
×
2973
                    }
2974

2975
                    /**
2976
                     * {@inheritDoc}
2977
                     */
2978
                    public void assertRecord() {
2979
                        throw new IllegalStateException("Cannot define a record entry for a module description type");
×
2980
                    }
2981

2982
                    /**
2983
                     * {@inheritDoc}
2984
                     */
2985
                    public void assertPermittedSubclass() {
2986
                        throw new IllegalStateException("Cannot permitt a subclass for a module description type");
×
2987
                    }
2988
                }
2989

2990
                /**
2991
                 * Represents the constraint of a package type.
2992
                 */
2993
                enum ForPackageType implements Constraint {
1✔
2994

2995
                    /**
2996
                     * The singleton instance.
2997
                     */
2998
                    INSTANCE;
1✔
2999

3000
                    /**
3001
                     * {@inheritDoc}
3002
                     */
3003
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3004
                        throw new IllegalStateException("Cannot define a field for a package description type");
1✔
3005
                    }
3006

3007
                    /**
3008
                     * {@inheritDoc}
3009
                     */
3010
                    public void assertMethod(String name,
3011
                                             boolean isAbstract,
3012
                                             boolean isPublic,
3013
                                             boolean isPrivate,
3014
                                             boolean isStatic,
3015
                                             boolean isVirtual,
3016
                                             boolean isConstructor,
3017
                                             boolean isNoDefaultValue,
3018
                                             boolean isGeneric) {
3019
                        throw new IllegalStateException("Cannot define a method for a package description type");
×
3020
                    }
3021

3022
                    /**
3023
                     * {@inheritDoc}
3024
                     */
3025
                    public void assertAnnotation() {
3026
                        /* do nothing */
3027
                    }
1✔
3028

3029
                    /**
3030
                     * {@inheritDoc}
3031
                     */
3032
                    public void assertTypeAnnotation() {
3033
                        /* do nothing */
3034
                    }
×
3035

3036
                    /**
3037
                     * {@inheritDoc}
3038
                     */
3039
                    public void assertDefaultValue(String name) {
3040
                        /* do nothing, implicit by forbidding methods */
3041
                    }
×
3042

3043
                    /**
3044
                     * {@inheritDoc}
3045
                     */
3046
                    public void assertDefaultMethodCall() {
3047
                        /* do nothing */
3048
                    }
×
3049

3050
                    /**
3051
                     * {@inheritDoc}
3052
                     */
3053
                    public void assertTypeInConstantPool() {
3054
                        /* do nothing */
3055
                    }
×
3056

3057
                    /**
3058
                     * {@inheritDoc}
3059
                     */
3060
                    public void assertMethodTypeInConstantPool() {
3061
                        /* do nothing */
3062
                    }
×
3063

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

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

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

3085
                    /**
3086
                     * {@inheritDoc}
3087
                     */
3088
                    public void assertType(int modifier, @MaybeNull String superClassInternalName, boolean definesInterfaces, boolean isGeneric) {
3089
                        if (modifier != PackageDescription.PACKAGE_MODIFIERS) {
1✔
3090
                            throw new IllegalStateException("A package description type must define " + PackageDescription.PACKAGE_MODIFIERS + " as modifier");
×
3091
                        } else if (!Type.getInternalName(Object.class).equals(superClassInternalName)) {
1✔
3092
                            throw new IllegalStateException("A package class must inherit from java.lang.Object");
×
3093
                        } else if (definesInterfaces) {
1✔
3094
                            throw new IllegalStateException("Cannot implement interface for package type");
1✔
3095
                        }
3096
                    }
1✔
3097

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

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

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

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

3127
                /**
3128
                 * Represents the constraint of an interface type.
3129
                 */
3130
                enum ForInterface implements Constraint {
1✔
3131

3132
                    /**
3133
                     * An interface type with the constraints for the Java versions 5 to 7.
3134
                     */
3135
                    CLASSIC(true),
1✔
3136

3137
                    /**
3138
                     * An interface type with the constraints for the Java versions 8+.
3139
                     */
3140
                    JAVA_8(false);
1✔
3141

3142
                    /**
3143
                     * {@code true} if this instance represents a classic interface type (pre Java 8).
3144
                     */
3145
                    private final boolean classic;
3146

3147
                    /**
3148
                     * Creates a constraint for an interface type.
3149
                     *
3150
                     * @param classic {@code true} if this instance represents a classic interface (pre Java 8).
3151
                     */
3152
                    ForInterface(boolean classic) {
1✔
3153
                        this.classic = classic;
1✔
3154
                    }
1✔
3155

3156
                    /**
3157
                     * {@inheritDoc}
3158
                     */
3159
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3160
                        if (!isStatic || !isPublic || !isFinal) {
1✔
3161
                            throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
1✔
3162
                        }
3163
                    }
1✔
3164

3165
                    /**
3166
                     * {@inheritDoc}
3167
                     */
3168
                    public void assertMethod(String name,
3169
                                             boolean isAbstract,
3170
                                             boolean isPublic,
3171
                                             boolean isPrivate,
3172
                                             boolean isStatic,
3173
                                             boolean isVirtual,
3174
                                             boolean isConstructor,
3175
                                             boolean isDefaultValueIncompatible,
3176
                                             boolean isGeneric) {
3177
                        if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
3178
                            if (isConstructor) {
1✔
3179
                                throw new IllegalStateException("Cannot define constructor for interface type");
1✔
3180
                            } else if (classic && !isPublic) {
1✔
3181
                                throw new IllegalStateException("Cannot define non-public method '" + name + "' for interface type");
×
3182
                            } else if (classic && !isVirtual) {
1✔
3183
                                throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 interface type");
×
3184
                            } else if (classic && !isAbstract) {
1✔
3185
                                throw new IllegalStateException("Cannot define default method '" + name + "' for pre-Java 8 interface type");
×
3186
                            }
3187
                        }
3188
                    }
1✔
3189

3190
                    /**
3191
                     * {@inheritDoc}
3192
                     */
3193
                    public void assertAnnotation() {
3194
                        /* do nothing */
3195
                    }
1✔
3196

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

3204
                    /**
3205
                     * {@inheritDoc}
3206
                     */
3207
                    public void assertDefaultValue(String name) {
3208
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
×
3209
                    }
3210

3211
                    /**
3212
                     * {@inheritDoc}
3213
                     */
3214
                    public void assertDefaultMethodCall() {
3215
                        /* do nothing */
3216
                    }
1✔
3217

3218
                    /**
3219
                     * {@inheritDoc}
3220
                     */
3221
                    public void assertType(int modifier, @MaybeNull String superClassInternalName, boolean definesInterfaces, boolean isGeneric) {
3222
                        if (!Type.getInternalName(Object.class).equals(superClassInternalName)) {
1✔
3223
                            throw new IllegalStateException("An interface must inherit from java.lang.Object");
×
3224
                        }
3225
                    }
1✔
3226

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

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

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

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

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

3262
                    /**
3263
                     * {@inheritDoc}
3264
                     */
3265
                    public void assertDynamicValueInConstantPool() {
3266
                        /* do nothing */
3267
                    }
×
3268

3269
                    /**
3270
                     * {@inheritDoc}
3271
                     */
3272
                    public void assertNestMate() {
3273
                        /* do nothing */
3274
                    }
×
3275

3276
                    /**
3277
                     * {@inheritDoc}
3278
                     */
3279
                    public void assertRecord() {
3280
                        /* do nothing */
3281
                    }
×
3282

3283
                    /**
3284
                     * {@inheritDoc}
3285
                     */
3286
                    public void assertPermittedSubclass() {
3287
                        /* do nothing */
3288
                    }
×
3289
                }
3290

3291
                /**
3292
                 * Represents the constraint of a record type.
3293
                 */
3294
                enum ForRecord implements Constraint {
1✔
3295

3296
                    /**
3297
                     * The singleton instance.
3298
                     */
3299
                    INSTANCE;
1✔
3300

3301
                    /**
3302
                     * {@inheritDoc}
3303
                     */
3304
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3305
                        /* do nothing */
3306
                    }
×
3307

3308
                    /**
3309
                     * {@inheritDoc}
3310
                     */
3311
                    public void assertMethod(String name,
3312
                                             boolean isAbstract,
3313
                                             boolean isPublic,
3314
                                             boolean isPrivate,
3315
                                             boolean isStatic,
3316
                                             boolean isVirtual,
3317
                                             boolean isConstructor,
3318
                                             boolean isDefaultValueIncompatible,
3319
                                             boolean isGeneric) {
3320
                        /* do nothing */
3321
                    }
×
3322

3323
                    /**
3324
                     * {@inheritDoc}
3325
                     */
3326
                    public void assertAnnotation() {
3327
                        /* do nothing */
3328
                    }
×
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
                    }
×
3343

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

3351
                    /**
3352
                     * {@inheritDoc}
3353
                     */
3354
                    public void assertType(int modifier, @MaybeNull String superClassInternalName, boolean definesInterfaces, boolean isGeneric) {
3355
                        if ((modifier & Opcodes.ACC_ABSTRACT) != 0) {
1✔
3356
                            throw new IllegalStateException("Cannot define a record class as abstract");
×
3357
                        } else if (!"java/lang/Record".equals(superClassInternalName)) {
1✔
3358
                            throw new IllegalStateException("A record must inherit from java.lang.Record");
×
3359
                        }
3360
                    }
1✔
3361

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

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

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

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

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

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

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

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

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

3426
                /**
3427
                 * Represents the constraint of an annotation type.
3428
                 */
3429
                enum ForAnnotation implements Constraint {
1✔
3430

3431
                    /**
3432
                     * An annotation type with the constraints for the Java versions 5 to 7.
3433
                     */
3434
                    CLASSIC(true),
1✔
3435

3436
                    /**
3437
                     * An annotation type with the constraints for the Java versions 8+.
3438
                     */
3439
                    JAVA_8(false);
1✔
3440

3441
                    /**
3442
                     * {@code true} if this instance represents a classic annotation type (pre Java 8).
3443
                     */
3444
                    private final boolean classic;
3445

3446
                    /**
3447
                     * Creates a constraint for an annotation type.
3448
                     *
3449
                     * @param classic {@code true} if this instance represents a classic annotation type (pre Java 8).
3450
                     */
3451
                    ForAnnotation(boolean classic) {
1✔
3452
                        this.classic = classic;
1✔
3453
                    }
1✔
3454

3455
                    /**
3456
                     * {@inheritDoc}
3457
                     */
3458
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3459
                        if (!isStatic || !isPublic || !isFinal) {
1✔
3460
                            throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
1✔
3461
                        }
3462
                    }
×
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 (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
3477
                            if (isConstructor) {
1✔
3478
                                throw new IllegalStateException("Cannot define constructor for interface type");
1✔
3479
                            } else if (classic && !isVirtual) {
1✔
3480
                                throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 annotation type");
1✔
3481
                            } else if (!isStatic && isDefaultValueIncompatible) {
1✔
3482
                                throw new IllegalStateException("Cannot define method '" + name + "' with the given signature as an annotation type method");
1✔
3483
                            }
3484
                        }
3485
                    }
1✔
3486

3487
                    /**
3488
                     * {@inheritDoc}
3489
                     */
3490
                    public void assertAnnotation() {
3491
                        /* do nothing */
3492
                    }
1✔
3493

3494
                    /**
3495
                     * {@inheritDoc}
3496
                     */
3497
                    public void assertTypeAnnotation() {
3498
                        /* do nothing */
3499
                    }
×
3500

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

3508
                    /**
3509
                     * {@inheritDoc}
3510
                     */
3511
                    public void assertDefaultMethodCall() {
3512
                        /* do nothing */
3513
                    }
×
3514

3515
                    /**
3516
                     * {@inheritDoc}
3517
                     */
3518
                    public void assertType(int modifier, String superClassInternalName, boolean definesInterfaces, boolean isGeneric) {
3519
                        if ((modifier & Opcodes.ACC_INTERFACE) == 0) {
1✔
3520
                            throw new IllegalStateException("Cannot define annotation type without interface modifier");
×
3521
                        }
3522
                    }
1✔
3523

3524
                    /**
3525
                     * {@inheritDoc}
3526
                     */
3527
                    public void assertTypeInConstantPool() {
3528
                        /* do nothing */
3529
                    }
×
3530

3531
                    /**
3532
                     * {@inheritDoc}
3533
                     */
3534
                    public void assertMethodTypeInConstantPool() {
3535
                        /* do nothing */
3536
                    }
×
3537

3538
                    /**
3539
                     * {@inheritDoc}
3540
                     */
3541
                    public void assertHandleInConstantPool() {
3542
                        /* do nothing */
3543
                    }
×
3544

3545
                    /**
3546
                     * {@inheritDoc}
3547
                     */
3548
                    public void assertInvokeDynamic() {
3549
                        /* do nothing */
3550
                    }
×
3551

3552
                    /**
3553
                     * {@inheritDoc}
3554
                     */
3555
                    public void assertSubRoutine() {
3556
                        /* do nothing */
3557
                    }
×
3558

3559
                    /**
3560
                     * {@inheritDoc}
3561
                     */
3562
                    public void assertDynamicValueInConstantPool() {
3563
                        /* do nothing */
3564
                    }
×
3565

3566
                    /**
3567
                     * {@inheritDoc}
3568
                     */
3569
                    public void assertNestMate() {
3570
                        /* do nothing */
3571
                    }
×
3572

3573
                    /**
3574
                     * {@inheritDoc}
3575
                     */
3576
                    public void assertRecord() {
3577
                        /* do nothing */
3578
                    }
×
3579

3580
                    /**
3581
                     * {@inheritDoc}
3582
                     */
3583
                    public void assertPermittedSubclass() {
3584
                        /* do nothing */
3585
                    }
×
3586
                }
3587

3588
                /**
3589
                 * Represents the constraint implied by a class file version.
3590
                 */
3591
                @HashCodeAndEqualsPlugin.Enhance
3592
                class ForClassFileVersion implements Constraint {
3593

3594
                    /**
3595
                     * The enforced class file version.
3596
                     */
3597
                    private final ClassFileVersion classFileVersion;
3598

3599
                    /**
3600
                     * Creates a new constraint for the given class file version.
3601
                     *
3602
                     * @param classFileVersion The enforced class file version.
3603
                     */
3604
                    protected ForClassFileVersion(ClassFileVersion classFileVersion) {
1✔
3605
                        this.classFileVersion = classFileVersion;
1✔
3606
                    }
1✔
3607

3608
                    /**
3609
                     * {@inheritDoc}
3610
                     */
3611
                    public void assertType(int modifiers, @MaybeNull String superClassInternalName, boolean definesInterfaces, boolean isGeneric) {
3612
                        if ((modifiers & Opcodes.ACC_ANNOTATION) != 0 && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
1✔
3613
                            throw new IllegalStateException("Cannot define annotation type for class file version " + classFileVersion);
×
3614
                        } else if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3615
                            throw new IllegalStateException("Cannot define a generic type for class file version " + classFileVersion);
×
3616
                        }
3617
                    }
1✔
3618

3619
                    /**
3620
                     * {@inheritDoc}
3621
                     */
3622
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3623
                        if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3624
                            throw new IllegalStateException("Cannot define generic field '" + name + "' for class file version " + classFileVersion);
×
3625
                        }
3626
                    }
1✔
3627

3628
                    /**
3629
                     * {@inheritDoc}
3630
                     */
3631
                    public void assertMethod(String name,
3632
                                             boolean isAbstract,
3633
                                             boolean isPublic,
3634
                                             boolean isPrivate,
3635
                                             boolean isStatic,
3636
                                             boolean isVirtual,
3637
                                             boolean isConstructor,
3638
                                             boolean isDefaultValueIncompatible,
3639
                                             boolean isGeneric) {
3640
                        if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3641
                            throw new IllegalStateException("Cannot define generic method '" + name + "' for class file version " + classFileVersion);
×
3642
                        } else if (!isVirtual && isAbstract) {
1✔
3643
                            throw new IllegalStateException("Cannot define static or non-virtual method '" + name + "' to be abstract");
1✔
3644
                        }
3645
                    }
1✔
3646

3647
                    /**
3648
                     * {@inheritDoc}
3649
                     */
3650
                    public void assertAnnotation() {
3651
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3652
                            throw new IllegalStateException("Cannot write annotations for class file version " + classFileVersion);
1✔
3653
                        }
3654
                    }
1✔
3655

3656
                    /**
3657
                     * {@inheritDoc}
3658
                     */
3659
                    public void assertTypeAnnotation() {
3660
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3661
                            throw new IllegalStateException("Cannot write type annotations for class file version " + classFileVersion);
×
3662
                        }
3663
                    }
1✔
3664

3665
                    /**
3666
                     * {@inheritDoc}
3667
                     */
3668
                    public void assertDefaultValue(String name) {
3669
                        /* do nothing, implicitly checked by type assertion */
3670
                    }
1✔
3671

3672
                    /**
3673
                     * {@inheritDoc}
3674
                     */
3675
                    public void assertDefaultMethodCall() {
3676
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V8)) {
1✔
3677
                            throw new IllegalStateException("Cannot invoke default method for class file version " + classFileVersion);
×
3678
                        }
3679
                    }
1✔
3680

3681
                    /**
3682
                     * {@inheritDoc}
3683
                     */
3684
                    public void assertTypeInConstantPool() {
3685
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3686
                            throw new IllegalStateException("Cannot write type to constant pool for class file version " + classFileVersion);
×
3687
                        }
3688
                    }
1✔
3689

3690
                    /**
3691
                     * {@inheritDoc}
3692
                     */
3693
                    public void assertMethodTypeInConstantPool() {
3694
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3695
                            throw new IllegalStateException("Cannot write method type to constant pool for class file version " + classFileVersion);
1✔
3696
                        }
3697
                    }
1✔
3698

3699
                    /**
3700
                     * {@inheritDoc}
3701
                     */
3702
                    public void assertHandleInConstantPool() {
3703
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3704
                            throw new IllegalStateException("Cannot write method handle to constant pool for class file version " + classFileVersion);
1✔
3705
                        }
3706
                    }
1✔
3707

3708
                    /**
3709
                     * {@inheritDoc}
3710
                     */
3711
                    public void assertInvokeDynamic() {
3712
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3713
                            throw new IllegalStateException("Cannot write invoke dynamic instruction for class file version " + classFileVersion);
×
3714
                        }
3715
                    }
1✔
3716

3717
                    /**
3718
                     * {@inheritDoc}
3719
                     */
3720
                    public void assertSubRoutine() {
3721
                        if (classFileVersion.isGreaterThan(ClassFileVersion.JAVA_V5)) {
1✔
3722
                            throw new IllegalStateException("Cannot write subroutine for class file version " + classFileVersion);
×
3723
                        }
3724
                    }
1✔
3725

3726
                    /**
3727
                     * {@inheritDoc}
3728
                     */
3729
                    public void assertDynamicValueInConstantPool() {
3730
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
1✔
3731
                            throw new IllegalStateException("Cannot write dynamic constant for class file version " + classFileVersion);
1✔
3732
                        }
3733
                    }
×
3734

3735
                    /**
3736
                     * {@inheritDoc}
3737
                     */
3738
                    public void assertNestMate() {
3739
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
×
3740
                            throw new IllegalStateException("Cannot define nest mate for class file version " + classFileVersion);
×
3741
                        }
3742
                    }
×
3743

3744
                    /**
3745
                     * {@inheritDoc}
3746
                     */
3747
                    public void assertRecord() {
3748
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V14)) {
1✔
3749
                            throw new IllegalStateException("Cannot define record for class file version " + classFileVersion);
1✔
3750
                        }
3751
                    }
×
3752

3753
                    /**
3754
                     * {@inheritDoc}
3755
                     */
3756
                    public void assertPermittedSubclass() {
3757
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V17)) {
×
3758
                            throw new IllegalStateException("Cannot define permitted subclasses for class file version " + classFileVersion);
×
3759
                        }
3760
                    }
×
3761
                }
3762

3763
                /**
3764
                 * A constraint implementation that summarizes several constraints.
3765
                 */
3766
                @HashCodeAndEqualsPlugin.Enhance
3767
                class Compound implements Constraint {
3768

3769
                    /**
3770
                     * A list of constraints that is enforced in the given order.
3771
                     */
3772
                    private final List<Constraint> constraints;
3773

3774
                    /**
3775
                     * Creates a new compound constraint.
3776
                     *
3777
                     * @param constraints A list of constraints that is enforced in the given order.
3778
                     */
3779
                    public Compound(List<? extends Constraint> constraints) {
1✔
3780
                        this.constraints = new ArrayList<Constraint>();
1✔
3781
                        for (Constraint constraint : constraints) {
1✔
3782
                            if (constraint instanceof Compound) {
1✔
3783
                                this.constraints.addAll(((Compound) constraint).constraints);
×
3784
                            } else {
3785
                                this.constraints.add(constraint);
1✔
3786
                            }
3787
                        }
1✔
3788
                    }
1✔
3789

3790
                    /**
3791
                     * {@inheritDoc}
3792
                     */
3793
                    public void assertType(int modifier, @MaybeNull String superClassInternalName, boolean definesInterfaces, boolean isGeneric) {
3794
                        for (Constraint constraint : constraints) {
1✔
3795
                            constraint.assertType(modifier, superClassInternalName, definesInterfaces, isGeneric);
1✔
3796
                        }
1✔
3797
                    }
1✔
3798

3799
                    /**
3800
                     * {@inheritDoc}
3801
                     */
3802
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3803
                        for (Constraint constraint : constraints) {
1✔
3804
                            constraint.assertField(name, isPublic, isStatic, isFinal, isGeneric);
1✔
3805
                        }
1✔
3806
                    }
1✔
3807

3808
                    /**
3809
                     * {@inheritDoc}
3810
                     */
3811
                    public void assertMethod(String name,
3812
                                             boolean isAbstract,
3813
                                             boolean isPublic,
3814
                                             boolean isPrivate,
3815
                                             boolean isStatic,
3816
                                             boolean isVirtual,
3817
                                             boolean isConstructor,
3818
                                             boolean isDefaultValueIncompatible,
3819
                                             boolean isGeneric) {
3820
                        for (Constraint constraint : constraints) {
1✔
3821
                            constraint.assertMethod(name,
1✔
3822
                                    isAbstract,
3823
                                    isPublic,
3824
                                    isPrivate,
3825
                                    isStatic,
3826
                                    isVirtual,
3827
                                    isConstructor,
3828
                                    isDefaultValueIncompatible,
3829
                                    isGeneric);
3830
                        }
1✔
3831
                    }
1✔
3832

3833
                    /**
3834
                     * {@inheritDoc}
3835
                     */
3836
                    public void assertDefaultValue(String name) {
3837
                        for (Constraint constraint : constraints) {
1✔
3838
                            constraint.assertDefaultValue(name);
1✔
3839
                        }
1✔
3840
                    }
1✔
3841

3842
                    /**
3843
                     * {@inheritDoc}
3844
                     */
3845
                    public void assertDefaultMethodCall() {
3846
                        for (Constraint constraint : constraints) {
1✔
3847
                            constraint.assertDefaultMethodCall();
1✔
3848
                        }
1✔
3849
                    }
1✔
3850

3851
                    /**
3852
                     * {@inheritDoc}
3853
                     */
3854
                    public void assertAnnotation() {
3855
                        for (Constraint constraint : constraints) {
1✔
3856
                            constraint.assertAnnotation();
1✔
3857
                        }
1✔
3858
                    }
1✔
3859

3860
                    /**
3861
                     * {@inheritDoc}
3862
                     */
3863
                    public void assertTypeAnnotation() {
3864
                        for (Constraint constraint : constraints) {
1✔
3865
                            constraint.assertTypeAnnotation();
1✔
3866
                        }
1✔
3867
                    }
1✔
3868

3869
                    /**
3870
                     * {@inheritDoc}
3871
                     */
3872
                    public void assertTypeInConstantPool() {
3873
                        for (Constraint constraint : constraints) {
1✔
3874
                            constraint.assertTypeInConstantPool();
1✔
3875
                        }
1✔
3876
                    }
1✔
3877

3878
                    /**
3879
                     * {@inheritDoc}
3880
                     */
3881
                    public void assertMethodTypeInConstantPool() {
3882
                        for (Constraint constraint : constraints) {
1✔
3883
                            constraint.assertMethodTypeInConstantPool();
1✔
3884
                        }
1✔
3885
                    }
1✔
3886

3887
                    /**
3888
                     * {@inheritDoc}
3889
                     */
3890
                    public void assertHandleInConstantPool() {
3891
                        for (Constraint constraint : constraints) {
1✔
3892
                            constraint.assertHandleInConstantPool();
1✔
3893
                        }
1✔
3894
                    }
1✔
3895

3896
                    /**
3897
                     * {@inheritDoc}
3898
                     */
3899
                    public void assertInvokeDynamic() {
3900
                        for (Constraint constraint : constraints) {
1✔
3901
                            constraint.assertInvokeDynamic();
1✔
3902
                        }
1✔
3903
                    }
1✔
3904

3905
                    /**
3906
                     * {@inheritDoc}
3907
                     */
3908
                    public void assertSubRoutine() {
3909
                        for (Constraint constraint : constraints) {
1✔
3910
                            constraint.assertSubRoutine();
1✔
3911
                        }
1✔
3912
                    }
1✔
3913

3914
                    /**
3915
                     * {@inheritDoc}
3916
                     */
3917
                    public void assertDynamicValueInConstantPool() {
3918
                        for (Constraint constraint : constraints) {
1✔
3919
                            constraint.assertDynamicValueInConstantPool();
×
3920
                        }
×
3921
                    }
×
3922

3923
                    /**
3924
                     * {@inheritDoc}
3925
                     */
3926
                    public void assertNestMate() {
3927
                        for (Constraint constraint : constraints) {
×
3928
                            constraint.assertNestMate();
×
3929
                        }
×
3930
                    }
×
3931

3932
                    /**
3933
                     * {@inheritDoc}
3934
                     */
3935
                    public void assertRecord() {
3936
                        for (Constraint constraint : constraints) {
1✔
3937
                            constraint.assertRecord();
×
3938
                        }
×
3939
                    }
×
3940

3941
                    /**
3942
                     * {@inheritDoc}
3943
                     */
3944
                    public void assertPermittedSubclass() {
3945
                        for (Constraint constraint : constraints) {
×
3946
                            constraint.assertPermittedSubclass();
×
3947
                        }
×
3948
                    }
×
3949
                }
3950
            }
3951

3952
            /**
3953
             * A field validator for checking default values.
3954
             */
3955
            protected class ValidatingFieldVisitor extends FieldVisitor {
3956

3957
                /**
3958
                 * Creates a validating field visitor.
3959
                 *
3960
                 * @param fieldVisitor The field visitor to which any calls are delegated to.
3961
                 */
3962
                protected ValidatingFieldVisitor(FieldVisitor fieldVisitor) {
1✔
3963
                    super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
3964
                }
1✔
3965

3966
                @Override
3967
                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
3968
                    constraint.assertAnnotation();
1✔
3969
                    return super.visitAnnotation(descriptor, visible);
1✔
3970
                }
3971
            }
3972

3973
            /**
3974
             * A method validator for checking default values.
3975
             */
3976
            protected class ValidatingMethodVisitor extends MethodVisitor {
3977

3978
                /**
3979
                 * The name of the method being visited.
3980
                 */
3981
                private final String name;
3982

3983
                /**
3984
                 * Creates a validating method visitor.
3985
                 *
3986
                 * @param methodVisitor The method visitor to which any calls are delegated to.
3987
                 * @param name          The name of the method being visited.
3988
                 */
3989
                protected ValidatingMethodVisitor(MethodVisitor methodVisitor, String name) {
1✔
3990
                    super(OpenedClassReader.ASM_API, methodVisitor);
1✔
3991
                    this.name = name;
1✔
3992
                }
1✔
3993

3994
                @Override
3995
                @MaybeNull
3996
                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
3997
                    constraint.assertAnnotation();
1✔
3998
                    return super.visitAnnotation(descriptor, visible);
1✔
3999
                }
4000

4001
                @Override
4002
                @MaybeNull
4003
                public AnnotationVisitor visitAnnotationDefault() {
4004
                    constraint.assertDefaultValue(name);
1✔
4005
                    return super.visitAnnotationDefault();
1✔
4006
                }
4007

4008
                @Override
4009
                @SuppressFBWarnings(value = "SF_SWITCH_NO_DEFAULT", justification = "Fall through to default case is intentional.")
4010
                public void visitLdcInsn(Object value) {
4011
                    if (value instanceof Type) {
1✔
4012
                        Type type = (Type) value;
1✔
4013
                        switch (type.getSort()) {
1✔
4014
                            case Type.OBJECT:
4015
                            case Type.ARRAY:
4016
                                constraint.assertTypeInConstantPool();
1✔
4017
                                break;
1✔
4018
                            case Type.METHOD:
4019
                                constraint.assertMethodTypeInConstantPool();
1✔
4020
                                break;
4021
                        }
4022
                    } else if (value instanceof Handle) {
1✔
4023
                        constraint.assertHandleInConstantPool();
1✔
4024
                    } else if (value instanceof ConstantDynamic) {
1✔
4025
                        constraint.assertDynamicValueInConstantPool();
×
4026
                    }
4027
                    super.visitLdcInsn(value);
1✔
4028
                }
1✔
4029

4030
                @Override
4031
                public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
4032
                    if (isInterface && opcode == Opcodes.INVOKESPECIAL) {
1✔
4033
                        constraint.assertDefaultMethodCall();
1✔
4034
                    }
4035
                    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
1✔
4036
                }
1✔
4037

4038
                @Override
4039
                public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethod, Object... bootstrapArgument) {
4040
                    constraint.assertInvokeDynamic();
1✔
4041
                    for (Object constant : bootstrapArgument) {
1✔
4042
                        if (constant instanceof ConstantDynamic) {
1✔
4043
                            constraint.assertDynamicValueInConstantPool();
×
4044
                        }
4045
                    }
4046
                    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethod, bootstrapArgument);
1✔
4047
                }
1✔
4048

4049
                @Override
4050
                public void visitJumpInsn(int opcode, Label label) {
4051
                    if (opcode == Opcodes.JSR) {
1✔
4052
                        constraint.assertSubRoutine();
1✔
4053
                    }
4054
                    super.visitJumpInsn(opcode, label);
1✔
4055
                }
1✔
4056
            }
4057
        }
4058

4059
        /**
4060
         * A type writer that inlines the created type into an existing class file.
4061
         *
4062
         * @param <U> The best known loaded type for the dynamically created type.
4063
         */
4064
        @HashCodeAndEqualsPlugin.Enhance
4065
        public abstract static class ForInlining<U> extends Default<U> {
4066

4067
            /**
4068
             * Indicates that a field should be ignored.
4069
             */
4070
            @AlwaysNull
4071
            private static final FieldVisitor IGNORE_FIELD = null;
1✔
4072

4073
            /**
4074
             * Indicates that a method should be ignored.
4075
             */
4076
            @AlwaysNull
4077
            private static final MethodVisitor IGNORE_METHOD = null;
1✔
4078

4079
            /**
4080
             * Indicates that a record component should be ignored.
4081
             */
4082
            @AlwaysNull
4083
            private static final RecordComponentVisitor IGNORE_RECORD_COMPONENT = null;
1✔
4084

4085
            /**
4086
             * Indicates that an annotation should be ignored.
4087
             */
4088
            @AlwaysNull
4089
            private static final AnnotationVisitor IGNORE_ANNOTATION = null;
1✔
4090

4091
            /**
4092
             * The original type's description.
4093
             */
4094
            protected final TypeDescription originalType;
4095

4096
            /**
4097
             * The class file locator for locating the original type's class file.
4098
             */
4099
            protected final ClassFileLocator classFileLocator;
4100

4101
            /**
4102
             * Creates a new inlining type writer.
4103
             *
4104
             * @param instrumentedType             The instrumented type to be created.
4105
             * @param classFileVersion             The class file specified by the user.
4106
             * @param fieldPool                    The field pool to use.
4107
             * @param recordComponentPool          The record component pool to use.
4108
             * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
4109
             * @param fields                       The instrumented type's declared fields.
4110
             * @param methods                      The instrumented type's declared and virtually inherited methods.
4111
             * @param instrumentedMethods          The instrumented methods relevant to this type creation.
4112
             * @param recordComponents             The instrumented type's record components.
4113
             * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
4114
             * @param typeInitializer              The type initializer to include in the created type's type initializer.
4115
             * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
4116
             * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
4117
             * @param annotationValueFilterFactory The annotation value filter factory to apply.
4118
             * @param annotationRetention          The annotation retention to apply.
4119
             * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
4120
             * @param implementationContextFactory The implementation context factory to apply.
4121
             * @param typeValidation               Determines if a type should be explicitly validated.
4122
             * @param classReaderFactory           The class reader factory to use.
4123
             * @param classWriterFactory           The class writer factory to use.
4124
             * @param typePool                     The type pool to use for computing stack map frames, if required.
4125
             * @param originalType                 The original type's description.
4126
             * @param classFileLocator             The class file locator for locating the original type's class file.
4127
             */
4128
            protected ForInlining(TypeDescription instrumentedType,
4129
                                  ClassFileVersion classFileVersion,
4130
                                  FieldPool fieldPool,
4131
                                  RecordComponentPool recordComponentPool,
4132
                                  List<? extends DynamicType> auxiliaryTypes,
4133
                                  FieldList<FieldDescription.InDefinedShape> fields,
4134
                                  MethodList<?> methods,
4135
                                  MethodList<?> instrumentedMethods,
4136
                                  RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
4137
                                  LoadedTypeInitializer loadedTypeInitializer,
4138
                                  TypeInitializer typeInitializer,
4139
                                  TypeAttributeAppender typeAttributeAppender,
4140
                                  AsmVisitorWrapper asmVisitorWrapper,
4141
                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
4142
                                  AnnotationRetention annotationRetention,
4143
                                  AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
4144
                                  Implementation.Context.Factory implementationContextFactory,
4145
                                  TypeValidation typeValidation,
4146
                                  AsmClassReader.Factory classReaderFactory,
4147
                                  AsmClassWriter.Factory classWriterFactory,
4148
                                  TypePool typePool,
4149
                                  TypeDescription originalType,
4150
                                  ClassFileLocator classFileLocator) {
4151
                super(instrumentedType,
1✔
4152
                        classFileVersion,
4153
                        fieldPool,
4154
                        recordComponentPool,
4155
                        auxiliaryTypes,
4156
                        fields,
4157
                        methods,
4158
                        instrumentedMethods,
4159
                        recordComponents,
4160
                        loadedTypeInitializer,
4161
                        typeInitializer,
4162
                        typeAttributeAppender,
4163
                        asmVisitorWrapper,
4164
                        annotationValueFilterFactory,
4165
                        annotationRetention,
4166
                        auxiliaryTypeNamingStrategy,
4167
                        implementationContextFactory,
4168
                        typeValidation,
4169
                        classReaderFactory,
4170
                        classWriterFactory,
4171
                        typePool);
4172
                this.originalType = originalType;
1✔
4173
                this.classFileLocator = classFileLocator;
1✔
4174
            }
1✔
4175

4176
            /**
4177
             * {@inheritDoc}
4178
             */
4179
            public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags) {
4180
                ContextRegistry contextRegistry = new ContextRegistry();
1✔
4181
                return new RegistryContextClassVisitor(writeTo(ValidatingClassVisitor.of(classVisitor, typeValidation),
1✔
4182
                        typeInitializer,
4183
                        contextRegistry,
4184
                        asmVisitorWrapper.mergeWriter(writerFlags),
1✔
4185
                        asmVisitorWrapper.mergeReader(readerFlags)), contextRegistry);
1✔
4186
            }
4187

4188
            @Override
4189
            protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
4190
                try {
4191
                    int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS);
1✔
4192
                    int readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
1✔
4193
                    byte[] binaryRepresentation = classFileLocator.locate(originalType.getName()).resolve();
1✔
4194
                    dispatcher.dump(instrumentedType, true, binaryRepresentation);
1✔
4195
                    AsmClassReader classReader = classReaderFactory.make(binaryRepresentation);
1✔
4196
                    AsmClassWriter classWriter = classWriterFactory.make(writerFlags, classReader, typePool);
1✔
4197
                    ContextRegistry contextRegistry = new ContextRegistry();
1✔
4198
                    classReader.accept(writeTo(ValidatingClassVisitor.of(classWriter.getVisitor(), typeValidation),
1✔
4199
                            typeInitializer,
4200
                            contextRegistry,
4201
                            writerFlags,
4202
                            readerFlags), readerFlags);
4203
                    return new UnresolvedType(classWriter.getBinaryRepresentation(), contextRegistry.getAuxiliaryTypes());
1✔
4204
                } catch (IOException exception) {
×
4205
                    throw new RuntimeException("The class file could not be written", exception);
×
4206
                }
4207
            }
4208

4209
            /**
4210
             * Creates a class visitor which weaves all changes and additions on the fly.
4211
             *
4212
             * @param classVisitor    The class visitor to which this entry is to be written to.
4213
             * @param typeInitializer The type initializer to apply.
4214
             * @param contextRegistry A context registry to register the lazily created implementation context to.
4215
             * @param writerFlags     The writer flags being used.
4216
             * @param readerFlags     The reader flags being used.
4217
             * @return A class visitor which is capable of applying the changes.
4218
             */
4219
            protected abstract ClassVisitor writeTo(ClassVisitor classVisitor,
4220
                                                    TypeInitializer typeInitializer,
4221
                                                    ContextRegistry contextRegistry,
4222
                                                    int writerFlags,
4223
                                                    int readerFlags);
4224

4225
            /**
4226
             * A context class visitor based on a {@link ContextRegistry}.
4227
             */
4228
            protected class RegistryContextClassVisitor extends ContextClassVisitor {
4229

4230
                /**
4231
                 * The context registry to use.
4232
                 */
4233
                private final ContextRegistry contextRegistry;
4234

4235
                /**
4236
                 * Creates a new context class visitor based on a {@link ContextRegistry}.
4237
                 *
4238
                 * @param classVisitor    The class visitor to delegate to.
4239
                 * @param contextRegistry The context registry to use.
4240
                 */
4241
                protected RegistryContextClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry) {
1✔
4242
                    super(classVisitor);
1✔
4243
                    this.contextRegistry = contextRegistry;
1✔
4244
                }
1✔
4245

4246
                @Override
4247
                public List<DynamicType> getAuxiliaryTypes() {
4248
                    return CompoundList.of(auxiliaryTypes, contextRegistry.getAuxiliaryTypes());
1✔
4249
                }
4250

4251
                @Override
4252
                public LoadedTypeInitializer getLoadedTypeInitializer() {
4253
                    return loadedTypeInitializer;
1✔
4254
                }
4255
            }
4256

4257
            /**
4258
             * A context registry allows to extract auxiliary types from a lazily created implementation context.
4259
             */
4260
            protected static class ContextRegistry {
1✔
4261

4262
                /**
4263
                 * The implementation context that is used for creating a class or {@code null} if it was not registered.
4264
                 */
4265
                @UnknownNull
4266
                private Implementation.Context.ExtractableView implementationContext;
4267

4268
                /**
4269
                 * Registers the implementation context.
4270
                 *
4271
                 * @param implementationContext The implementation context.
4272
                 */
4273
                public void setImplementationContext(Implementation.Context.ExtractableView implementationContext) {
4274
                    this.implementationContext = implementationContext;
1✔
4275
                }
1✔
4276

4277
                /**
4278
                 * Returns the auxiliary types that were registered during class creation. This method must only be called after
4279
                 * a class was created.
4280
                 *
4281
                 * @return The auxiliary types that were registered during class creation
4282
                 */
4283
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Lazy value definition is intended.")
4284
                public List<DynamicType> getAuxiliaryTypes() {
4285
                    return implementationContext.getAuxiliaryTypes();
1✔
4286
                }
4287
            }
4288

4289
            /**
4290
             * A default type writer that reprocesses a type completely.
4291
             *
4292
             * @param <V> The best known loaded type for the dynamically created type.
4293
             */
4294
            @HashCodeAndEqualsPlugin.Enhance
4295
            protected static class WithFullProcessing<V> extends ForInlining<V> {
4296

4297
                /**
4298
                 * An empty array to indicate missing frames.
4299
                 */
4300
                private static final Object[] EMPTY = new Object[0];
1✔
4301

4302
                /**
4303
                 * The method registry to use.
4304
                 */
4305
                private final MethodRegistry.Prepared methodRegistry;
4306

4307
                /**
4308
                 * The implementation target factory to use.
4309
                 */
4310
                private final Implementation.Target.Factory implementationTargetFactory;
4311

4312
                /**
4313
                 * The method rebase resolver to use for rebasing methods.
4314
                 */
4315
                private final MethodRebaseResolver methodRebaseResolver;
4316

4317
                /**
4318
                 * Creates a new inlining type writer that fully reprocesses a type.
4319
                 *
4320
                 * @param instrumentedType             The instrumented type to be created.
4321
                 * @param classFileVersion             The class file specified by the user.
4322
                 * @param fieldPool                    The field pool to use.
4323
                 * @param recordComponentPool          The record component pool to use.
4324
                 * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
4325
                 * @param fields                       The instrumented type's declared fields.
4326
                 * @param methods                      The instrumented type's declared and virtually inherited methods.
4327
                 * @param instrumentedMethods          The instrumented methods relevant to this type creation.
4328
                 * @param recordComponents             The instrumented type's record components.
4329
                 * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
4330
                 * @param typeInitializer              The type initializer to include in the created type's type initializer.
4331
                 * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
4332
                 * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
4333
                 * @param annotationValueFilterFactory The annotation value filter factory to apply.
4334
                 * @param annotationRetention          The annotation retention to apply.
4335
                 * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
4336
                 * @param implementationContextFactory The implementation context factory to apply.
4337
                 * @param typeValidation               Determines if a type should be explicitly validated.
4338
                 * @param classReaderFactory           The class reader factory to use.
4339
                 * @param classWriterFactory           The class writer factory to use.
4340
                 * @param typePool                     The type pool to use for computing stack map frames, if required.
4341
                 * @param originalType                 The original type's description.
4342
                 * @param classFileLocator             The class file locator for locating the original type's class file.
4343
                 * @param methodRegistry               The method registry to use.
4344
                 * @param implementationTargetFactory  The implementation target factory to use.
4345
                 * @param methodRebaseResolver         The method rebase resolver to use for rebasing methods.
4346
                 */
4347
                protected WithFullProcessing(TypeDescription instrumentedType,
4348
                                             ClassFileVersion classFileVersion,
4349
                                             FieldPool fieldPool,
4350
                                             RecordComponentPool recordComponentPool,
4351
                                             List<? extends DynamicType> auxiliaryTypes,
4352
                                             FieldList<FieldDescription.InDefinedShape> fields,
4353
                                             MethodList<?> methods, MethodList<?> instrumentedMethods,
4354
                                             RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
4355
                                             LoadedTypeInitializer loadedTypeInitializer,
4356
                                             TypeInitializer typeInitializer,
4357
                                             TypeAttributeAppender typeAttributeAppender,
4358
                                             AsmVisitorWrapper asmVisitorWrapper,
4359
                                             AnnotationValueFilter.Factory annotationValueFilterFactory,
4360
                                             AnnotationRetention annotationRetention,
4361
                                             AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
4362
                                             Implementation.Context.Factory implementationContextFactory,
4363
                                             TypeValidation typeValidation,
4364
                                             AsmClassReader.Factory classReaderFactory,
4365
                                             AsmClassWriter.Factory classWriterFactory,
4366
                                             TypePool typePool,
4367
                                             TypeDescription originalType,
4368
                                             ClassFileLocator classFileLocator,
4369
                                             MethodRegistry.Prepared methodRegistry,
4370
                                             Implementation.Target.Factory implementationTargetFactory,
4371
                                             MethodRebaseResolver methodRebaseResolver) {
4372
                    super(instrumentedType,
1✔
4373
                            classFileVersion,
4374
                            fieldPool,
4375
                            recordComponentPool,
4376
                            auxiliaryTypes,
4377
                            fields,
4378
                            methods,
4379
                            instrumentedMethods,
4380
                            recordComponents,
4381
                            loadedTypeInitializer,
4382
                            typeInitializer,
4383
                            typeAttributeAppender,
4384
                            asmVisitorWrapper,
4385
                            annotationValueFilterFactory,
4386
                            annotationRetention,
4387
                            auxiliaryTypeNamingStrategy,
4388
                            implementationContextFactory,
4389
                            typeValidation,
4390
                            classReaderFactory,
4391
                            classWriterFactory,
4392
                            typePool,
4393
                            originalType,
4394
                            classFileLocator);
4395
                    this.methodRegistry = methodRegistry;
1✔
4396
                    this.implementationTargetFactory = implementationTargetFactory;
1✔
4397
                    this.methodRebaseResolver = methodRebaseResolver;
1✔
4398
                }
1✔
4399

4400
                /**
4401
                 * {@inheritDoc}
4402
                 */
4403
                protected ClassVisitor writeTo(ClassVisitor classVisitor, TypeInitializer typeInitializer, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
4404
                    classVisitor = new RedefinitionClassVisitor(classVisitor, typeInitializer, contextRegistry, writerFlags, readerFlags);
1✔
4405
                    return originalType.getName().equals(instrumentedType.getName())
1✔
4406
                            ? classVisitor
4407
                            : new OpenedClassRemapper(classVisitor, new SimpleRemapper(OpenedClassReader.ASM_API, originalType.getInternalName(), instrumentedType.getInternalName()));
1✔
4408
                }
4409

4410
                /**
4411
                 * A {@link ClassRemapper} that uses the Byte Buddy-defined API version.
4412
                 */
4413
                protected static class OpenedClassRemapper extends ClassRemapper {
4414

4415
                    /**
4416
                     * Creates a new opened class remapper.
4417
                     *
4418
                     * @param classVisitor The class visitor to wrap
4419
                     * @param remapper     The remapper to apply.
4420
                     */
4421
                    protected OpenedClassRemapper(ClassVisitor classVisitor, Remapper remapper) {
4422
                        super(OpenedClassReader.ASM_API, classVisitor, remapper);
1✔
4423
                    }
1✔
4424
                }
4425

4426
                /**
4427
                 * An initialization handler is responsible for handling the creation of the type initializer.
4428
                 */
4429
                protected interface InitializationHandler {
4430

4431
                    /**
4432
                     * Invoked upon completion of writing the instrumented type.
4433
                     *
4434
                     * @param classVisitor          The class visitor to write any methods to.
4435
                     * @param implementationContext The implementation context to use.
4436
                     */
4437
                    void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext);
4438

4439
                    /**
4440
                     * An initialization handler that creates a new type initializer.
4441
                     */
4442
                    class Creating extends TypeInitializer.Drain.Default implements InitializationHandler {
4443

4444
                        /**
4445
                         * Creates a new creating initialization handler.
4446
                         *
4447
                         * @param instrumentedType             The instrumented type.
4448
                         * @param methodPool                   The method pool to use.
4449
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4450
                         */
4451
                        protected Creating(TypeDescription instrumentedType,
4452
                                           MethodPool methodPool,
4453
                                           AnnotationValueFilter.Factory annotationValueFilterFactory) {
4454
                            super(instrumentedType, methodPool, annotationValueFilterFactory);
1✔
4455
                        }
1✔
4456

4457
                        /**
4458
                         * {@inheritDoc}
4459
                         */
4460
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4461
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4462
                        }
1✔
4463
                    }
4464

4465
                    /**
4466
                     * An initialization handler that appends code to a previously visited type initializer.
4467
                     */
4468
                    abstract class Appending extends MethodVisitor implements InitializationHandler, TypeInitializer.Drain {
4469

4470
                        /**
4471
                         * The instrumented type.
4472
                         */
4473
                        protected final TypeDescription instrumentedType;
4474

4475
                        /**
4476
                         * The method pool record for the type initializer.
4477
                         */
4478
                        protected final MethodPool.Record record;
4479

4480
                        /**
4481
                         * The used annotation value filter factory.
4482
                         */
4483
                        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
4484

4485
                        /**
4486
                         * The frame writer to use.
4487
                         */
4488
                        protected final FrameWriter frameWriter;
4489

4490
                        /**
4491
                         * The currently recorded stack size.
4492
                         */
4493
                        protected int stackSize;
4494

4495
                        /**
4496
                         * The currently recorded local variable length.
4497
                         */
4498
                        protected int localVariableLength;
4499

4500
                        /**
4501
                         * Creates a new appending initialization handler.
4502
                         *
4503
                         * @param methodVisitor                The underlying method visitor.
4504
                         * @param instrumentedType             The instrumented type.
4505
                         * @param record                       The method pool record for the type initializer.
4506
                         * @param annotationValueFilterFactory The used annotation value filter factory.
4507
                         * @param requireFrames                {@code true} if the visitor is required to add frames.
4508
                         * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4509
                         */
4510
                        protected Appending(MethodVisitor methodVisitor,
4511
                                            TypeDescription instrumentedType,
4512
                                            MethodPool.Record record,
4513
                                            AnnotationValueFilter.Factory annotationValueFilterFactory,
4514
                                            boolean requireFrames,
4515
                                            boolean expandFrames) {
4516
                            super(OpenedClassReader.ASM_API, methodVisitor);
1✔
4517
                            this.instrumentedType = instrumentedType;
1✔
4518
                            this.record = record;
1✔
4519
                            this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
4520
                            if (!requireFrames) {
1✔
4521
                                frameWriter = FrameWriter.NoOp.INSTANCE;
1✔
4522
                            } else if (expandFrames) {
1✔
4523
                                frameWriter = FrameWriter.Expanding.INSTANCE;
×
4524
                            } else {
4525
                                frameWriter = new FrameWriter.Active();
1✔
4526
                            }
4527
                        }
1✔
4528

4529
                        /**
4530
                         * Resolves an initialization handler.
4531
                         *
4532
                         * @param enabled                      {@code true} if the implementation context is enabled, i.e. any {@link TypeInitializer} might be active.
4533
                         * @param methodVisitor                The delegation method visitor.
4534
                         * @param instrumentedType             The instrumented type.
4535
                         * @param methodPool                   The method pool to use.
4536
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4537
                         * @param requireFrames                {@code true} if frames must be computed.
4538
                         * @param expandFrames                 {@code true} if frames must be expanded.
4539
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4540
                         */
4541
                        protected static InitializationHandler of(boolean enabled,
4542
                                                                  MethodVisitor methodVisitor,
4543
                                                                  TypeDescription instrumentedType,
4544
                                                                  MethodPool methodPool,
4545
                                                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
4546
                                                                  boolean requireFrames,
4547
                                                                  boolean expandFrames) {
4548
                            return enabled
1✔
4549
                                    ? withDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames)
1✔
4550
                                    : withoutDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4551
                        }
4552

4553
                        /**
4554
                         * Resolves an initialization handler with a drain.
4555
                         *
4556
                         * @param methodVisitor                The delegation method visitor.
4557
                         * @param instrumentedType             The instrumented type.
4558
                         * @param methodPool                   The method pool to use.
4559
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4560
                         * @param requireFrames                {@code true} if frames must be computed.
4561
                         * @param expandFrames                 {@code true} if frames must be expanded.
4562
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4563
                         */
4564
                        private static WithDrain withDrain(MethodVisitor methodVisitor,
4565
                                                           TypeDescription instrumentedType,
4566
                                                           MethodPool methodPool,
4567
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4568
                                                           boolean requireFrames,
4569
                                                           boolean expandFrames) {
4570
                            MethodPool.Record record = methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4571
                            return record.getSort().isImplemented()
1✔
4572
                                    ? new WithDrain.WithActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames)
4573
                                    : new WithDrain.WithoutActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4574
                        }
4575

4576
                        /**
4577
                         * Resolves an initialization handler without a drain.
4578
                         *
4579
                         * @param methodVisitor                The delegation method visitor.
4580
                         * @param instrumentedType             The instrumented type.
4581
                         * @param methodPool                   The method pool to use.
4582
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4583
                         * @param requireFrames                {@code true} if frames must be computed.
4584
                         * @param expandFrames                 {@code true} if frames must be expanded.
4585
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4586
                         */
4587
                        private static WithoutDrain withoutDrain(MethodVisitor methodVisitor,
4588
                                                                 TypeDescription instrumentedType,
4589
                                                                 MethodPool methodPool,
4590
                                                                 AnnotationValueFilter.Factory annotationValueFilterFactory,
4591
                                                                 boolean requireFrames,
4592
                                                                 boolean expandFrames) {
4593
                            MethodPool.Record record = methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4594
                            return record.getSort().isImplemented()
1✔
4595
                                    ? new WithoutDrain.WithActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames)
4596
                                    : new WithoutDrain.WithoutActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory);
4597
                        }
4598

4599
                        @Override
4600
                        public void visitCode() {
4601
                            record.applyAttributes(mv, annotationValueFilterFactory);
1✔
4602
                            super.visitCode();
1✔
4603
                            onStart();
1✔
4604
                        }
1✔
4605

4606
                        /**
4607
                         * Invoked after the user code was visited.
4608
                         */
4609
                        protected abstract void onStart();
4610

4611
                        @Override
4612
                        public void visitFrame(int type, int localVariableLength, @MaybeNull Object[] localVariable, int stackSize, @MaybeNull Object[] stack) {
4613
                            super.visitFrame(type, localVariableLength, localVariable, stackSize, stack);
1✔
4614
                            frameWriter.onFrame(type, localVariableLength);
1✔
4615
                        }
1✔
4616

4617
                        @Override
4618
                        public void visitMaxs(int stackSize, int localVariableLength) {
4619
                            this.stackSize = stackSize;
1✔
4620
                            this.localVariableLength = localVariableLength;
1✔
4621
                        }
1✔
4622

4623
                        @Override
4624
                        public abstract void visitEnd();
4625

4626
                        /**
4627
                         * {@inheritDoc}
4628
                         */
4629
                        public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
4630
                            ByteCodeAppender.Size size = typeInitializer.apply(mv, implementationContext, new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4631
                            stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4632
                            localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4633
                            onComplete(implementationContext);
1✔
4634
                        }
1✔
4635

4636
                        /**
4637
                         * Invoked upon completion of writing the type initializer.
4638
                         *
4639
                         * @param implementationContext The implementation context to use.
4640
                         */
4641
                        protected abstract void onComplete(Implementation.Context implementationContext);
4642

4643
                        /**
4644
                         * {@inheritDoc}
4645
                         */
4646
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4647
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4648
                            mv.visitMaxs(stackSize, localVariableLength);
1✔
4649
                            mv.visitEnd();
1✔
4650
                        }
1✔
4651

4652
                        /**
4653
                         * A frame writer is responsible for adding empty frames on jump instructions.
4654
                         */
4655
                        protected interface FrameWriter {
4656

4657
                            /**
4658
                             * An empty array.
4659
                             */
4660
                            Object[] EMPTY = new Object[0];
1✔
4661

4662
                            /**
4663
                             * Informs this frame writer of an observed frame.
4664
                             *
4665
                             * @param type                The frame type.
4666
                             * @param localVariableLength The length of the local variables array.
4667
                             */
4668
                            void onFrame(int type, int localVariableLength);
4669

4670
                            /**
4671
                             * Emits an empty frame.
4672
                             *
4673
                             * @param methodVisitor The method visitor to write the frame to.
4674
                             */
4675
                            void emitFrame(MethodVisitor methodVisitor);
4676

4677
                            /**
4678
                             * A non-operational frame writer.
4679
                             */
4680
                            enum NoOp implements FrameWriter {
1✔
4681

4682
                                /**
4683
                                 * The singleton instance.
4684
                                 */
4685
                                INSTANCE;
1✔
4686

4687
                                /**
4688
                                 * {@inheritDoc}
4689
                                 */
4690
                                public void onFrame(int type, int localVariableLength) {
4691
                                    /* do nothing */
4692
                                }
1✔
4693

4694
                                /**
4695
                                 * {@inheritDoc}
4696
                                 */
4697
                                public void emitFrame(MethodVisitor methodVisitor) {
4698
                                    /* do nothing */
4699
                                }
1✔
4700
                            }
4701

4702
                            /**
4703
                             * A frame writer that creates an expanded frame.
4704
                             */
4705
                            enum Expanding implements FrameWriter {
1✔
4706

4707
                                /**
4708
                                 * The singleton instance.
4709
                                 */
4710
                                INSTANCE;
1✔
4711

4712
                                /**
4713
                                 * {@inheritDoc}
4714
                                 */
4715
                                public void onFrame(int type, int localVariableLength) {
4716
                                    /* do nothing */
4717
                                }
1✔
4718

4719
                                /**
4720
                                 * {@inheritDoc}
4721
                                 */
4722
                                public void emitFrame(MethodVisitor methodVisitor) {
4723
                                    methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4724
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4725
                                }
1✔
4726
                            }
4727

4728
                            /**
4729
                             * An active frame writer that creates the most efficient frame.
4730
                             */
4731
                            class Active implements FrameWriter {
1✔
4732

4733
                                /**
4734
                                 * The current length of the current local variable array.
4735
                                 */
4736
                                private int currentLocalVariableLength;
4737

4738
                                /**
4739
                                 * {@inheritDoc}
4740
                                 */
4741
                                public void onFrame(int type, int localVariableLength) {
4742
                                    switch (type) {
1✔
4743
                                        case Opcodes.F_SAME:
4744
                                        case Opcodes.F_SAME1:
4745
                                            break;
1✔
4746
                                        case Opcodes.F_APPEND:
4747
                                            currentLocalVariableLength += localVariableLength;
1✔
4748
                                            break;
1✔
4749
                                        case Opcodes.F_CHOP:
4750
                                            currentLocalVariableLength -= localVariableLength;
1✔
4751
                                            break;
1✔
4752
                                        case Opcodes.F_NEW:
4753
                                        case Opcodes.F_FULL:
4754
                                            currentLocalVariableLength = localVariableLength;
1✔
4755
                                            break;
1✔
4756
                                        default:
4757
                                            throw new IllegalStateException("Unexpected frame type: " + type);
1✔
4758
                                    }
4759
                                }
1✔
4760

4761
                                /**
4762
                                 * {@inheritDoc}
4763
                                 */
4764
                                public void emitFrame(MethodVisitor methodVisitor) {
4765
                                    if (currentLocalVariableLength == 0) {
1✔
4766
                                        methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4767
                                    } else if (currentLocalVariableLength > 3) {
1✔
4768
                                        methodVisitor.visitFrame(Opcodes.F_FULL, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4769
                                    } else {
4770
                                        methodVisitor.visitFrame(Opcodes.F_CHOP, currentLocalVariableLength, EMPTY, EMPTY.length, EMPTY);
1✔
4771
                                    }
4772
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4773
                                    currentLocalVariableLength = 0;
1✔
4774
                                }
1✔
4775
                            }
4776
                        }
4777

4778
                        /**
4779
                         * An initialization handler that appends code to a previously visited type initializer without allowing active
4780
                         * {@link TypeInitializer} registrations.
4781
                         */
4782
                        protected abstract static class WithoutDrain extends Appending {
4783

4784
                            /**
4785
                             * Creates a new appending initialization handler without a drain.
4786
                             *
4787
                             * @param methodVisitor                The underlying method visitor.
4788
                             * @param instrumentedType             The instrumented type.
4789
                             * @param record                       The method pool record for the type initializer.
4790
                             * @param annotationValueFilterFactory The used annotation value filter factory.
4791
                             * @param requireFrames                {@code true} if the visitor is required to add frames.
4792
                             * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4793
                             */
4794
                            protected WithoutDrain(MethodVisitor methodVisitor,
4795
                                                   TypeDescription instrumentedType,
4796
                                                   MethodPool.Record record,
4797
                                                   AnnotationValueFilter.Factory annotationValueFilterFactory,
4798
                                                   boolean requireFrames,
4799
                                                   boolean expandFrames) {
4800
                                super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4801
                            }
1✔
4802

4803
                            @Override
4804
                            protected void onStart() {
4805
                                /* do nothing */
4806
                            }
1✔
4807

4808
                            @Override
4809
                            public void visitEnd() {
4810
                                /* do nothing */
4811
                            }
1✔
4812

4813
                            /**
4814
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4815
                             * {@link TypeInitializer} registrations and without an active record.
4816
                             */
4817
                            protected static class WithoutActiveRecord extends WithoutDrain {
4818

4819
                                /**
4820
                                 * Creates a new appending initialization handler without a drain and without an active record.
4821
                                 *
4822
                                 * @param methodVisitor                The underlying method visitor.
4823
                                 * @param instrumentedType             The instrumented type.
4824
                                 * @param record                       The method pool record for the type initializer.
4825
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4826
                                 */
4827
                                protected WithoutActiveRecord(MethodVisitor methodVisitor,
4828
                                                              TypeDescription instrumentedType,
4829
                                                              MethodPool.Record record,
4830
                                                              AnnotationValueFilter.Factory annotationValueFilterFactory) {
4831
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, false, false);
1✔
4832
                                }
1✔
4833

4834
                                @Override
4835
                                protected void onComplete(Implementation.Context implementationContext) {
4836
                                    /* do nothing */
4837
                                }
1✔
4838
                            }
4839

4840
                            /**
4841
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4842
                             * {@link TypeInitializer} registrations and with an active record.
4843
                             */
4844
                            protected static class WithActiveRecord extends WithoutDrain {
4845

4846
                                /**
4847
                                 * The label that indicates the beginning of the active record.
4848
                                 */
4849
                                private final Label label;
4850

4851
                                /**
4852
                                 * Creates a new appending initialization handler without a drain and with an active record.
4853
                                 *
4854
                                 * @param methodVisitor                The underlying method visitor.
4855
                                 * @param instrumentedType             The instrumented type.
4856
                                 * @param record                       The method pool record for the type initializer.
4857
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4858
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4859
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4860
                                 */
4861
                                protected WithActiveRecord(MethodVisitor methodVisitor,
4862
                                                           TypeDescription instrumentedType,
4863
                                                           MethodPool.Record record,
4864
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4865
                                                           boolean requireFrames,
4866
                                                           boolean expandFrames) {
4867
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4868
                                    label = new Label();
1✔
4869
                                }
1✔
4870

4871
                                @Override
4872
                                public void visitInsn(int opcode) {
4873
                                    if (opcode == Opcodes.RETURN) {
1✔
4874
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4875
                                    } else {
4876
                                        super.visitInsn(opcode);
1✔
4877
                                    }
4878
                                }
1✔
4879

4880
                                @Override
4881
                                protected void onComplete(Implementation.Context implementationContext) {
4882
                                    mv.visitLabel(label);
1✔
4883
                                    frameWriter.emitFrame(mv);
1✔
4884
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
4885
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4886
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4887
                                }
1✔
4888

4889
                            }
4890
                        }
4891

4892
                        /**
4893
                         * An initialization handler that appends code to a previously visited type initializer with allowing active
4894
                         * {@link TypeInitializer} registrations.
4895
                         */
4896
                        protected abstract static class WithDrain extends Appending {
4897

4898
                            /**
4899
                             * A label marking the beginning of the appended code.
4900
                             */
4901
                            protected final Label appended;
4902

4903
                            /**
4904
                             * A label marking the beginning og the original type initializer's code.
4905
                             */
4906
                            protected final Label original;
4907

4908
                            /**
4909
                             * Creates a new appending initialization handler with a drain.
4910
                             *
4911
                             * @param methodVisitor                The underlying method visitor.
4912
                             * @param instrumentedType             The instrumented type.
4913
                             * @param record                       The method pool record for the type initializer.
4914
                             * @param annotationValueFilterFactory The used annotation value filter factory.
4915
                             * @param requireFrames                {@code true} if the visitor is required to add frames.
4916
                             * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4917
                             */
4918
                            protected WithDrain(MethodVisitor methodVisitor,
4919
                                                TypeDescription instrumentedType,
4920
                                                MethodPool.Record record,
4921
                                                AnnotationValueFilter.Factory annotationValueFilterFactory,
4922
                                                boolean requireFrames,
4923
                                                boolean expandFrames) {
4924
                                super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4925
                                appended = new Label();
1✔
4926
                                original = new Label();
1✔
4927
                            }
1✔
4928

4929
                            @Override
4930
                            protected void onStart() {
4931
                                mv.visitJumpInsn(Opcodes.GOTO, appended);
1✔
4932
                                mv.visitLabel(original);
1✔
4933
                                frameWriter.emitFrame(mv);
1✔
4934
                            }
1✔
4935

4936
                            @Override
4937
                            public void visitEnd() {
4938
                                mv.visitLabel(appended);
1✔
4939
                                frameWriter.emitFrame(mv);
1✔
4940
                            }
1✔
4941

4942
                            @Override
4943
                            protected void onComplete(Implementation.Context implementationContext) {
4944
                                mv.visitJumpInsn(Opcodes.GOTO, original);
1✔
4945
                                onAfterComplete(implementationContext);
1✔
4946
                            }
1✔
4947

4948
                            /**
4949
                             * Invoked after completion of writing the type initializer.
4950
                             *
4951
                             * @param implementationContext The implementation context to use.
4952
                             */
4953
                            protected abstract void onAfterComplete(Implementation.Context implementationContext);
4954

4955
                            /**
4956
                             * A code appending initialization handler with a drain that does not apply an explicit record.
4957
                             */
4958
                            protected static class WithoutActiveRecord extends WithDrain {
4959

4960
                                /**
4961
                                 * Creates a new appending initialization handler with a drain and without an active record.
4962
                                 *
4963
                                 * @param methodVisitor                The underlying method visitor.
4964
                                 * @param instrumentedType             The instrumented type.
4965
                                 * @param record                       The method pool record for the type initializer.
4966
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4967
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4968
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4969
                                 */
4970
                                protected WithoutActiveRecord(MethodVisitor methodVisitor,
4971
                                                              TypeDescription instrumentedType,
4972
                                                              MethodPool.Record record,
4973
                                                              AnnotationValueFilter.Factory annotationValueFilterFactory,
4974
                                                              boolean requireFrames,
4975
                                                              boolean expandFrames) {
4976
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4977
                                }
1✔
4978

4979
                                @Override
4980
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4981
                                    /* do nothing */
4982
                                }
1✔
4983
                            }
4984

4985
                            /**
4986
                             * A code appending initialization handler with a drain that applies an explicit record.
4987
                             */
4988
                            protected static class WithActiveRecord extends WithDrain {
4989

4990
                                /**
4991
                                 * A label indicating the beginning of the record's code.
4992
                                 */
4993
                                private final Label label;
4994

4995
                                /**
4996
                                 * Creates a new appending initialization handler with a drain and with an active record.
4997
                                 *
4998
                                 * @param methodVisitor                The underlying method visitor.
4999
                                 * @param instrumentedType             The instrumented type.
5000
                                 * @param record                       The method pool record for the type initializer.
5001
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
5002
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
5003
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
5004
                                 */
5005
                                protected WithActiveRecord(MethodVisitor methodVisitor,
5006
                                                           TypeDescription instrumentedType,
5007
                                                           MethodPool.Record record,
5008
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
5009
                                                           boolean requireFrames,
5010
                                                           boolean expandFrames) {
5011
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
5012
                                    label = new Label();
1✔
5013
                                }
1✔
5014

5015
                                @Override
5016
                                public void visitInsn(int opcode) {
5017
                                    if (opcode == Opcodes.RETURN) {
1✔
5018
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
5019
                                    } else {
5020
                                        super.visitInsn(opcode);
1✔
5021
                                    }
5022
                                }
1✔
5023

5024
                                @Override
5025
                                protected void onAfterComplete(Implementation.Context implementationContext) {
5026
                                    mv.visitLabel(label);
1✔
5027
                                    frameWriter.emitFrame(mv);
1✔
5028
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
5029
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
5030
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
5031
                                }
1✔
5032
                            }
5033
                        }
5034
                    }
5035
                }
5036

5037
                /**
5038
                 * A class visitor which is capable of applying a redefinition of an existing class file.
5039
                 */
5040
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
5041
                protected class RedefinitionClassVisitor extends MetadataAwareClassVisitor {
5042

5043
                    /**
5044
                     * The type initializer to apply.
5045
                     */
5046
                    private final TypeInitializer typeInitializer;
5047

5048
                    /**
5049
                     * A context registry to register the lazily created implementation context to.
5050
                     */
5051
                    private final ContextRegistry contextRegistry;
5052

5053
                    /**
5054
                     * The writer flags being used.
5055
                     */
5056
                    private final int writerFlags;
5057

5058
                    /**
5059
                     * The reader flags being used.
5060
                     */
5061
                    private final int readerFlags;
5062

5063
                    /**
5064
                     * A mapping of fields to write by their unique signature.
5065
                     */
5066
                    private final LinkedHashMap<SignatureKey, FieldDescription> declarableFields;
5067

5068
                    /**
5069
                     * A mapping of methods to write by their unique signature.
5070
                     */
5071
                    private final LinkedHashMap<SignatureKey, MethodDescription> declarableMethods;
5072

5073
                    /**
5074
                     * A mapping of record components to write by their names.
5075
                     */
5076
                    private final LinkedHashMap<String, RecordComponentDescription> declarableRecordComponents;
5077

5078
                    /**
5079
                     * 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.
5080
                     */
5081
                    private final Set<String> nestMembers;
5082

5083
                    /**
5084
                     * A mapping of the internal names of all declared types to their description.
5085
                     */
5086
                    private final LinkedHashMap<String, TypeDescription> declaredTypes;
5087

5088
                    /**
5089
                     * A list of internal names of permitted subclasses to include.
5090
                     */
5091
                    @MaybeNull
5092
                    private final Set<String> permittedSubclasses;
5093

5094
                    /**
5095
                     * The method pool to use or {@code null} if the pool was not yet initialized.
5096
                     */
5097
                    @UnknownNull
5098
                    private MethodPool methodPool;
5099

5100
                    /**
5101
                     * The initialization handler to use or {@code null} if the handler was not yet initialized.
5102
                     */
5103
                    @UnknownNull
5104
                    private InitializationHandler initializationHandler;
5105

5106
                    /**
5107
                     * The implementation context for this class creation or {@code null} if it was not yet created.
5108
                     */
5109
                    @UnknownNull
5110
                    private Implementation.Context.ExtractableView implementationContext;
5111

5112
                    /**
5113
                     * {@code true} if the modifiers for deprecation should be retained.
5114
                     */
5115
                    private boolean retainDeprecationModifiers;
5116

5117
                    /**
5118
                     * A set of keys for fields that were previosuly visited.
5119
                     */
5120
                    private final Set<SignatureKey> fieldKeys = new HashSet<SignatureKey>();
1✔
5121

5122
                    /**
5123
                     * A set of keys for methods that were previosuly visited.
5124
                     */
5125
                    private final Set<SignatureKey> methodsKeys = new HashSet<SignatureKey>();
1✔
5126

5127
                    /**
5128
                     * Creates a class visitor which is capable of redefining an existent class on the fly.
5129
                     *
5130
                     * @param classVisitor    The underlying class visitor to which writes are delegated.
5131
                     * @param typeInitializer The type initializer to apply.
5132
                     * @param contextRegistry A context registry to register the lazily created implementation context to.
5133
                     * @param writerFlags     The writer flags being used.
5134
                     * @param readerFlags     The reader flags being used.
5135
                     */
5136
                    protected RedefinitionClassVisitor(ClassVisitor classVisitor,
5137
                                                       TypeInitializer typeInitializer,
5138
                                                       ContextRegistry contextRegistry,
5139
                                                       int writerFlags,
5140
                                                       int readerFlags) {
1✔
5141
                        super(OpenedClassReader.ASM_API, classVisitor);
1✔
5142
                        this.typeInitializer = typeInitializer;
1✔
5143
                        this.contextRegistry = contextRegistry;
1✔
5144
                        this.writerFlags = writerFlags;
1✔
5145
                        this.readerFlags = readerFlags;
1✔
5146
                        declarableFields = new LinkedHashMap<SignatureKey, FieldDescription>((int) Math.ceil(fields.size() / 0.75));
1✔
5147
                        for (FieldDescription fieldDescription : fields) {
1✔
5148
                            declarableFields.put(new SignatureKey(fieldDescription.getInternalName(), fieldDescription.getDescriptor()), fieldDescription);
1✔
5149
                        }
1✔
5150
                        declarableMethods = new LinkedHashMap<SignatureKey, MethodDescription>((int) Math.ceil(instrumentedMethods.size() / 0.75));
1✔
5151
                        for (MethodDescription methodDescription : instrumentedMethods) {
1✔
5152
                            declarableMethods.put(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()), methodDescription);
1✔
5153
                        }
1✔
5154
                        declarableRecordComponents = new LinkedHashMap<String, RecordComponentDescription>((int) Math.ceil(recordComponents.size() / 0.75));
1✔
5155
                        for (RecordComponentDescription recordComponentDescription : recordComponents) {
1✔
5156
                            declarableRecordComponents.put(recordComponentDescription.getActualName(), recordComponentDescription);
×
5157
                        }
×
5158
                        if (instrumentedType.isNestHost()) {
1✔
5159
                            nestMembers = new LinkedHashSet<String>((int) Math.ceil(instrumentedType.getNestMembers().size() / 0.75));
1✔
5160
                            for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
1✔
5161
                                nestMembers.add(typeDescription.getInternalName());
×
5162
                            }
1✔
5163
                        } else {
5164
                            nestMembers = Collections.emptySet();
×
5165
                        }
5166
                        declaredTypes = new LinkedHashMap<String, TypeDescription>((int) Math.ceil(instrumentedType.getDeclaredTypes().size() / 0.75));
1✔
5167
                        for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
5168
                            declaredTypes.put(typeDescription.getInternalName(), typeDescription);
1✔
5169
                        }
1✔
5170
                        if (instrumentedType.isSealed()) {
1✔
5171
                            permittedSubclasses = new LinkedHashSet<String>((int) Math.ceil(instrumentedType.getPermittedSubtypes().size() / 0.75));
×
5172
                            for (TypeDescription typeDescription : instrumentedType.getPermittedSubtypes()) {
×
5173
                                permittedSubclasses.add(typeDescription.getInternalName());
×
5174
                            }
×
5175
                        } else {
5176
                            permittedSubclasses = null;
1✔
5177
                        }
5178
                    }
1✔
5179

5180
                    @Override
5181
                    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Relying on correlated type properties.")
5182
                    public void visit(int classFileVersionNumber,
5183
                                      int modifiers,
5184
                                      String internalName,
5185
                                      String genericSignature,
5186
                                      String superClassInternalName,
5187
                                      String[] interfaceTypeInternalName) {
5188
                        ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
1✔
5189
                        methodPool = methodRegistry.compile(implementationTargetFactory, classFileVersion);
1✔
5190
                        initializationHandler = new InitializationHandler.Creating(instrumentedType, methodPool, annotationValueFilterFactory);
1✔
5191
                        implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5192
                                auxiliaryTypeNamingStrategy,
5193
                                typeInitializer,
5194
                                classFileVersion,
5195
                                WithFullProcessing.this.classFileVersion,
5196
                                (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5197
                                        ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5198
                                        : Implementation.Context.FrameGeneration.DISABLED);
5199
                        retainDeprecationModifiers = classFileVersion.isLessThan(ClassFileVersion.JAVA_V5);
1✔
5200
                        contextRegistry.setImplementationContext(implementationContext);
1✔
5201
                        cv = asmVisitorWrapper.wrap(instrumentedType,
1✔
5202
                                cv,
5203
                                implementationContext,
5204
                                typePool,
5205
                                fields,
5206
                                methods,
5207
                                writerFlags,
5208
                                readerFlags);
5209
                        cv.visit(classFileVersionNumber,
1✔
5210
                                instrumentedType.getActualModifiers((modifiers & Opcodes.ACC_SUPER) != 0 && !instrumentedType.isInterface())
1✔
5211
                                        | resolveDeprecationModifiers(modifiers)
1✔
5212
                                        // Anonymous types might not preserve their class file's final modifier via their inner class modifier.
5213
                                        | (((modifiers & Opcodes.ACC_FINAL) != 0 && instrumentedType.isAnonymousType()) ? Opcodes.ACC_FINAL : ModifierContributor.EMPTY_MASK)
1✔
5214
                                        | (instrumentedType.isModuleType() ? Opcodes.ACC_MODULE : ModifierContributor.EMPTY_MASK),
1✔
5215
                                instrumentedType.getInternalName(),
1✔
5216
                                TypeDescription.AbstractBase.RAW_TYPES
5217
                                        ? genericSignature
5218
                                        : instrumentedType.getGenericSignature(),
1✔
5219
                                instrumentedType.getSuperClass() == null
1✔
5220
                                        ? (instrumentedType.isInterface() ? TypeDescription.ForLoadedType.of(Object.class).getInternalName() : NO_REFERENCE)
1✔
5221
                                        : instrumentedType.getSuperClass().asErasure().getInternalName(),
1✔
5222
                                instrumentedType.getInterfaces().asErasures().toInternalNames());
1✔
5223
                    }
1✔
5224

5225
                    @Override
5226
                    @MaybeNull
5227
                    protected ModuleVisitor onVisitModule(String name, int modifiers, @MaybeNull String version) {
5228
                        onModule();
1✔
5229
                        return null;
1✔
5230
                    }
5231

5232
                    @Override
5233
                    protected void onModule() {
5234
                        ModuleDescription moduleDescription = instrumentedType.toModuleDescription();
1✔
5235
                        if (moduleDescription != null) {
1✔
5236
                            moduleDescription.accept(cv);
1✔
5237
                        }
5238
                    }
1✔
5239

5240
                    @Override
5241
                    protected void onVisitNestHost(String nestHost) {
5242
                        onNestHost();
×
5243
                    }
×
5244

5245
                    @Override
5246
                    protected void onNestHost() {
5247
                        if (!instrumentedType.isNestHost()) {
1✔
5248
                            cv.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
5249
                        }
5250
                    }
1✔
5251

5252
                    @Override
5253
                    protected void onVisitPermittedSubclass(String permittedSubclass) {
5254
                        if (permittedSubclasses != null && permittedSubclasses.remove(permittedSubclass)) {
×
5255
                            cv.visitPermittedSubclass(permittedSubclass);
×
5256
                        }
5257
                    }
×
5258

5259
                    @Override
5260
                    protected void onVisitOuterClass(String owner, @MaybeNull String name, @MaybeNull String descriptor) {
5261
                        try { // The Groovy compiler often gets this attribute wrong such that this safety just retains it.
5262
                            onOuterType();
×
5263
                        } catch (Throwable ignored) {
×
5264
                            cv.visitOuterClass(owner, name, descriptor);
×
5265
                        }
×
5266
                    }
×
5267

5268
                    @Override
5269
                    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "Relying on correlated type properties.")
5270
                    protected void onOuterType() {
5271
                        MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
1✔
5272
                        if (enclosingMethod != null) {
1✔
5273
                            cv.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
1✔
5274
                                    enclosingMethod.getInternalName(),
1✔
5275
                                    enclosingMethod.getDescriptor());
1✔
5276
                        } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
1✔
5277
                            cv.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
1✔
5278
                        }
5279
                    }
1✔
5280

5281
                    @Override
5282
                    protected void onAfterAttributes() {
5283
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5284
                    }
1✔
5285

5286
                    @Override
5287
                    @MaybeNull
5288
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5289
                        return annotationRetention.isEnabled()
1✔
5290
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
1✔
5291
                                : IGNORE_ANNOTATION;
×
5292
                    }
5293

5294
                    @Override
5295
                    @MaybeNull
5296
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5297
                        return annotationRetention.isEnabled()
1✔
5298
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5299
                                : IGNORE_ANNOTATION;
1✔
5300
                    }
5301

5302
                    @Override
5303
                    @MaybeNull
5304
                    protected RecordComponentVisitor onVisitRecordComponent(String name, String descriptor, @MaybeNull String genericSignature) {
5305
                        RecordComponentDescription recordComponentDescription = declarableRecordComponents.remove(name);
×
5306
                        if (recordComponentDescription != null) {
×
5307
                            RecordComponentPool.Record record = recordComponentPool.target(recordComponentDescription);
×
5308
                            if (!record.isImplicit()) {
×
5309
                                return redefine(record, genericSignature);
×
5310
                            }
5311
                        }
5312
                        return cv.visitRecordComponent(name, descriptor, genericSignature);
×
5313
                    }
5314

5315
                    /**
5316
                     * Redefines a record component using the given explicit record component pool record.
5317
                     *
5318
                     * @param record           The record component pool record to apply during visitation of the existing record.
5319
                     * @param genericSignature The record component's original generic signature which can be {@code null}.
5320
                     * @return A record component visitor for visiting the existing record component definition.
5321
                     */
5322
                    @MaybeNull
5323
                    protected RecordComponentVisitor redefine(RecordComponentPool.Record record, @MaybeNull String genericSignature) {
5324
                        RecordComponentDescription recordComponentDescription = record.getRecordComponent();
×
5325
                        RecordComponentVisitor recordComponentVisitor = cv.visitRecordComponent(recordComponentDescription.getActualName(),
×
5326
                                recordComponentDescription.getDescriptor(),
×
5327
                                TypeDescription.AbstractBase.RAW_TYPES
5328
                                        ? genericSignature
5329
                                        : recordComponentDescription.getGenericSignature());
×
5330
                        return recordComponentVisitor == null
×
5331
                                ? IGNORE_RECORD_COMPONENT
×
5332
                                : new AttributeObtainingRecordComponentVisitor(recordComponentVisitor, record);
5333
                    }
5334

5335
                    @Override
5336
                    @MaybeNull
5337
                    protected FieldVisitor onVisitField(int modifiers,
5338
                                                        String internalName,
5339
                                                        String descriptor,
5340
                                                        @MaybeNull String genericSignature,
5341
                                                        @MaybeNull Object value) {
5342
                        SignatureKey key = new SignatureKey(internalName, descriptor);
1✔
5343
                        fieldKeys.add(key);
1✔
5344
                        FieldDescription fieldDescription = declarableFields.remove(key);
1✔
5345
                        if (fieldDescription != null) {
1✔
5346
                            FieldPool.Record record = fieldPool.target(fieldDescription);
1✔
5347
                            if (!record.isImplicit()) {
1✔
5348
                                return redefine(record, value, modifiers, genericSignature);
1✔
5349
                            }
5350
                        }
5351
                        return cv.visitField(modifiers, internalName, descriptor, genericSignature, value);
1✔
5352
                    }
5353

5354
                    /**
5355
                     * Redefines a field using the given explicit field pool record and default value.
5356
                     *
5357
                     * @param record           The field pool value to apply during visitation of the existing field.
5358
                     * @param value            The default value to write onto the field which might be {@code null}.
5359
                     * @param modifiers        The original modifiers of the transformed field.
5360
                     * @param genericSignature The field's original generic signature which can be {@code null}.
5361
                     * @return A field visitor for visiting the existing field definition.
5362
                     */
5363
                    @MaybeNull
5364
                    protected FieldVisitor redefine(FieldPool.Record record, @MaybeNull Object value, int modifiers, @MaybeNull String genericSignature) {
5365
                        FieldDescription instrumentedField = record.getField();
1✔
5366
                        FieldVisitor fieldVisitor = cv.visitField(instrumentedField.getActualModifiers() | resolveDeprecationModifiers(modifiers),
1✔
5367
                                instrumentedField.getInternalName(),
1✔
5368
                                instrumentedField.getDescriptor(),
1✔
5369
                                TypeDescription.AbstractBase.RAW_TYPES
5370
                                        ? genericSignature
5371
                                        : instrumentedField.getGenericSignature(),
1✔
5372
                                record.resolveDefault(value));
1✔
5373
                        return fieldVisitor == null
1✔
5374
                                ? IGNORE_FIELD
1✔
5375
                                : new AttributeObtainingFieldVisitor(fieldVisitor, record);
5376
                    }
5377

5378
                    @Override
5379
                    @MaybeNull
5380
                    protected MethodVisitor onVisitMethod(int modifiers,
5381
                                                          String internalName,
5382
                                                          String descriptor,
5383
                                                          @MaybeNull String genericSignature,
5384
                                                          @MaybeNull String[] exceptionName) {
5385
                        if (internalName.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
5386
                            MethodVisitor methodVisitor = cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName);
1✔
5387
                            return methodVisitor == null
1✔
5388
                                    ? IGNORE_METHOD
1✔
5389
                                    : (MethodVisitor) (initializationHandler = InitializationHandler.Appending.of(implementationContext.isEnabled(),
1✔
5390
                                    methodVisitor,
5391
                                    instrumentedType,
5392
                                    methodPool,
5393
                                    annotationValueFilterFactory,
5394
                                    (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && implementationContext.getClassFileVersion().isAtLeast(ClassFileVersion.JAVA_V6),
1✔
5395
                                    (readerFlags & ClassReader.EXPAND_FRAMES) != 0));
5396
                        } else {
5397
                            SignatureKey key = new SignatureKey(internalName, descriptor);
1✔
5398
                            methodsKeys.add(key);
1✔
5399
                            MethodDescription methodDescription = declarableMethods.remove(key);
1✔
5400
                            return methodDescription == null
1✔
5401
                                    ? cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName)
1✔
5402
                                    : redefine(methodDescription, (modifiers & Opcodes.ACC_ABSTRACT) != 0, modifiers, genericSignature);
1✔
5403
                        }
5404
                    }
5405

5406
                    /**
5407
                     * Redefines a given method if this is required by looking up a potential implementation from the
5408
                     * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool}.
5409
                     *
5410
                     * @param methodDescription The method being considered for redefinition.
5411
                     * @param abstractOrigin    {@code true} if the original method is abstract, i.e. there is no implementation to preserve.
5412
                     * @param modifiers         The original modifiers of the transformed method.
5413
                     * @param genericSignature  The method's original generic signature which can be {@code null}.
5414
                     * @return A method visitor which is capable of consuming the original method.
5415
                     */
5416
                    @MaybeNull
5417
                    protected MethodVisitor redefine(MethodDescription methodDescription, boolean abstractOrigin, int modifiers, @MaybeNull String genericSignature) {
5418
                        MethodPool.Record record = methodPool.target(methodDescription);
1✔
5419
                        if (!record.getSort().isDefined()) {
1✔
5420
                            return cv.visitMethod(methodDescription.getActualModifiers() | resolveDeprecationModifiers(modifiers),
×
5421
                                    methodDescription.getInternalName(),
×
5422
                                    methodDescription.getDescriptor(),
×
5423
                                    TypeDescription.AbstractBase.RAW_TYPES
5424
                                            ? genericSignature
5425
                                            : methodDescription.getGenericSignature(),
×
5426
                                    methodDescription.getExceptionTypes().asErasures().toInternalNames());
×
5427
                        }
5428
                        MethodDescription implementedMethod = record.getMethod();
1✔
5429
                        MethodVisitor methodVisitor = cv.visitMethod(ModifierContributor.Resolver
1✔
5430
                                        .of(Collections.singleton(record.getVisibility()))
1✔
5431
                                        .resolve(implementedMethod.getActualModifiers(record.getSort().isImplemented())) | resolveDeprecationModifiers(modifiers),
1✔
5432
                                implementedMethod.getInternalName(),
1✔
5433
                                implementedMethod.getDescriptor(),
1✔
5434
                                TypeDescription.AbstractBase.RAW_TYPES
5435
                                        ? genericSignature
5436
                                        : implementedMethod.getGenericSignature(),
1✔
5437
                                implementedMethod.getExceptionTypes().asErasures().toInternalNames());
1✔
5438
                        if (methodVisitor == null) {
1✔
5439
                            return IGNORE_METHOD;
×
5440
                        } else if (abstractOrigin) {
1✔
5441
                            return new AttributeObtainingMethodVisitor(methodVisitor, record);
1✔
5442
                        } else if (methodDescription.isNative()) {
1✔
5443
                            MethodRebaseResolver.Resolution resolution = methodRebaseResolver.resolve(implementedMethod.asDefined());
×
5444
                            if (resolution.isRebased()) {
×
5445
                                MethodVisitor rebasedMethodVisitor = super.visitMethod(resolution.getResolvedMethod().getActualModifiers()
×
5446
                                                | resolveDeprecationModifiers(modifiers),
×
5447
                                        resolution.getResolvedMethod().getInternalName(),
×
5448
                                        resolution.getResolvedMethod().getDescriptor(),
×
5449
                                        TypeDescription.AbstractBase.RAW_TYPES
5450
                                                ? genericSignature
5451
                                                : implementedMethod.getGenericSignature(),
×
5452
                                        resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
×
5453
                                if (rebasedMethodVisitor != null) {
×
5454
                                    rebasedMethodVisitor.visitEnd();
×
5455
                                }
5456
                            }
5457
                            return new AttributeObtainingMethodVisitor(methodVisitor, record);
×
5458
                        } else {
5459
                            return new CodePreservingMethodVisitor(methodVisitor, record, methodRebaseResolver.resolve(implementedMethod.asDefined()));
1✔
5460
                        }
5461
                    }
5462

5463
                    @Override
5464
                    protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
5465
                        if (!internalName.equals(instrumentedType.getInternalName())) {
1✔
5466
                            TypeDescription declaredType = declaredTypes.remove(internalName);
1✔
5467
                            if (declaredType == null) {
1✔
5468
                                cv.visitInnerClass(internalName, outerName, innerName, modifiers);
1✔
5469
                            } else {
5470
                                cv.visitInnerClass(internalName,
1✔
5471
                                        // The second condition is added to retain the structure of some Java 6 compiled classes
5472
                                        declaredType.isMemberType() || outerName != null && innerName == null && declaredType.isAnonymousType()
1✔
5473
                                                ? instrumentedType.getInternalName()
1✔
5474
                                                : NO_REFERENCE,
1✔
5475
                                        declaredType.isAnonymousType()
1✔
5476
                                                ? NO_REFERENCE
1✔
5477
                                                : declaredType.getSimpleName(),
1✔
5478
                                        declaredType.getModifiers());
1✔
5479
                            }
5480
                        }
5481
                    }
1✔
5482

5483
                    @Override
5484
                    protected void onVisitNestMember(String nestMember) {
5485
                        if (instrumentedType.isNestHost() && nestMembers.remove(nestMember)) {
×
5486
                            cv.visitNestMember(nestMember);
×
5487
                        }
5488
                    }
×
5489

5490
                    @Override
5491
                    protected void onVisitEnd() {
5492
                        for (String nestMember : nestMembers) {
1✔
5493
                            cv.visitNestMember(nestMember);
×
5494
                        }
×
5495
                        if (permittedSubclasses != null) {
1✔
5496
                            for (String permittedSubclass : permittedSubclasses) {
×
5497
                                cv.visitPermittedSubclass(permittedSubclass);
×
5498
                            }
×
5499
                        }
5500
                        TypeDescription declaringType = instrumentedType.getDeclaringType();
1✔
5501
                        if (declaringType != null) {
1✔
5502
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5503
                                    declaringType.getInternalName(),
1✔
5504
                                    instrumentedType.getSimpleName(),
1✔
5505
                                    instrumentedType.getModifiers());
1✔
5506
                        } else if (instrumentedType.isLocalType()) {
1✔
5507
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5508
                                    NO_REFERENCE,
1✔
5509
                                    instrumentedType.getSimpleName(),
1✔
5510
                                    instrumentedType.getModifiers());
1✔
5511
                        } else if (instrumentedType.isAnonymousType()) {
1✔
5512
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5513
                                    NO_REFERENCE,
1✔
5514
                                    NO_REFERENCE,
1✔
5515
                                    instrumentedType.getModifiers());
1✔
5516
                        }
5517
                        for (TypeDescription typeDescription : declaredTypes.values()) {
1✔
5518
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
5519
                                    typeDescription.isMemberType()
×
5520
                                            ? instrumentedType.getInternalName()
×
5521
                                            : NO_REFERENCE,
×
5522
                                    typeDescription.isAnonymousType()
×
5523
                                            ? NO_REFERENCE
×
5524
                                            : typeDescription.getSimpleName(),
×
5525
                                    typeDescription.getModifiers());
×
5526
                        }
×
5527
                        for (RecordComponentDescription recordComponent : declarableRecordComponents.values()) {
1✔
5528
                            recordComponentPool.target(recordComponent).apply(cv, annotationValueFilterFactory);
×
5529
                        }
×
5530
                        for (FieldDescription fieldDescription : declarableFields.values()) {
1✔
5531
                            fieldPool.target(fieldDescription).apply(new DeduplicatingClassVisitor(cv), annotationValueFilterFactory);
1✔
5532
                        }
1✔
5533
                        for (MethodDescription methodDescription : declarableMethods.values()) {
1✔
5534
                            methodPool.target(methodDescription).apply(new DeduplicatingClassVisitor(cv),
1✔
5535
                                    implementationContext,
5536
                                    annotationValueFilterFactory);
5537
                        }
1✔
5538
                        initializationHandler.complete(cv, implementationContext);
1✔
5539
                        cv.visitEnd();
1✔
5540
                    }
1✔
5541

5542
                    /**
5543
                     * Returns {@link Opcodes#ACC_DEPRECATED} if the current class file version only represents deprecated methods using modifiers
5544
                     * that are not exposed in the type description API what is true for class files before Java 5 and if the supplied modifiers indicate
5545
                     * deprecation.
5546
                     *
5547
                     * @param modifiers The original modifiers.
5548
                     * @return {@link Opcodes#ACC_DEPRECATED} if the supplied modifiers imply deprecation.
5549
                     */
5550
                    private int resolveDeprecationModifiers(int modifiers) {
5551
                        return retainDeprecationModifiers && (modifiers & Opcodes.ACC_DEPRECATED) != 0
1✔
5552
                                ? Opcodes.ACC_DEPRECATED
5553
                                : ModifierContributor.EMPTY_MASK;
5554
                    }
5555

5556
                    /**
5557
                     * A class visitor that deduplicates fields and methods, mostly when access bridge methods are
5558
                     * previously declared, but incomplete.
5559
                     */
5560
                    protected class DeduplicatingClassVisitor extends ClassVisitor {
5561

5562
                        /**
5563
                         * Creates a new method deduplicating class visitor.
5564
                         *
5565
                         * @param classVisitor The class visitor to delegate to.
5566
                         */
5567
                        protected DeduplicatingClassVisitor(ClassVisitor classVisitor) {
1✔
5568
                            super(OpenedClassReader.ASM_API, classVisitor);
1✔
5569
                        }
1✔
5570

5571
                        @Override
5572
                        @MaybeNull
5573
                        public FieldVisitor visitField(int access,
5574
                                                       String internalName,
5575
                                                       String descriptor,
5576
                                                       @MaybeNull String signature,
5577
                                                       @MaybeNull Object value) {
5578
                            if (fieldKeys.contains(new SignatureKey(internalName, descriptor))) {
1✔
5579
                                throw new IllegalStateException("Field already defined: " + internalName + descriptor);
×
5580
                            }
5581
                            return super.visitField(access, internalName, descriptor, signature, value);
1✔
5582
                        }
5583

5584
                        @Override
5585
                        @MaybeNull
5586
                        public MethodVisitor visitMethod(int access,
5587
                                                         String internalName,
5588
                                                         String descriptor,
5589
                                                         @MaybeNull String signature,
5590
                                                         @MaybeNull String[] exception) {
5591
                            if (methodsKeys.contains(new SignatureKey(internalName, descriptor))) {
1✔
5592
                                if ((access & Opcodes.ACC_BRIDGE) != 0) {
×
5593
                                    return null;
×
5594
                                } else {
5595
                                    throw new IllegalStateException("Method already defined: " + internalName + descriptor);
×
5596
                                }
5597
                            }
5598
                            return super.visitMethod(access, internalName, descriptor, signature, exception);
1✔
5599
                        }
5600
                    }
5601

5602
                    /**
5603
                     * A field visitor that obtains all attributes and annotations of a field that is found in the
5604
                     * class file but that discards all code.
5605
                     */
5606
                    protected class AttributeObtainingFieldVisitor extends FieldVisitor {
5607

5608
                        /**
5609
                         * The field pool record to apply onto the field visitor.
5610
                         */
5611
                        private final FieldPool.Record record;
5612

5613
                        /**
5614
                         * Creates a new attribute obtaining field visitor.
5615
                         *
5616
                         * @param fieldVisitor The field visitor to delegate to.
5617
                         * @param record       The field pool record to apply onto the field visitor.
5618
                         */
5619
                        protected AttributeObtainingFieldVisitor(FieldVisitor fieldVisitor, FieldPool.Record record) {
1✔
5620
                            super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
5621
                            this.record = record;
1✔
5622
                        }
1✔
5623

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

5632
                        @Override
5633
                        @MaybeNull
5634
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5635
                            return annotationRetention.isEnabled()
1✔
5636
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5637
                                    : IGNORE_ANNOTATION;
1✔
5638
                        }
5639

5640
                        @Override
5641
                        public void visitEnd() {
5642
                            record.apply(fv, annotationValueFilterFactory);
1✔
5643
                            super.visitEnd();
1✔
5644
                        }
1✔
5645
                    }
5646

5647
                    /**
5648
                     * A record component visitor that obtains all attributes and annotations of a record component that is found
5649
                     * in the class file but discards all code.
5650
                     */
5651
                    protected class AttributeObtainingRecordComponentVisitor extends RecordComponentVisitor {
5652

5653
                        /**
5654
                         * The record component pool record to apply onto the record component visitor.
5655
                         */
5656
                        private final RecordComponentPool.Record record;
5657

5658
                        /**
5659
                         * Creates a new attribute obtaining record component visitor.
5660
                         *
5661
                         * @param recordComponentVisitor The record component visitor to delegate to.
5662
                         * @param record                 The record component pool record to apply onto the record component visitor.
5663
                         */
5664
                        protected AttributeObtainingRecordComponentVisitor(RecordComponentVisitor recordComponentVisitor, RecordComponentPool.Record record) {
×
5665
                            super(OpenedClassReader.ASM_API, recordComponentVisitor);
×
5666
                            this.record = record;
×
5667
                        }
×
5668

5669
                        @Override
5670
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5671
                            return annotationRetention.isEnabled()
×
5672
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5673
                                    : IGNORE_ANNOTATION;
×
5674
                        }
5675

5676
                        @Override
5677
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5678
                            return annotationRetention.isEnabled()
×
5679
                                    ? super.visitAnnotation(descriptor, visible)
×
5680
                                    : IGNORE_ANNOTATION;
×
5681
                        }
5682

5683
                        @Override
5684
                        public void visitEnd() {
5685
                            record.apply(getDelegate(), annotationValueFilterFactory);
×
5686
                            super.visitEnd();
×
5687
                        }
×
5688
                    }
5689

5690
                    /**
5691
                     * A method visitor that preserves the code of a method in the class file by copying it into a rebased
5692
                     * method while copying all attributes and annotations to the actual method.
5693
                     */
5694
                    protected class CodePreservingMethodVisitor extends MethodVisitor {
5695

5696
                        /**
5697
                         * The method visitor of the actual method.
5698
                         */
5699
                        private final MethodVisitor actualMethodVisitor;
5700

5701
                        /**
5702
                         * The method pool entry to apply.
5703
                         */
5704
                        private final MethodPool.Record record;
5705

5706
                        /**
5707
                         * The resolution of a potential rebased method.
5708
                         */
5709
                        private final MethodRebaseResolver.Resolution resolution;
5710

5711
                        /**
5712
                         * Creates a new code preserving method visitor.
5713
                         *
5714
                         * @param actualMethodVisitor The method visitor of the actual method.
5715
                         * @param record              The method pool entry to apply.
5716
                         * @param resolution          The resolution of the method rebase resolver in use.
5717
                         */
5718
                        protected CodePreservingMethodVisitor(MethodVisitor actualMethodVisitor,
5719
                                                              MethodPool.Record record,
5720
                                                              MethodRebaseResolver.Resolution resolution) {
1✔
5721
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5722
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5723
                            this.record = record;
1✔
5724
                            this.resolution = resolution;
1✔
5725
                            record.applyHead(actualMethodVisitor);
1✔
5726
                        }
1✔
5727

5728
                        @Override
5729
                        @MaybeNull
5730
                        public AnnotationVisitor visitAnnotationDefault() {
5731
                            return IGNORE_ANNOTATION; // Annotation types can never be rebased.
×
5732
                        }
5733

5734
                        @Override
5735
                        @MaybeNull
5736
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5737
                            return annotationRetention.isEnabled()
×
5738
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5739
                                    : IGNORE_ANNOTATION;
×
5740
                        }
5741

5742
                        @Override
5743
                        @MaybeNull
5744
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5745
                            return annotationRetention.isEnabled()
1✔
5746
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5747
                                    : IGNORE_ANNOTATION;
1✔
5748
                        }
5749

5750
                        @Override
5751
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5752
                            if (annotationRetention.isEnabled()) {
1✔
5753
                                super.visitAnnotableParameterCount(count, visible);
1✔
5754
                            }
5755
                        }
1✔
5756

5757
                        @Override
5758
                        @MaybeNull
5759
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5760
                            return annotationRetention.isEnabled()
1✔
5761
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
1✔
5762
                                    : IGNORE_ANNOTATION;
1✔
5763
                        }
5764

5765
                        @Override
5766
                        public void visitCode() {
5767
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5768
                            actualMethodVisitor.visitEnd();
1✔
5769
                            if (resolution.isRebased()) {
1✔
5770
                                mv = cv.visitMethod(resolution.getResolvedMethod().getActualModifiers(),
1✔
5771
                                        resolution.getResolvedMethod().getInternalName(),
1✔
5772
                                        resolution.getResolvedMethod().getDescriptor(),
1✔
5773
                                        resolution.getResolvedMethod().getGenericSignature(),
1✔
5774
                                        resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
1✔
5775
                                super.visitCode();
1✔
5776
                                if (!resolution.getAppendedParameters().isEmpty() && implementationContext.getFrameGeneration().isActive()) {
1✔
5777
                                    if (implementationContext.getFrameGeneration() == Implementation.Context.FrameGeneration.GENERATE && resolution.getAppendedParameters().size() < 4) {
1✔
5778
                                        super.visitFrame(Opcodes.F_CHOP, resolution.getAppendedParameters().size(), EMPTY, EMPTY.length, EMPTY);
1✔
5779
                                    } else {
5780
                                        Object[] frame = new Object[resolution.getResolvedMethod().getParameters().size()
1✔
5781
                                                - resolution.getAppendedParameters().size()
1✔
5782
                                                + 1];
5783
                                        frame[0] = Opcodes.UNINITIALIZED_THIS;
1✔
5784
                                        for (int index = 1; index < frame.length; index++) {
1✔
5785
                                            TypeDefinition typeDefinition = resolution.getResolvedMethod()
1✔
5786
                                                    .getParameters()
1✔
5787
                                                    .get(index - 1)
1✔
5788
                                                    .getType();
1✔
5789
                                            if (typeDefinition.represents(boolean.class)
1✔
5790
                                                    || typeDefinition.represents(byte.class)
1✔
5791
                                                    || typeDefinition.represents(short.class)
1✔
5792
                                                    || typeDefinition.represents(char.class)
1✔
5793
                                                    || typeDefinition.represents(int.class)) {
1✔
5794
                                                frame[index] = Opcodes.INTEGER;
×
5795
                                            } else if (typeDefinition.represents(long.class)) {
1✔
5796
                                                frame[index] = Opcodes.LONG;
×
5797
                                            } else if (typeDefinition.represents(float.class)) {
1✔
5798
                                                frame[index] = Opcodes.FLOAT;
×
5799
                                            } else if (typeDefinition.represents(double.class)) {
1✔
5800
                                                frame[index] = Opcodes.DOUBLE;
×
5801
                                            } else {
5802
                                                frame[index] = typeDefinition.asErasure().getInternalName();
1✔
5803
                                            }
5804
                                        }
5805
                                        super.visitFrame((readerFlags & ClassReader.EXPAND_FRAMES) == 0
1✔
5806
                                                ? Opcodes.F_FULL
5807
                                                : Opcodes.F_NEW, frame.length, frame, EMPTY.length, EMPTY);
1✔
5808
                                    }
5809
                                    super.visitInsn(Opcodes.NOP);
1✔
5810
                                }
5811
                            } else {
5812
                                mv = IGNORE_METHOD;
1✔
5813
                                super.visitCode();
1✔
5814
                            }
5815
                        }
1✔
5816

5817
                        @Override
5818
                        public void visitMaxs(int stackSize, int localVariableLength) {
5819
                            super.visitMaxs(stackSize, Math.max(localVariableLength, resolution.getResolvedMethod().getStackSize()));
1✔
5820
                        }
1✔
5821
                    }
5822

5823
                    /**
5824
                     * A method visitor that obtains all attributes and annotations of a method that is found in the
5825
                     * class file but that discards all code.
5826
                     */
5827
                    protected class AttributeObtainingMethodVisitor extends MethodVisitor {
5828

5829
                        /**
5830
                         * The method visitor to which the actual method is to be written to.
5831
                         */
5832
                        private final MethodVisitor actualMethodVisitor;
5833

5834
                        /**
5835
                         * The method pool entry to apply.
5836
                         */
5837
                        private final MethodPool.Record record;
5838

5839
                        /**
5840
                         * Creates a new attribute obtaining method visitor.
5841
                         *
5842
                         * @param actualMethodVisitor The method visitor of the actual method.
5843
                         * @param record              The method pool entry to apply.
5844
                         */
5845
                        protected AttributeObtainingMethodVisitor(MethodVisitor actualMethodVisitor, MethodPool.Record record) {
1✔
5846
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5847
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5848
                            this.record = record;
1✔
5849
                            record.applyHead(actualMethodVisitor);
1✔
5850
                        }
1✔
5851

5852
                        @Override
5853
                        @MaybeNull
5854
                        public AnnotationVisitor visitAnnotationDefault() {
5855
                            return IGNORE_ANNOTATION;
×
5856
                        }
5857

5858
                        @Override
5859
                        @MaybeNull
5860
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5861
                            return annotationRetention.isEnabled()
×
5862
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5863
                                    : IGNORE_ANNOTATION;
×
5864
                        }
5865

5866
                        @Override
5867
                        @MaybeNull
5868
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5869
                            return annotationRetention.isEnabled()
×
5870
                                    ? super.visitAnnotation(descriptor, visible)
×
5871
                                    : IGNORE_ANNOTATION;
×
5872
                        }
5873

5874
                        @Override
5875
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5876
                            if (annotationRetention.isEnabled()) {
×
5877
                                super.visitAnnotableParameterCount(count, visible);
×
5878
                            }
5879
                        }
×
5880

5881
                        @Override
5882
                        @MaybeNull
5883
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5884
                            return annotationRetention.isEnabled()
×
5885
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
×
5886
                                    : IGNORE_ANNOTATION;
×
5887
                        }
5888

5889
                        @Override
5890
                        public void visitCode() {
5891
                            mv = IGNORE_METHOD;
×
5892
                        }
×
5893

5894
                        @Override
5895
                        public void visitEnd() {
5896
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5897
                            actualMethodVisitor.visitEnd();
1✔
5898
                        }
1✔
5899
                    }
5900
                }
5901
            }
5902

5903
            /**
5904
             * A default type writer that only applies a type decoration.
5905
             *
5906
             * @param <V> The best known loaded type for the dynamically created type.
5907
             */
5908
            protected static class WithDecorationOnly<V> extends ForInlining<V> {
5909

5910
                /**
5911
                 * Creates a new inlining type writer that only applies a decoration.
5912
                 *
5913
                 * @param instrumentedType             The instrumented type to be created.
5914
                 * @param classFileVersion             The class file specified by the user.
5915
                 * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
5916
                 * @param methods                      The instrumented type's declared and virtually inherited methods.
5917
                 * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
5918
                 * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
5919
                 * @param annotationValueFilterFactory The annotation value filter factory to apply.
5920
                 * @param annotationRetention          The annotation retention to apply.
5921
                 * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
5922
                 * @param implementationContextFactory The implementation context factory to apply.
5923
                 * @param typeValidation               Determines if a type should be explicitly validated.
5924
                 * @param classReaderFactory           The class reader factory to use.
5925
                 * @param classWriterFactory           The class writer factory to use.
5926
                 * @param typePool                     The type pool to use for computing stack map frames, if required.
5927
                 * @param classFileLocator             The class file locator for locating the original type's class file.
5928
                 */
5929
                protected WithDecorationOnly(TypeDescription instrumentedType,
5930
                                             ClassFileVersion classFileVersion,
5931
                                             List<? extends DynamicType> auxiliaryTypes,
5932
                                             MethodList<?> methods,
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
                                             ClassFileLocator classFileLocator) {
5944
                    super(instrumentedType,
1✔
5945
                            classFileVersion,
5946
                            FieldPool.Disabled.INSTANCE,
5947
                            RecordComponentPool.Disabled.INSTANCE,
5948
                            auxiliaryTypes,
5949
                            new LazyFieldList(instrumentedType),
5950
                            methods,
5951
                            new MethodList.Empty<MethodDescription>(),
5952
                            new RecordComponentList.Empty<RecordComponentDescription.InDefinedShape>(),
5953
                            LoadedTypeInitializer.NoOp.INSTANCE,
5954
                            TypeInitializer.None.INSTANCE,
5955
                            typeAttributeAppender,
5956
                            asmVisitorWrapper,
5957
                            annotationValueFilterFactory,
5958
                            annotationRetention,
5959
                            auxiliaryTypeNamingStrategy,
5960
                            implementationContextFactory,
5961
                            typeValidation,
5962
                            classReaderFactory,
5963
                            classWriterFactory,
5964
                            typePool,
5965
                            instrumentedType,
5966
                            classFileLocator);
5967
                }
1✔
5968

5969
                /**
5970
                 * {@inheritDoc}
5971
                 */
5972
                protected ClassVisitor writeTo(ClassVisitor classVisitor,
5973
                                               TypeInitializer typeInitializer,
5974
                                               ContextRegistry contextRegistry,
5975
                                               int writerFlags,
5976
                                               int readerFlags) {
5977
                    if (typeInitializer.isDefined()) {
1✔
5978
                        throw new UnsupportedOperationException("Cannot apply a type initializer for a decoration");
×
5979
                    }
5980
                    return new DecorationClassVisitor(classVisitor, contextRegistry, writerFlags, readerFlags);
1✔
5981
                }
5982

5983
                /**
5984
                 * A field list that only reads fields lazy to avoid an eager lookup since fields are often not required.
5985
                 */
5986
                protected static class LazyFieldList extends FieldList.AbstractBase<FieldDescription.InDefinedShape> {
5987

5988
                    /**
5989
                     * The instrumented type.
5990
                     */
5991
                    private final TypeDescription instrumentedType;
5992

5993
                    /**
5994
                     * Creates a lazy field list.
5995
                     *
5996
                     * @param instrumentedType The instrumented type.
5997
                     */
5998
                    protected LazyFieldList(TypeDescription instrumentedType) {
1✔
5999
                        this.instrumentedType = instrumentedType;
1✔
6000
                    }
1✔
6001

6002
                    /**
6003
                     * {@inheritDoc}
6004
                     */
6005
                    public FieldDescription.InDefinedShape get(int index) {
6006
                        return instrumentedType.getDeclaredFields().get(index);
×
6007
                    }
6008

6009
                    /**
6010
                     * {@inheritDoc}
6011
                     */
6012
                    public int size() {
6013
                        return instrumentedType.getDeclaredFields().size();
×
6014
                    }
6015
                }
6016

6017
                /**
6018
                 * A class visitor that decorates an existing type.
6019
                 */
6020
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
6021
                protected class DecorationClassVisitor extends MetadataAwareClassVisitor implements TypeInitializer.Drain {
6022

6023
                    /**
6024
                     * A context registry to register the lazily created implementation context to.
6025
                     */
6026
                    private final ContextRegistry contextRegistry;
6027

6028
                    /**
6029
                     * The writer flags being used.
6030
                     */
6031
                    private final int writerFlags;
6032

6033
                    /**
6034
                     * The reader flags being used.
6035
                     */
6036
                    private final int readerFlags;
6037

6038
                    /**
6039
                     * The implementation context to use or {@code null} if the context is not yet initialized.
6040
                     */
6041
                    @UnknownNull
6042
                    private Implementation.Context.ExtractableView implementationContext;
6043

6044
                    /**
6045
                     * Creates a class visitor which is capable of decorating an existent class on the fly.
6046
                     *
6047
                     * @param classVisitor    The underlying class visitor to which writes are delegated.
6048
                     * @param contextRegistry A context registry to register the lazily created implementation context to.
6049
                     * @param writerFlags     The writer flags being used.
6050
                     * @param readerFlags     The reader flags being used.
6051
                     */
6052
                    protected DecorationClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
1✔
6053
                        super(OpenedClassReader.ASM_API, classVisitor);
1✔
6054
                        this.contextRegistry = contextRegistry;
1✔
6055
                        this.writerFlags = writerFlags;
1✔
6056
                        this.readerFlags = readerFlags;
1✔
6057
                    }
1✔
6058

6059
                    @Override
6060
                    public void visit(int classFileVersionNumber,
6061
                                      int modifiers,
6062
                                      String internalName,
6063
                                      String genericSignature,
6064
                                      String superClassInternalName,
6065
                                      String[] interfaceTypeInternalName) {
6066
                        ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
1✔
6067
                        implementationContext = implementationContextFactory.make(instrumentedType,
1✔
6068
                                auxiliaryTypeNamingStrategy,
6069
                                typeInitializer,
6070
                                classFileVersion,
6071
                                WithDecorationOnly.this.classFileVersion,
6072
                                (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
6073
                                        ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
6074
                                        : Implementation.Context.FrameGeneration.DISABLED);
6075
                        contextRegistry.setImplementationContext(implementationContext);
1✔
6076
                        cv = asmVisitorWrapper.wrap(instrumentedType,
1✔
6077
                                cv,
6078
                                implementationContext,
6079
                                typePool,
6080
                                fields,
6081
                                methods,
6082
                                writerFlags,
6083
                                readerFlags);
6084
                        cv.visit(classFileVersionNumber, modifiers, internalName, genericSignature, superClassInternalName, interfaceTypeInternalName);
1✔
6085
                    }
1✔
6086

6087
                    @Override
6088
                    @MaybeNull
6089
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
6090
                        return annotationRetention.isEnabled()
×
6091
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
6092
                                : IGNORE_ANNOTATION;
×
6093
                    }
6094

6095
                    @Override
6096
                    @MaybeNull
6097
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
6098
                        return annotationRetention.isEnabled()
1✔
6099
                                ? cv.visitAnnotation(descriptor, visible)
1✔
6100
                                : IGNORE_ANNOTATION;
1✔
6101
                    }
6102

6103
                    @Override
6104
                    protected void onAfterAttributes() {
6105
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6106
                    }
1✔
6107

6108
                    @Override
6109
                    protected void onVisitEnd() {
6110
                        implementationContext.drain(this, cv, annotationValueFilterFactory);
1✔
6111
                        cv.visitEnd();
1✔
6112
                    }
1✔
6113

6114
                    /**
6115
                     * {@inheritDoc}
6116
                     */
6117
                    public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
6118
                        /* do nothing */
6119
                    }
1✔
6120
                }
6121
            }
6122
        }
6123

6124
        /**
6125
         * A type writer that creates a class file that is not based upon another, existing class.
6126
         *
6127
         * @param <U> The best known loaded type for the dynamically created type.
6128
         */
6129
        @HashCodeAndEqualsPlugin.Enhance
6130
        public static class ForCreation<U> extends Default<U> {
6131

6132
            /**
6133
             * The method pool to use.
6134
             */
6135
            private final MethodPool methodPool;
6136

6137
            /**
6138
             * Creates a new default type writer for creating a new type that is not based on an existing class file.
6139
             *
6140
             * @param instrumentedType             The instrumented type to be created.
6141
             * @param classFileVersion             The class file version to write the instrumented type in and to apply when creating auxiliary types.
6142
             * @param fieldPool                    The field pool to use.
6143
             * @param methodPool                   The method pool to use.
6144
             * @param recordComponentPool          The record component pool to use.
6145
             * @param auxiliaryTypes               A list of auxiliary types to add to the created type.
6146
             * @param fields                       The instrumented type's declared fields.
6147
             * @param methods                      The instrumented type's declared and virtually inherited methods.
6148
             * @param instrumentedMethods          The instrumented methods relevant to this type creation.
6149
             * @param recordComponents             The instrumented type's record components.
6150
             * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
6151
             * @param typeInitializer              The type initializer to include in the created type's type initializer.
6152
             * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
6153
             * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
6154
             * @param annotationValueFilterFactory The annotation value filter factory to apply.
6155
             * @param annotationRetention          The annotation retention to apply.
6156
             * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
6157
             * @param implementationContextFactory The implementation context factory to apply.
6158
             * @param typeValidation               Determines if a type should be explicitly validated.
6159
             * @param classReaderFactory           The class reader factory to use.
6160
             * @param classWriterFactory           The class writer factory to use.
6161
             * @param typePool                     The type pool to use for computing stack map frames, if required.
6162
             */
6163
            protected ForCreation(TypeDescription instrumentedType,
6164
                                  ClassFileVersion classFileVersion,
6165
                                  FieldPool fieldPool,
6166
                                  MethodPool methodPool,
6167
                                  RecordComponentPool recordComponentPool,
6168
                                  List<? extends DynamicType> auxiliaryTypes,
6169
                                  FieldList<FieldDescription.InDefinedShape> fields,
6170
                                  MethodList<?> methods,
6171
                                  MethodList<?> instrumentedMethods,
6172
                                  RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
6173
                                  LoadedTypeInitializer loadedTypeInitializer,
6174
                                  TypeInitializer typeInitializer,
6175
                                  TypeAttributeAppender typeAttributeAppender,
6176
                                  AsmVisitorWrapper asmVisitorWrapper,
6177
                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
6178
                                  AnnotationRetention annotationRetention,
6179
                                  AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
6180
                                  Implementation.Context.Factory implementationContextFactory,
6181
                                  TypeValidation typeValidation,
6182
                                  AsmClassReader.Factory classReaderFactory,
6183
                                  AsmClassWriter.Factory classWriterFactory,
6184
                                  TypePool typePool) {
6185
                super(instrumentedType,
1✔
6186
                        classFileVersion,
6187
                        fieldPool,
6188
                        recordComponentPool,
6189
                        auxiliaryTypes,
6190
                        fields,
6191
                        methods,
6192
                        instrumentedMethods,
6193
                        recordComponents,
6194
                        loadedTypeInitializer,
6195
                        typeInitializer,
6196
                        typeAttributeAppender,
6197
                        asmVisitorWrapper,
6198
                        annotationValueFilterFactory,
6199
                        annotationRetention,
6200
                        auxiliaryTypeNamingStrategy,
6201
                        implementationContextFactory,
6202
                        typeValidation,
6203
                        classReaderFactory,
6204
                        classWriterFactory,
6205
                        typePool);
6206
                this.methodPool = methodPool;
1✔
6207
            }
1✔
6208

6209
            /**
6210
             * {@inheritDoc}
6211
             */
6212
            public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags) {
6213
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
6214
                        auxiliaryTypeNamingStrategy,
6215
                        typeInitializer,
6216
                        classFileVersion,
6217
                        classFileVersion,
6218
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
6219
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
6220
                                : Implementation.Context.FrameGeneration.DISABLED);
6221
                return new ImplementationContextClassVisitor(new CreationClassVisitor(asmVisitorWrapper.wrap(instrumentedType,
1✔
6222
                        ValidatingClassVisitor.of(classVisitor, typeValidation),
1✔
6223
                        implementationContext,
6224
                        typePool,
6225
                        fields,
6226
                        methods,
6227
                        asmVisitorWrapper.mergeWriter(writerFlags),
1✔
6228
                        asmVisitorWrapper.mergeReader(readerFlags)), implementationContext, instrumentedType.toModuleDescription()), implementationContext);
1✔
6229
            }
6230

6231
            @Override
6232
            @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Relying on correlated type properties.")
6233
            protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
6234
                int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS), readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
1✔
6235
                AsmClassWriter classWriter = classWriterFactory.make(writerFlags, typePool);
1✔
6236
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
6237
                        auxiliaryTypeNamingStrategy,
6238
                        typeInitializer,
6239
                        classFileVersion,
6240
                        classFileVersion,
6241
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
6242
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
6243
                                : Implementation.Context.FrameGeneration.DISABLED);
6244
                ClassVisitor classVisitor = asmVisitorWrapper.wrap(instrumentedType,
1✔
6245
                        ValidatingClassVisitor.of(classWriter.getVisitor(), typeValidation),
1✔
6246
                        implementationContext,
6247
                        typePool,
6248
                        fields,
6249
                        methods,
6250
                        writerFlags,
6251
                        readerFlags);
6252
                classVisitor.visit(classFileVersion.getMinorMajorVersion(),
1✔
6253
                        instrumentedType.getActualModifiers(!instrumentedType.isInterface()),
1✔
6254
                        instrumentedType.getInternalName(),
1✔
6255
                        instrumentedType.getGenericSignature(),
1✔
6256
                        instrumentedType.getName().equals(ModuleDescription.MODULE_CLASS_NAME) ? null : (instrumentedType.getSuperClass() == null
1✔
6257
                                ? TypeDescription.ForLoadedType.of(Object.class)
1✔
6258
                                : instrumentedType.getSuperClass().asErasure()).getInternalName(),
1✔
6259
                        instrumentedType.getInterfaces().asErasures().toInternalNames());
1✔
6260
                ModuleDescription moduleDescription = instrumentedType.toModuleDescription();
1✔
6261
                if (moduleDescription != null) {
1✔
6262
                    moduleDescription.accept(classVisitor);
1✔
6263
                }
6264
                if (!instrumentedType.isNestHost()) {
1✔
6265
                    classVisitor.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
6266
                }
6267
                MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
1✔
6268
                if (enclosingMethod != null) {
1✔
6269
                    classVisitor.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
1✔
6270
                            enclosingMethod.getInternalName(),
1✔
6271
                            enclosingMethod.getDescriptor());
1✔
6272
                } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
1✔
6273
                    classVisitor.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
1✔
6274
                }
6275
                typeAttributeAppender.apply(classVisitor, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6276
                if (instrumentedType.isNestHost()) {
1✔
6277
                    for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
1✔
6278
                        classVisitor.visitNestMember(typeDescription.getInternalName());
×
6279
                    }
×
6280
                }
6281
                for (TypeDescription typeDescription : instrumentedType.getPermittedSubtypes()) {
1✔
6282
                    classVisitor.visitPermittedSubclass(typeDescription.getInternalName());
×
6283
                }
×
6284
                TypeDescription declaringType = instrumentedType.getDeclaringType();
1✔
6285
                if (declaringType != null) {
1✔
6286
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6287
                            declaringType.getInternalName(),
1✔
6288
                            instrumentedType.getSimpleName(),
1✔
6289
                            instrumentedType.getModifiers());
1✔
6290
                } else if (instrumentedType.isLocalType()) {
1✔
6291
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6292
                            NO_REFERENCE,
1✔
6293
                            instrumentedType.getSimpleName(),
1✔
6294
                            instrumentedType.getModifiers());
1✔
6295
                } else if (instrumentedType.isAnonymousType()) {
1✔
6296
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6297
                            NO_REFERENCE,
1✔
6298
                            NO_REFERENCE,
1✔
6299
                            instrumentedType.getModifiers());
1✔
6300
                }
6301
                for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6302
                    classVisitor.visitInnerClass(typeDescription.getInternalName(),
1✔
6303
                            typeDescription.isMemberType()
1✔
6304
                                    ? instrumentedType.getInternalName()
1✔
6305
                                    : NO_REFERENCE,
1✔
6306
                            typeDescription.isAnonymousType()
1✔
6307
                                    ? NO_REFERENCE
1✔
6308
                                    : typeDescription.getSimpleName(),
1✔
6309
                            typeDescription.getModifiers());
1✔
6310
                }
1✔
6311
                for (RecordComponentDescription recordComponentDescription : recordComponents) {
1✔
6312
                    recordComponentPool.target(recordComponentDescription).apply(classVisitor, annotationValueFilterFactory);
×
6313
                }
×
6314
                for (FieldDescription fieldDescription : fields) {
1✔
6315
                    fieldPool.target(fieldDescription).apply(classVisitor, annotationValueFilterFactory);
1✔
6316
                }
1✔
6317
                for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6318
                    methodPool.target(methodDescription).apply(classVisitor, implementationContext, annotationValueFilterFactory);
1✔
6319
                }
1✔
6320
                implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6321
                        methodPool,
6322
                        annotationValueFilterFactory), classVisitor, annotationValueFilterFactory);
6323
                classVisitor.visitEnd();
1✔
6324
                return new UnresolvedType(classWriter.getBinaryRepresentation(), implementationContext.getAuxiliaryTypes());
1✔
6325
            }
6326

6327
            /**
6328
             * A class visitor that applies the subclass creation as a wrapper.
6329
             */
6330
            protected class CreationClassVisitor extends MetadataAwareClassVisitor {
6331

6332
                /**
6333
                 * The implementation context to apply.
6334
                 */
6335
                private final Implementation.Context.ExtractableView implementationContext;
6336

6337
                /**
6338
                 * The underlying module information or {@code null} if no such information is provided.
6339
                 */
6340
                @MaybeNull
6341
                private final ModuleDescription moduleDescription;
6342

6343
                /**
6344
                 * The declared types that have been visited.
6345
                 */
6346
                private final Set<String> declaredTypes = new HashSet<String>();
1✔
6347

6348
                /**
6349
                 * The signatures of all fields that were explicitly visited.
6350
                 */
6351
                private final Set<SignatureKey> visitedFields = new HashSet<SignatureKey>();
1✔
6352

6353
                /**
6354
                 * The signature of all methods that were explicitly visited.
6355
                 */
6356
                private final Set<SignatureKey> visitedMethods = new HashSet<SignatureKey>();
1✔
6357

6358
                /**
6359
                 * Creates a new wrapper visitor.
6360
                 *
6361
                 * @param classVisitor          The class visitor being wrapped.
6362
                 * @param implementationContext The implementation context to apply.
6363
                 * @param moduleDescription     The underlying module information or {@code null} if no such information is provided.
6364
                 */
6365
                protected CreationClassVisitor(ClassVisitor classVisitor,
6366
                                               Implementation.Context.ExtractableView implementationContext,
6367
                                               @MaybeNull ModuleDescription moduleDescription) {
1✔
6368
                    super(OpenedClassReader.ASM_API, classVisitor);
1✔
6369
                    this.implementationContext = implementationContext;
1✔
6370
                    this.moduleDescription = moduleDescription;
1✔
6371
                }
1✔
6372

6373
                @Override
6374
                protected void onModule() {
6375
                    if (moduleDescription != null) {
1✔
6376
                        moduleDescription.accept(cv);
×
6377
                    }
6378
                }
1✔
6379

6380
                @Override
6381
                @MaybeNull
6382
                protected ModuleVisitor onVisitModule(String name, int modifiers, @MaybeNull String version) {
6383
                    return moduleDescription == null ? null : new PatchingModuleVisitor(cv.visitModule(moduleDescription.getActualName(),
×
6384
                            moduleDescription.getModifiers(),
×
6385
                            moduleDescription.getVersion()), moduleDescription);
×
6386
                }
6387

6388
                @Override
6389
                protected void onAfterAttributes() {
6390
                    typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6391
                }
1✔
6392

6393
                @Override
6394
                protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
6395
                    declaredTypes.add(internalName);
×
6396
                    super.onVisitInnerClass(internalName, outerName, innerName, modifiers);
×
6397
                }
×
6398

6399
                @Override
6400
                @MaybeNull
6401
                protected FieldVisitor onVisitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
6402
                    visitedFields.add(new SignatureKey(name, descriptor));
×
6403
                    return super.onVisitField(modifiers, name, descriptor, signature, value);
×
6404
                }
6405

6406
                @Override
6407
                @MaybeNull
6408
                protected MethodVisitor onVisitMethod(int modifiers, String internalName, String descriptor, @MaybeNull String signature, @MaybeNull String[] exception) {
6409
                    visitedMethods.add(new SignatureKey(internalName, descriptor));
×
6410
                    return super.onVisitMethod(modifiers, internalName, descriptor, signature, exception);
×
6411
                }
6412

6413
                @Override
6414
                protected void onVisitEnd() {
6415
                    for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6416
                        if (!declaredTypes.contains(typeDescription.getInternalName())) {
×
6417
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
6418
                                    typeDescription.isMemberType()
×
6419
                                            ? instrumentedType.getInternalName()
×
6420
                                            : NO_REFERENCE,
×
6421
                                    typeDescription.isAnonymousType()
×
6422
                                            ? NO_REFERENCE
×
6423
                                            : typeDescription.getSimpleName(),
×
6424
                                    typeDescription.getModifiers());
×
6425
                        }
6426
                    }
×
6427
                    for (FieldDescription fieldDescription : fields) {
1✔
6428
                        if (!visitedFields.contains(new SignatureKey(fieldDescription.getName(), fieldDescription.getDescriptor()))) {
×
6429
                            fieldPool.target(fieldDescription).apply(cv, annotationValueFilterFactory);
×
6430
                        }
6431
                    }
×
6432
                    for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6433
                        if (!visitedMethods.contains(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()))) {
1✔
6434
                            methodPool.target(methodDescription).apply(cv, implementationContext, annotationValueFilterFactory);
1✔
6435
                        }
6436
                    }
1✔
6437
                    implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6438
                            methodPool,
1✔
6439
                            annotationValueFilterFactory), cv, annotationValueFilterFactory);
6440
                    super.onVisitEnd();
1✔
6441
                }
1✔
6442
            }
6443

6444
            /**
6445
             * A class visitor that applies the subclass creation as a wrapper.
6446
             */
6447
            protected static class PatchingModuleVisitor extends ModuleVisitor {
6448

6449
                /**
6450
                 * The internal name of the main class or {@code null} if no main class is defined.
6451
                 */
6452
                @MaybeNull
6453
                private String mainClass;
6454

6455
                /**
6456
                 * The internal name of all packages of the module.
6457
                 */
6458
                private final Set<String> packages;
6459

6460
                /**
6461
                 * A mapping of required modules to their configuration.
6462
                 */
6463
                private final Map<String, ModuleDescription.Requires> requires;
6464

6465
                /**
6466
                 * A mapping of the internal names of exported packages to their configuration.
6467
                 */
6468
                private final Map<String, ModuleDescription.Exports> exports;
6469

6470
                /**
6471
                 * A mapping of the internal names of opened packages to their configuration.
6472
                 */
6473
                private final Map<String, ModuleDescription.Opens> opens;
6474

6475
                /**
6476
                 * A collection of internal names of used services.
6477
                 */
6478
                private final Set<String> uses;
6479

6480
                /**
6481
                 * A mapping of the internal names of provided services to the internal names of the provided implementations.
6482
                 */
6483
                private final Map<String, Set<String>> provides;
6484

6485
                /**
6486
                 * Creates a module visitor that patches the module implementation.
6487
                 *
6488
                 * @param moduleVisitor     The module visitor to which the data is delegated to.
6489
                 * @param moduleDescription A description of the module.
6490
                 */
6491
                protected PatchingModuleVisitor(ModuleVisitor moduleVisitor, ModuleDescription moduleDescription) {
6492
                    super(OpenedClassReader.ASM_API, moduleVisitor);
×
6493
                    mainClass = moduleDescription.getMainClass();
×
6494
                    if (mainClass != null) {
×
6495
                        mainClass = mainClass.replace('.', '/');
×
6496
                    }
6497
                    packages = new LinkedHashSet<String>();
×
6498
                    for (String aPackage : moduleDescription.getPackages()) {
×
6499
                        packages.add(aPackage.replace('.', '/'));
×
6500
                    }
×
6501
                    requires = new LinkedHashMap<String, ModuleDescription.Requires>(moduleDescription.getRequires());
×
6502
                    exports = new LinkedHashMap<String, ModuleDescription.Exports>();
×
6503
                    for (Map.Entry<String, ModuleDescription.Exports> entry : moduleDescription.getExports().entrySet()) {
×
6504
                        exports.put(entry.getKey().replace('.', '/'), entry.getValue());
×
6505
                    }
×
6506
                    opens = new LinkedHashMap<String, ModuleDescription.Opens>();
×
6507
                    for (Map.Entry<String, ModuleDescription.Opens> entry : moduleDescription.getOpens().entrySet()) {
×
6508
                        opens.put(entry.getKey().replace('.', '/'), entry.getValue());
×
6509
                    }
×
6510
                    uses = new LinkedHashSet<String>();
×
6511
                    for (String use : moduleDescription.getUses()) {
×
6512
                        uses.add(use.replace('.', '/'));
×
6513
                    }
×
6514
                    provides = new LinkedHashMap<String, Set<String>>();
×
6515
                    for (Map.Entry<String, ModuleDescription.Provides> entry : moduleDescription.getProvides().entrySet()) {
×
6516
                        Set<String> providers = new LinkedHashSet<String>();
×
6517
                        for (String provider : entry.getValue().getProviders()) {
×
6518
                            providers.add(provider.replace('.', '/'));
×
6519
                        }
×
6520
                        provides.put(entry.getKey().replace('.', '/'), providers);
×
6521
                    }
×
6522
                }
×
6523

6524
                @Override
6525
                public void visitMainClass(String mainClass) {
6526
                    if (this.mainClass != null) {
×
6527
                        super.visitMainClass(this.mainClass);
×
6528
                        this.mainClass = null;
×
6529
                    }
6530
                }
×
6531

6532
                @Override
6533
                public void visitPackage(String aPackage) {
6534
                    super.visitPackage(aPackage);
×
6535
                    packages.remove(aPackage);
×
6536
                }
×
6537

6538
                @Override
6539
                public void visitRequire(String module, int modifiers, @MaybeNull String version) {
6540
                    ModuleDescription.Requires requires = this.requires.remove(module);
×
6541
                    if (requires != null) {
×
6542
                        super.visitRequire(module, requires.getModifiers(), requires.getVersion());
×
6543
                    } else {
6544
                        super.visitRequire(module, modifiers, version);
×
6545
                    }
6546
                }
×
6547

6548
                @Override
6549
                public void visitExport(String aPackage, int modifiers, @MaybeNull String... module) {
6550
                    ModuleDescription.Exports exports = this.exports.remove(aPackage);
×
6551
                    if (exports != null) {
×
6552
                        super.visitExport(aPackage, exports.getModifiers(), exports.getTargets().isEmpty()
×
6553
                                ? null
6554
                                : exports.getTargets().toArray(new String[0]));
×
6555
                    } else {
6556
                        super.visitExport(aPackage, modifiers, module);
×
6557
                    }
6558
                }
×
6559

6560
                @Override
6561
                public void visitOpen(String aPackage, int modifiers, @MaybeNull String... module) {
6562
                    ModuleDescription.Opens opens = this.opens.remove(aPackage);
×
6563
                    if (opens != null) {
×
6564
                        super.visitOpen(aPackage, opens.getModifiers(), opens.getTargets().isEmpty()
×
6565
                                ? null
6566
                                : opens.getTargets().toArray(new String[0]));
×
6567
                    } else {
6568
                        super.visitOpen(aPackage, modifiers, module);
×
6569
                    }
6570
                }
×
6571

6572
                @Override
6573
                public void visitUse(String service) {
6574
                    uses.remove(service);
×
6575
                    super.visitUse(service);
×
6576
                }
×
6577

6578
                @Override
6579
                public void visitProvide(String service, String... provider) {
6580
                    Set<String> providers = this.provides.remove(service);
×
6581
                    if (providers != null) {
×
6582
                        super.visitProvide(service, providers.toArray(new String[0]));
×
6583
                    } else {
6584
                        super.visitProvide(service, provider);
×
6585
                    }
6586
                }
×
6587

6588
                @Override
6589
                public void visitEnd() {
6590
                    if (mainClass != null) {
×
6591
                        super.visitMainClass(mainClass);
×
6592
                    }
6593
                    for (String aPackage : packages) {
×
6594
                        super.visitPackage(aPackage);
×
6595
                    }
×
6596
                    for (Map.Entry<String, ModuleDescription.Requires> entry : requires.entrySet()) {
×
6597
                        super.visitRequire(entry.getKey(), entry.getValue().getModifiers(), entry.getValue().getVersion());
×
6598
                    }
×
6599
                    for (Map.Entry<String, ModuleDescription.Exports> entry : exports.entrySet()) {
×
6600
                        super.visitExport(entry.getKey(),
×
6601
                                entry.getValue().getModifiers(),
×
6602
                                entry.getValue().getTargets().isEmpty() ? null : entry.getValue().getTargets().toArray(new String[0]));
×
6603
                    }
×
6604
                    for (Map.Entry<String, ModuleDescription.Opens> entry : opens.entrySet()) {
×
6605
                        super.visitOpen(entry.getKey(),
×
6606
                                entry.getValue().getModifiers(),
×
6607
                                entry.getValue().getTargets().isEmpty() ? null : entry.getValue().getTargets().toArray(new String[0]));
×
6608
                    }
×
6609
                    for (String use : uses) {
×
6610
                        super.visitUse(use);
×
6611
                    }
×
6612
                    for (Map.Entry<String, Set<String>> entry : provides.entrySet()) {
×
6613
                        super.visitProvide(entry.getKey(), entry.getValue().isEmpty() ? null : entry.getValue().toArray(new String[0]));
×
6614
                    }
×
6615
                    super.visitEnd();
×
6616
                }
×
6617
            }
6618

6619
            /**
6620
             * A context class visitor based on an {@link Implementation.Context}.
6621
             */
6622
            protected class ImplementationContextClassVisitor extends ContextClassVisitor {
6623

6624
                /**
6625
                 * The implementation context to use.
6626
                 */
6627
                private final Implementation.Context.ExtractableView implementationContext;
6628

6629
                /**
6630
                 * Creates a context class loader based on an {@link Implementation.Context}.
6631
                 *
6632
                 * @param classVisitor          The class visitor to delegate to.
6633
                 * @param implementationContext The implementation context to use.
6634
                 */
6635
                protected ImplementationContextClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6636
                    super(classVisitor);
1✔
6637
                    this.implementationContext = implementationContext;
1✔
6638
                }
1✔
6639

6640
                @Override
6641
                public List<DynamicType> getAuxiliaryTypes() {
6642
                    return CompoundList.of(auxiliaryTypes, implementationContext.getAuxiliaryTypes());
1✔
6643
                }
6644

6645
                @Override
6646
                public LoadedTypeInitializer getLoadedTypeInitializer() {
6647
                    return loadedTypeInitializer;
1✔
6648
                }
6649
            }
6650
        }
6651

6652
        /**
6653
         * An action to write a class file to the dumping location.
6654
         */
6655
        @HashCodeAndEqualsPlugin.Enhance
6656
        protected static class ClassDumpAction implements PrivilegedExceptionAction<Void> {
6657

6658
            /**
6659
             * Indicates that nothing is returned from this action.
6660
             */
6661
            @AlwaysNull
6662
            private static final Void NOTHING = null;
1✔
6663

6664
            /**
6665
             * The target folder for writing the class file to.
6666
             */
6667
            private final String target;
6668

6669
            /**
6670
             * The instrumented type.
6671
             */
6672
            private final TypeDescription instrumentedType;
6673

6674
            /**
6675
             * {@code true} if the dumped class file is an input to a class transformation.
6676
             */
6677
            private final boolean original;
6678

6679
            /**
6680
             * The suffix to append to the dumped class file.
6681
             */
6682
            private final long suffix;
6683

6684
            /**
6685
             * The type's binary representation.
6686
             */
6687
            private final byte[] binaryRepresentation;
6688

6689
            /**
6690
             * Creates a new class dump action.
6691
             *
6692
             * @param target               The target folder for writing the class file to.
6693
             * @param instrumentedType     The instrumented type.
6694
             * @param original             {@code true} if the dumped class file is an input to a class transformation.
6695
             * @param suffix               The suffix to append to the dumped class file.
6696
             * @param binaryRepresentation The type's binary representation.
6697
             */
6698
            protected ClassDumpAction(String target, TypeDescription instrumentedType, boolean original, long suffix, byte[] binaryRepresentation) {
1✔
6699
                this.target = target;
1✔
6700
                this.instrumentedType = instrumentedType;
1✔
6701
                this.original = original;
1✔
6702
                this.suffix = suffix;
1✔
6703
                this.binaryRepresentation = binaryRepresentation;
1✔
6704
            }
1✔
6705

6706
            /**
6707
             * {@inheritDoc}
6708
             */
6709
            public Void run() throws Exception {
6710
                OutputStream outputStream = new FileOutputStream(new File(target, instrumentedType.getName()
1✔
6711
                        + (original ? "-original." : ".")
6712
                        + suffix
6713
                        + ClassFileLocator.CLASS_FILE_EXTENSION));
6714
                try {
6715
                    outputStream.write(binaryRepresentation);
1✔
6716
                    return NOTHING;
1✔
6717
                } finally {
6718
                    outputStream.close();
1✔
6719
                }
6720
            }
6721

6722
            /**
6723
             * A dispatcher for dumping class files to the file system.
6724
             */
6725
            protected interface Dispatcher {
6726

6727
                /**
6728
                 * Dumps a class file to the file system.
6729
                 *
6730
                 * @param instrumentedType     The type to dump.
6731
                 * @param original             {@code true} if the class file is in its original state.
6732
                 * @param binaryRepresentation The class file's binary representation.
6733
                 */
6734
                void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation);
6735

6736
                /**
6737
                 * A disabled dispatcher that does not dump any class files.
6738
                 */
6739
                enum Disabled implements Dispatcher {
1✔
6740

6741
                    /**
6742
                     * The singleton instance.
6743
                     */
6744
                    INSTANCE;
1✔
6745

6746
                    /**
6747
                     * {@inheritDoc}
6748
                     */
6749
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6750
                        /* do nothing */
6751
                    }
1✔
6752
                }
6753

6754
                /**
6755
                 * An enabled dispatcher that dumps class files to a given folder.
6756
                 */
6757
                @HashCodeAndEqualsPlugin.Enhance
6758
                class Enabled implements Dispatcher {
6759

6760
                    /**
6761
                     * The folder to write class files to.
6762
                     */
6763
                    private final String folder;
6764

6765
                    /**
6766
                     * The timestamp to append.
6767
                     */
6768
                    private final long timestamp;
6769

6770
                    /**
6771
                     * Creates a new dispatcher for dumping class files.
6772
                     *
6773
                     * @param folder    The folder to write class files to.
6774
                     * @param timestamp The timestamp to append.
6775
                     */
6776
                    protected Enabled(String folder, long timestamp) {
1✔
6777
                        this.folder = folder;
1✔
6778
                        this.timestamp = timestamp;
1✔
6779
                    }
1✔
6780

6781
                    /**
6782
                     * {@inheritDoc}
6783
                     */
6784
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6785
                        try {
6786
                            doPrivileged(new ClassDumpAction(folder, instrumentedType, original, timestamp, binaryRepresentation));
1✔
6787
                        } catch (Exception exception) {
×
6788
                            exception.printStackTrace();
×
6789
                        }
1✔
6790
                    }
1✔
6791
                }
6792
            }
6793
        }
6794
    }
6795
}
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