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

raphw / byte-buddy / #869

31 Mar 2026 10:03PM UTC coverage: 83.949% (+0.004%) from 83.945%
#869

push

raphw
Add nullability annotations.

29968 of 35698 relevant lines covered (83.95%)

0.84 hits per line

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

75.59
/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.ExceptionTableSensitiveMethodVisitor;
74
import net.bytebuddy.utility.visitor.MetadataAwareClassVisitor;
75
import org.objectweb.asm.AnnotationVisitor;
76
import org.objectweb.asm.ClassReader;
77
import org.objectweb.asm.ClassVisitor;
78
import org.objectweb.asm.ClassWriter;
79
import org.objectweb.asm.ConstantDynamic;
80
import org.objectweb.asm.FieldVisitor;
81
import org.objectweb.asm.Handle;
82
import org.objectweb.asm.Label;
83
import org.objectweb.asm.MethodVisitor;
84
import org.objectweb.asm.ModuleVisitor;
85
import org.objectweb.asm.Opcodes;
86
import org.objectweb.asm.RecordComponentVisitor;
87
import org.objectweb.asm.Type;
88
import org.objectweb.asm.TypePath;
89
import org.objectweb.asm.commons.ClassRemapper;
90
import org.objectweb.asm.commons.Remapper;
91
import org.objectweb.asm.commons.SimpleRemapper;
92

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3324
                    /**
3325
                     * {@inheritDoc}
3326
                     */
3327
                    public void assertAnnotation() {
3328
                        /* do nothing */
3329
                    }
×
3330

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3456
                    /**
3457
                     * {@inheritDoc}
3458
                     */
3459
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3460
                        if (!isStatic || !isPublic || !isFinal) {
1✔
3461
                            throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
1✔
3462
                        }
3463
                    }
×
3464

3465
                    /**
3466
                     * {@inheritDoc}
3467
                     */
3468
                    public void assertMethod(String name,
3469
                                             boolean isAbstract,
3470
                                             boolean isPublic,
3471
                                             boolean isPrivate,
3472
                                             boolean isStatic,
3473
                                             boolean isVirtual,
3474
                                             boolean isConstructor,
3475
                                             boolean isDefaultValueIncompatible,
3476
                                             boolean isGeneric) {
3477
                        if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
3478
                            if (isConstructor) {
1✔
3479
                                throw new IllegalStateException("Cannot define constructor for interface type");
1✔
3480
                            } else if (classic && !isVirtual) {
1✔
3481
                                throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 annotation type");
1✔
3482
                            } else if (!isStatic && isDefaultValueIncompatible) {
1✔
3483
                                throw new IllegalStateException("Cannot define method '" + name + "' with the given signature as an annotation type method");
1✔
3484
                            }
3485
                        }
3486
                    }
1✔
3487

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4606
                        @Override
4607
                        protected void onAfterExceptionTable() {
4608
                            onStart();
1✔
4609
                        }
1✔
4610

4611
                        /**
4612
                         * Invoked after the user code was visited.
4613
                         */
4614
                        protected abstract void onStart();
4615

4616
                        @Override
4617
                        protected void onVisitFrame(int type, int localVariableLength, @MaybeNull Object[] localVariable, int stackSize, @MaybeNull Object[] stack) {
4618
                            super.onVisitFrame(type, localVariableLength, localVariable, stackSize, stack);
1✔
4619
                            frameWriter.onFrame(type, localVariableLength);
1✔
4620
                        }
1✔
4621

4622
                        @Override
4623
                        public void visitMaxs(int stackSize, int localVariableLength) {
4624
                            this.stackSize = stackSize;
1✔
4625
                            this.localVariableLength = localVariableLength;
1✔
4626
                        }
1✔
4627

4628
                        @Override
4629
                        public abstract void visitEnd();
4630

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

4641
                        /**
4642
                         * Invoked upon completion of writing the type initializer.
4643
                         *
4644
                         * @param implementationContext The implementation context to use.
4645
                         */
4646
                        protected abstract void onComplete(Implementation.Context implementationContext);
4647

4648
                        /**
4649
                         * {@inheritDoc}
4650
                         */
4651
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4652
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4653
                            mv.visitMaxs(stackSize, localVariableLength);
1✔
4654
                            mv.visitEnd();
1✔
4655
                        }
1✔
4656

4657
                        /**
4658
                         * A frame writer is responsible for adding empty frames on jump instructions.
4659
                         */
4660
                        protected interface FrameWriter {
4661

4662
                            /**
4663
                             * An empty array.
4664
                             */
4665
                            Object[] EMPTY = new Object[0];
1✔
4666

4667
                            /**
4668
                             * Informs this frame writer of an observed frame.
4669
                             *
4670
                             * @param type                The frame type.
4671
                             * @param localVariableLength The length of the local variables array.
4672
                             */
4673
                            void onFrame(int type, int localVariableLength);
4674

4675
                            /**
4676
                             * Emits an empty frame.
4677
                             *
4678
                             * @param methodVisitor The method visitor to write the frame to.
4679
                             */
4680
                            void emitFrame(MethodVisitor methodVisitor);
4681

4682
                            /**
4683
                             * A non-operational frame writer.
4684
                             */
4685
                            enum NoOp implements FrameWriter {
1✔
4686

4687
                                /**
4688
                                 * The singleton instance.
4689
                                 */
4690
                                INSTANCE;
1✔
4691

4692
                                /**
4693
                                 * {@inheritDoc}
4694
                                 */
4695
                                public void onFrame(int type, int localVariableLength) {
4696
                                    /* do nothing */
4697
                                }
1✔
4698

4699
                                /**
4700
                                 * {@inheritDoc}
4701
                                 */
4702
                                public void emitFrame(MethodVisitor methodVisitor) {
4703
                                    /* do nothing */
4704
                                }
1✔
4705
                            }
4706

4707
                            /**
4708
                             * A frame writer that creates an expanded frame.
4709
                             */
4710
                            enum Expanding implements FrameWriter {
1✔
4711

4712
                                /**
4713
                                 * The singleton instance.
4714
                                 */
4715
                                INSTANCE;
1✔
4716

4717
                                /**
4718
                                 * {@inheritDoc}
4719
                                 */
4720
                                public void onFrame(int type, int localVariableLength) {
4721
                                    /* do nothing */
4722
                                }
1✔
4723

4724
                                /**
4725
                                 * {@inheritDoc}
4726
                                 */
4727
                                public void emitFrame(MethodVisitor methodVisitor) {
4728
                                    methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4729
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4730
                                }
1✔
4731
                            }
4732

4733
                            /**
4734
                             * An active frame writer that creates the most efficient frame.
4735
                             */
4736
                            class Active implements FrameWriter {
1✔
4737

4738
                                /**
4739
                                 * The current length of the current local variable array.
4740
                                 */
4741
                                private int currentLocalVariableLength;
4742

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

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

4783
                        /**
4784
                         * An initialization handler that appends code to a previously visited type initializer without allowing active
4785
                         * {@link TypeInitializer} registrations.
4786
                         */
4787
                        protected abstract static class WithoutDrain extends Appending {
4788

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

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

4813
                            @Override
4814
                            public void visitEnd() {
4815
                                /* do nothing */
4816
                            }
1✔
4817

4818
                            /**
4819
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4820
                             * {@link TypeInitializer} registrations and without an active record.
4821
                             */
4822
                            protected static class WithoutActiveRecord extends WithoutDrain {
4823

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

4839
                                @Override
4840
                                protected void onComplete(Implementation.Context implementationContext) {
4841
                                    /* do nothing */
4842
                                }
1✔
4843
                            }
4844

4845
                            /**
4846
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4847
                             * {@link TypeInitializer} registrations and with an active record.
4848
                             */
4849
                            protected static class WithActiveRecord extends WithoutDrain {
4850

4851
                                /**
4852
                                 * The label that indicates the beginning of the active record.
4853
                                 */
4854
                                private final Label label;
4855

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

4876
                                @Override
4877
                                protected void onVisitInsn(int opcode) {
4878
                                    if (opcode == Opcodes.RETURN) {
1✔
4879
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4880
                                    } else {
4881
                                        super.onVisitInsn(opcode);
1✔
4882
                                    }
4883
                                }
1✔
4884

4885
                                @Override
4886
                                protected void onComplete(Implementation.Context implementationContext) {
4887
                                    mv.visitLabel(label);
1✔
4888
                                    frameWriter.emitFrame(mv);
1✔
4889
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
4890
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4891
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4892
                                }
1✔
4893

4894
                            }
4895
                        }
4896

4897
                        /**
4898
                         * An initialization handler that appends code to a previously visited type initializer with allowing active
4899
                         * {@link TypeInitializer} registrations.
4900
                         */
4901
                        protected abstract static class WithDrain extends Appending {
4902

4903
                            /**
4904
                             * A label marking the beginning of the appended code.
4905
                             */
4906
                            protected final Label appended;
4907

4908
                            /**
4909
                             * A label marking the beginning og the original type initializer's code.
4910
                             */
4911
                            protected final Label original;
4912

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

4934
                            @Override
4935
                            protected void onStart() {
4936
                                mv.visitJumpInsn(Opcodes.GOTO, appended);
1✔
4937
                                mv.visitLabel(original);
1✔
4938
                                frameWriter.emitFrame(mv);
1✔
4939
                            }
1✔
4940

4941
                            @Override
4942
                            public void visitEnd() {
4943
                                mv.visitLabel(appended);
1✔
4944
                                frameWriter.emitFrame(mv);
1✔
4945
                            }
1✔
4946

4947
                            @Override
4948
                            protected void onComplete(Implementation.Context implementationContext) {
4949
                                mv.visitJumpInsn(Opcodes.GOTO, original);
1✔
4950
                                onAfterComplete(implementationContext);
1✔
4951
                            }
1✔
4952

4953
                            /**
4954
                             * Invoked after completion of writing the type initializer.
4955
                             *
4956
                             * @param implementationContext The implementation context to use.
4957
                             */
4958
                            protected abstract void onAfterComplete(Implementation.Context implementationContext);
4959

4960
                            /**
4961
                             * A code appending initialization handler with a drain that does not apply an explicit record.
4962
                             */
4963
                            protected static class WithoutActiveRecord extends WithDrain {
4964

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

4984
                                @Override
4985
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4986
                                    /* do nothing */
4987
                                }
1✔
4988
                            }
4989

4990
                            /**
4991
                             * A code appending initialization handler with a drain that applies an explicit record.
4992
                             */
4993
                            protected static class WithActiveRecord extends WithDrain {
4994

4995
                                /**
4996
                                 * A label indicating the beginning of the record's code.
4997
                                 */
4998
                                private final Label label;
4999

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

5020
                                @Override
5021
                                protected void onVisitInsn(int opcode) {
5022
                                    if (opcode == Opcodes.RETURN) {
1✔
5023
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
5024
                                    } else {
5025
                                        super.onVisitInsn(opcode);
1✔
5026
                                    }
5027
                                }
1✔
5028

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

5042
                /**
5043
                 * A class visitor which is capable of applying a redefinition of an existing class file.
5044
                 */
5045
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
5046
                protected class RedefinitionClassVisitor extends MetadataAwareClassVisitor {
5047

5048
                    /**
5049
                     * The type initializer to apply.
5050
                     */
5051
                    private final TypeInitializer typeInitializer;
5052

5053
                    /**
5054
                     * A context registry to register the lazily created implementation context to.
5055
                     */
5056
                    private final ContextRegistry contextRegistry;
5057

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

5063
                    /**
5064
                     * The reader flags being used.
5065
                     */
5066
                    private final int readerFlags;
5067

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

5073
                    /**
5074
                     * A mapping of methods to write by their unique signature.
5075
                     */
5076
                    private final LinkedHashMap<SignatureKey, MethodDescription> declarableMethods;
5077

5078
                    /**
5079
                     * A mapping of record components to write by their names.
5080
                     */
5081
                    private final LinkedHashMap<String, RecordComponentDescription> declarableRecordComponents;
5082

5083
                    /**
5084
                     * 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.
5085
                     */
5086
                    private final Set<String> nestMembers;
5087

5088
                    /**
5089
                     * A mapping of the internal names of all declared types to their description.
5090
                     */
5091
                    private final LinkedHashMap<String, TypeDescription> declaredTypes;
5092

5093
                    /**
5094
                     * A list of internal names of permitted subclasses to include.
5095
                     */
5096
                    @MaybeNull
5097
                    private final Set<String> permittedSubclasses;
5098

5099
                    /**
5100
                     * The method pool to use or {@code null} if the pool was not yet initialized.
5101
                     */
5102
                    @UnknownNull
5103
                    private MethodPool methodPool;
5104

5105
                    /**
5106
                     * The initialization handler to use or {@code null} if the handler was not yet initialized.
5107
                     */
5108
                    @UnknownNull
5109
                    private InitializationHandler initializationHandler;
5110

5111
                    /**
5112
                     * The implementation context for this class creation or {@code null} if it was not yet created.
5113
                     */
5114
                    @UnknownNull
5115
                    private Implementation.Context.ExtractableView implementationContext;
5116

5117
                    /**
5118
                     * {@code true} if the modifiers for deprecation should be retained.
5119
                     */
5120
                    private boolean retainDeprecationModifiers;
5121

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

5127
                    /**
5128
                     * A set of keys for methods that were previosuly visited.
5129
                     */
5130
                    private final Set<SignatureKey> methodsKeys = new HashSet<SignatureKey>();
1✔
5131

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

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

5230
                    @Override
5231
                    @MaybeNull
5232
                    protected ModuleVisitor onVisitModule(String name, int modifiers, @MaybeNull String version) {
5233
                        onModule();
1✔
5234
                        return null;
1✔
5235
                    }
5236

5237
                    @Override
5238
                    protected void onModule() {
5239
                        ModuleDescription moduleDescription = instrumentedType.toModuleDescription();
1✔
5240
                        if (moduleDescription != null) {
1✔
5241
                            moduleDescription.accept(cv);
1✔
5242
                        }
5243
                    }
1✔
5244

5245
                    @Override
5246
                    protected void onVisitNestHost(String nestHost) {
5247
                        onNestHost();
×
5248
                    }
×
5249

5250
                    @Override
5251
                    protected void onNestHost() {
5252
                        if (!instrumentedType.isNestHost()) {
1✔
5253
                            cv.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
5254
                        }
5255
                    }
1✔
5256

5257
                    @Override
5258
                    protected void onVisitPermittedSubclass(String permittedSubclass) {
5259
                        if (permittedSubclasses != null && permittedSubclasses.remove(permittedSubclass)) {
×
5260
                            cv.visitPermittedSubclass(permittedSubclass);
×
5261
                        }
5262
                    }
×
5263

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

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

5286
                    @Override
5287
                    protected void onAfterAttributes() {
5288
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5289
                    }
1✔
5290

5291
                    @Override
5292
                    @MaybeNull
5293
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5294
                        return annotationRetention.isEnabled()
1✔
5295
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
1✔
5296
                                : IGNORE_ANNOTATION;
×
5297
                    }
5298

5299
                    @Override
5300
                    @MaybeNull
5301
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5302
                        return annotationRetention.isEnabled()
1✔
5303
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5304
                                : IGNORE_ANNOTATION;
1✔
5305
                    }
5306

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

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

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

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

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

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

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

5488
                    @Override
5489
                    protected void onVisitNestMember(String nestMember) {
5490
                        if (instrumentedType.isNestHost() && nestMembers.remove(nestMember)) {
×
5491
                            cv.visitNestMember(nestMember);
×
5492
                        }
5493
                    }
×
5494

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

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

5561
                    /**
5562
                     * A class visitor that deduplicates fields and methods, mostly when access bridge methods are
5563
                     * previously declared, but incomplete.
5564
                     */
5565
                    protected class DeduplicatingClassVisitor extends ClassVisitor {
5566

5567
                        /**
5568
                         * Creates a new method deduplicating class visitor.
5569
                         *
5570
                         * @param classVisitor The class visitor to delegate to.
5571
                         */
5572
                        protected DeduplicatingClassVisitor(ClassVisitor classVisitor) {
1✔
5573
                            super(OpenedClassReader.ASM_API, classVisitor);
1✔
5574
                        }
1✔
5575

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

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

5607
                    /**
5608
                     * A field visitor that obtains all attributes and annotations of a field that is found in the
5609
                     * class file but that discards all code.
5610
                     */
5611
                    protected class AttributeObtainingFieldVisitor extends FieldVisitor {
5612

5613
                        /**
5614
                         * The field pool record to apply onto the field visitor.
5615
                         */
5616
                        private final FieldPool.Record record;
5617

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

5629
                        @Override
5630
                        @MaybeNull
5631
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5632
                            return annotationRetention.isEnabled()
×
5633
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5634
                                    : IGNORE_ANNOTATION;
×
5635
                        }
5636

5637
                        @Override
5638
                        @MaybeNull
5639
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5640
                            return annotationRetention.isEnabled()
1✔
5641
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5642
                                    : IGNORE_ANNOTATION;
1✔
5643
                        }
5644

5645
                        @Override
5646
                        public void visitEnd() {
5647
                            record.apply(fv, annotationValueFilterFactory);
1✔
5648
                            super.visitEnd();
1✔
5649
                        }
1✔
5650
                    }
5651

5652
                    /**
5653
                     * A record component visitor that obtains all attributes and annotations of a record component that is found
5654
                     * in the class file but discards all code.
5655
                     */
5656
                    protected class AttributeObtainingRecordComponentVisitor extends RecordComponentVisitor {
5657

5658
                        /**
5659
                         * The record component pool record to apply onto the record component visitor.
5660
                         */
5661
                        private final RecordComponentPool.Record record;
5662

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

5674
                        @Override
5675
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5676
                            return annotationRetention.isEnabled()
×
5677
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5678
                                    : IGNORE_ANNOTATION;
×
5679
                        }
5680

5681
                        @Override
5682
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5683
                            return annotationRetention.isEnabled()
×
5684
                                    ? super.visitAnnotation(descriptor, visible)
×
5685
                                    : IGNORE_ANNOTATION;
×
5686
                        }
5687

5688
                        @Override
5689
                        public void visitEnd() {
5690
                            record.apply(getDelegate(), annotationValueFilterFactory);
×
5691
                            super.visitEnd();
×
5692
                        }
×
5693
                    }
5694

5695
                    /**
5696
                     * A method visitor that preserves the code of a method in the class file by copying it into a rebased
5697
                     * method while copying all attributes and annotations to the actual method.
5698
                     */
5699
                    protected class CodePreservingMethodVisitor extends MethodVisitor {
5700

5701
                        /**
5702
                         * The method visitor of the actual method.
5703
                         */
5704
                        private final MethodVisitor actualMethodVisitor;
5705

5706
                        /**
5707
                         * The method pool entry to apply.
5708
                         */
5709
                        private final MethodPool.Record record;
5710

5711
                        /**
5712
                         * The resolution of a potential rebased method.
5713
                         */
5714
                        private final MethodRebaseResolver.Resolution resolution;
5715

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

5733
                        @Override
5734
                        @MaybeNull
5735
                        public AnnotationVisitor visitAnnotationDefault() {
5736
                            return IGNORE_ANNOTATION; // Annotation types can never be rebased.
×
5737
                        }
5738

5739
                        @Override
5740
                        @MaybeNull
5741
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5742
                            return annotationRetention.isEnabled()
×
5743
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5744
                                    : IGNORE_ANNOTATION;
×
5745
                        }
5746

5747
                        @Override
5748
                        @MaybeNull
5749
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5750
                            return annotationRetention.isEnabled()
1✔
5751
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5752
                                    : IGNORE_ANNOTATION;
1✔
5753
                        }
5754

5755
                        @Override
5756
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5757
                            if (annotationRetention.isEnabled()) {
1✔
5758
                                super.visitAnnotableParameterCount(count, visible);
1✔
5759
                            }
5760
                        }
1✔
5761

5762
                        @Override
5763
                        @MaybeNull
5764
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5765
                            return annotationRetention.isEnabled()
1✔
5766
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
1✔
5767
                                    : IGNORE_ANNOTATION;
1✔
5768
                        }
5769

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

5822
                        @Override
5823
                        public void visitMaxs(int stackSize, int localVariableLength) {
5824
                            super.visitMaxs(stackSize, Math.max(localVariableLength, resolution.getResolvedMethod().getStackSize()));
1✔
5825
                        }
1✔
5826
                    }
5827

5828
                    /**
5829
                     * A method visitor that obtains all attributes and annotations of a method that is found in the
5830
                     * class file but that discards all code.
5831
                     */
5832
                    protected class AttributeObtainingMethodVisitor extends MethodVisitor {
5833

5834
                        /**
5835
                         * The method visitor to which the actual method is to be written to.
5836
                         */
5837
                        private final MethodVisitor actualMethodVisitor;
5838

5839
                        /**
5840
                         * The method pool entry to apply.
5841
                         */
5842
                        private final MethodPool.Record record;
5843

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

5857
                        @Override
5858
                        @MaybeNull
5859
                        public AnnotationVisitor visitAnnotationDefault() {
5860
                            return IGNORE_ANNOTATION;
×
5861
                        }
5862

5863
                        @Override
5864
                        @MaybeNull
5865
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5866
                            return annotationRetention.isEnabled()
×
5867
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5868
                                    : IGNORE_ANNOTATION;
×
5869
                        }
5870

5871
                        @Override
5872
                        @MaybeNull
5873
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5874
                            return annotationRetention.isEnabled()
×
5875
                                    ? super.visitAnnotation(descriptor, visible)
×
5876
                                    : IGNORE_ANNOTATION;
×
5877
                        }
5878

5879
                        @Override
5880
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5881
                            if (annotationRetention.isEnabled()) {
×
5882
                                super.visitAnnotableParameterCount(count, visible);
×
5883
                            }
5884
                        }
×
5885

5886
                        @Override
5887
                        @MaybeNull
5888
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5889
                            return annotationRetention.isEnabled()
×
5890
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
×
5891
                                    : IGNORE_ANNOTATION;
×
5892
                        }
5893

5894
                        @Override
5895
                        public void visitCode() {
5896
                            mv = IGNORE_METHOD;
×
5897
                        }
×
5898

5899
                        @Override
5900
                        public void visitEnd() {
5901
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5902
                            actualMethodVisitor.visitEnd();
1✔
5903
                        }
1✔
5904
                    }
5905
                }
5906
            }
5907

5908
            /**
5909
             * A default type writer that only applies a type decoration.
5910
             *
5911
             * @param <V> The best known loaded type for the dynamically created type.
5912
             */
5913
            protected static class WithDecorationOnly<V> extends ForInlining<V> {
5914

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

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

5988
                /**
5989
                 * A field list that only reads fields lazy to avoid an eager lookup since fields are often not required.
5990
                 */
5991
                protected static class LazyFieldList extends FieldList.AbstractBase<FieldDescription.InDefinedShape> {
5992

5993
                    /**
5994
                     * The instrumented type.
5995
                     */
5996
                    private final TypeDescription instrumentedType;
5997

5998
                    /**
5999
                     * Creates a lazy field list.
6000
                     *
6001
                     * @param instrumentedType The instrumented type.
6002
                     */
6003
                    protected LazyFieldList(TypeDescription instrumentedType) {
1✔
6004
                        this.instrumentedType = instrumentedType;
1✔
6005
                    }
1✔
6006

6007
                    /**
6008
                     * {@inheritDoc}
6009
                     */
6010
                    public FieldDescription.InDefinedShape get(int index) {
6011
                        return instrumentedType.getDeclaredFields().get(index);
×
6012
                    }
6013

6014
                    /**
6015
                     * {@inheritDoc}
6016
                     */
6017
                    public int size() {
6018
                        return instrumentedType.getDeclaredFields().size();
×
6019
                    }
6020
                }
6021

6022
                /**
6023
                 * A class visitor that decorates an existing type.
6024
                 */
6025
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
6026
                protected class DecorationClassVisitor extends MetadataAwareClassVisitor implements TypeInitializer.Drain {
6027

6028
                    /**
6029
                     * A context registry to register the lazily created implementation context to.
6030
                     */
6031
                    private final ContextRegistry contextRegistry;
6032

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

6038
                    /**
6039
                     * The reader flags being used.
6040
                     */
6041
                    private final int readerFlags;
6042

6043
                    /**
6044
                     * The implementation context to use or {@code null} if the context is not yet initialized.
6045
                     */
6046
                    @UnknownNull
6047
                    private Implementation.Context.ExtractableView implementationContext;
6048

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

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

6092
                    @Override
6093
                    @MaybeNull
6094
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
6095
                        return annotationRetention.isEnabled()
×
6096
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
6097
                                : IGNORE_ANNOTATION;
×
6098
                    }
6099

6100
                    @Override
6101
                    @MaybeNull
6102
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
6103
                        return annotationRetention.isEnabled()
1✔
6104
                                ? cv.visitAnnotation(descriptor, visible)
1✔
6105
                                : IGNORE_ANNOTATION;
1✔
6106
                    }
6107

6108
                    @Override
6109
                    protected void onAfterAttributes() {
6110
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6111
                    }
1✔
6112

6113
                    @Override
6114
                    protected void onVisitEnd() {
6115
                        implementationContext.drain(this, cv, annotationValueFilterFactory);
1✔
6116
                        cv.visitEnd();
1✔
6117
                    }
1✔
6118

6119
                    /**
6120
                     * {@inheritDoc}
6121
                     */
6122
                    public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
6123
                        /* do nothing */
6124
                    }
1✔
6125
                }
6126
            }
6127
        }
6128

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

6137
            /**
6138
             * The method pool to use.
6139
             */
6140
            private final MethodPool methodPool;
6141

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

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

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

6332
            /**
6333
             * A class visitor that applies the subclass creation as a wrapper.
6334
             */
6335
            protected class CreationClassVisitor extends MetadataAwareClassVisitor {
6336

6337
                /**
6338
                 * The implementation context to apply.
6339
                 */
6340
                private final Implementation.Context.ExtractableView implementationContext;
6341

6342
                /**
6343
                 * The underlying module information or {@code null} if no such information is provided.
6344
                 */
6345
                @MaybeNull
6346
                private final ModuleDescription moduleDescription;
6347

6348
                /**
6349
                 * The declared types that have been visited.
6350
                 */
6351
                private final Set<String> declaredTypes = new HashSet<String>();
1✔
6352

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

6358
                /**
6359
                 * The signature of all methods that were explicitly visited.
6360
                 */
6361
                private final Set<SignatureKey> visitedMethods = new HashSet<SignatureKey>();
1✔
6362

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

6378
                @Override
6379
                protected void onModule() {
6380
                    if (moduleDescription != null) {
1✔
6381
                        moduleDescription.accept(cv);
×
6382
                    }
6383
                }
1✔
6384

6385
                @Override
6386
                @MaybeNull
6387
                protected ModuleVisitor onVisitModule(String name, int modifiers, @MaybeNull String version) {
6388
                    return moduleDescription == null ? null : new PatchingModuleVisitor(cv.visitModule(moduleDescription.getActualName(),
×
6389
                            moduleDescription.getModifiers(),
×
6390
                            moduleDescription.getVersion()), moduleDescription);
×
6391
                }
6392

6393
                @Override
6394
                protected void onAfterAttributes() {
6395
                    typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6396
                }
1✔
6397

6398
                @Override
6399
                protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
6400
                    declaredTypes.add(internalName);
×
6401
                    super.onVisitInnerClass(internalName, outerName, innerName, modifiers);
×
6402
                }
×
6403

6404
                @Override
6405
                @MaybeNull
6406
                protected FieldVisitor onVisitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
6407
                    visitedFields.add(new SignatureKey(name, descriptor));
×
6408
                    return super.onVisitField(modifiers, name, descriptor, signature, value);
×
6409
                }
6410

6411
                @Override
6412
                @MaybeNull
6413
                protected MethodVisitor onVisitMethod(int modifiers, String internalName, String descriptor, @MaybeNull String signature, @MaybeNull String[] exception) {
6414
                    visitedMethods.add(new SignatureKey(internalName, descriptor));
×
6415
                    return super.onVisitMethod(modifiers, internalName, descriptor, signature, exception);
×
6416
                }
6417

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

6449
            /**
6450
             * A class visitor that applies the subclass creation as a wrapper.
6451
             */
6452
            protected static class PatchingModuleVisitor extends ModuleVisitor {
6453

6454
                /**
6455
                 * The internal name of the main class or {@code null} if no main class is defined.
6456
                 */
6457
                @MaybeNull
6458
                private String mainClass;
6459

6460
                /**
6461
                 * The internal name of all packages of the module.
6462
                 */
6463
                private final Set<String> packages;
6464

6465
                /**
6466
                 * A mapping of required modules to their configuration.
6467
                 */
6468
                private final Map<String, ModuleDescription.Requires> requires;
6469

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

6475
                /**
6476
                 * A mapping of the internal names of opened packages to their configuration.
6477
                 */
6478
                private final Map<String, ModuleDescription.Opens> opens;
6479

6480
                /**
6481
                 * A collection of internal names of used services.
6482
                 */
6483
                private final Set<String> uses;
6484

6485
                /**
6486
                 * A mapping of the internal names of provided services to the internal names of the provided implementations.
6487
                 */
6488
                private final Map<String, Set<String>> provides;
6489

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

6529
                @Override
6530
                public void visitMainClass(String mainClass) {
6531
                    if (this.mainClass != null) {
×
6532
                        super.visitMainClass(this.mainClass);
×
6533
                        this.mainClass = null;
×
6534
                    }
6535
                }
×
6536

6537
                @Override
6538
                public void visitPackage(String aPackage) {
6539
                    super.visitPackage(aPackage);
×
6540
                    packages.remove(aPackage);
×
6541
                }
×
6542

6543
                @Override
6544
                public void visitRequire(String module, int modifiers, @MaybeNull String version) {
6545
                    ModuleDescription.Requires requires = this.requires.remove(module);
×
6546
                    if (requires != null) {
×
6547
                        super.visitRequire(module, requires.getModifiers(), requires.getVersion());
×
6548
                    } else {
6549
                        super.visitRequire(module, modifiers, version);
×
6550
                    }
6551
                }
×
6552

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

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

6577
                @Override
6578
                public void visitUse(String service) {
6579
                    uses.remove(service);
×
6580
                    super.visitUse(service);
×
6581
                }
×
6582

6583
                @Override
6584
                public void visitProvide(String service, String... provider) {
6585
                    Set<String> providers = this.provides.remove(service);
×
6586
                    if (providers != null) {
×
6587
                        super.visitProvide(service, providers.toArray(new String[0]));
×
6588
                    } else {
6589
                        super.visitProvide(service, provider);
×
6590
                    }
6591
                }
×
6592

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

6624
            /**
6625
             * A context class visitor based on an {@link Implementation.Context}.
6626
             */
6627
            protected class ImplementationContextClassVisitor extends ContextClassVisitor {
6628

6629
                /**
6630
                 * The implementation context to use.
6631
                 */
6632
                private final Implementation.Context.ExtractableView implementationContext;
6633

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

6645
                @Override
6646
                public List<DynamicType> getAuxiliaryTypes() {
6647
                    return CompoundList.of(auxiliaryTypes, implementationContext.getAuxiliaryTypes());
1✔
6648
                }
6649

6650
                @Override
6651
                public LoadedTypeInitializer getLoadedTypeInitializer() {
6652
                    return loadedTypeInitializer;
1✔
6653
                }
6654
            }
6655
        }
6656

6657
        /**
6658
         * An action to write a class file to the dumping location.
6659
         */
6660
        @HashCodeAndEqualsPlugin.Enhance
6661
        protected static class ClassDumpAction implements PrivilegedExceptionAction<Void> {
6662

6663
            /**
6664
             * Indicates that nothing is returned from this action.
6665
             */
6666
            @AlwaysNull
6667
            private static final Void NOTHING = null;
1✔
6668

6669
            /**
6670
             * The target folder for writing the class file to.
6671
             */
6672
            private final String target;
6673

6674
            /**
6675
             * The instrumented type.
6676
             */
6677
            private final TypeDescription instrumentedType;
6678

6679
            /**
6680
             * {@code true} if the dumped class file is an input to a class transformation.
6681
             */
6682
            private final boolean original;
6683

6684
            /**
6685
             * The suffix to append to the dumped class file.
6686
             */
6687
            private final long suffix;
6688

6689
            /**
6690
             * The type's binary representation.
6691
             */
6692
            private final byte[] binaryRepresentation;
6693

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

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

6727
            /**
6728
             * A dispatcher for dumping class files to the file system.
6729
             */
6730
            protected interface Dispatcher {
6731

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

6741
                /**
6742
                 * A disabled dispatcher that does not dump any class files.
6743
                 */
6744
                enum Disabled implements Dispatcher {
1✔
6745

6746
                    /**
6747
                     * The singleton instance.
6748
                     */
6749
                    INSTANCE;
1✔
6750

6751
                    /**
6752
                     * {@inheritDoc}
6753
                     */
6754
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6755
                        /* do nothing */
6756
                    }
1✔
6757
                }
6758

6759
                /**
6760
                 * An enabled dispatcher that dumps class files to a given folder.
6761
                 */
6762
                @HashCodeAndEqualsPlugin.Enhance
6763
                class Enabled implements Dispatcher {
6764

6765
                    /**
6766
                     * The folder to write class files to.
6767
                     */
6768
                    private final String folder;
6769

6770
                    /**
6771
                     * The timestamp to append.
6772
                     */
6773
                    private final long timestamp;
6774

6775
                    /**
6776
                     * Creates a new dispatcher for dumping class files.
6777
                     *
6778
                     * @param folder    The folder to write class files to.
6779
                     * @param timestamp The timestamp to append.
6780
                     */
6781
                    protected Enabled(String folder, long timestamp) {
1✔
6782
                        this.folder = folder;
1✔
6783
                        this.timestamp = timestamp;
1✔
6784
                    }
1✔
6785

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