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

hazendaz / jmockit1 / 496

15 Nov 2025 05:33PM UTC coverage: 72.192% (-0.008%) from 72.2%
496

push

github

web-flow
Merge pull request #412 from hazendaz/renovate/major-spring-core

Update spring core to v7 (major)

5677 of 8360 branches covered (67.91%)

Branch coverage included in aggregate %.

11922 of 16018 relevant lines covered (74.43%)

0.74 hits per line

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

60.26
/main/src/main/java/mockit/asm/annotations/AnnotationVisitor.java
1
/*
2
 * MIT License
3
 * Copyright (c) 2006-2025 JMockit developers
4
 * See LICENSE file for full license text.
5
 */
6
package mockit.asm.annotations;
7

8
import edu.umd.cs.findbugs.annotations.NonNull;
9
import edu.umd.cs.findbugs.annotations.Nullable;
10

11
import java.lang.reflect.Array;
12

13
import mockit.asm.constantPool.ConstantPoolGeneration;
14
import mockit.asm.constantPool.Item;
15
import mockit.asm.types.JavaType;
16
import mockit.asm.util.ByteVector;
17

18
import org.checkerframework.checker.index.qual.NonNegative;
19

20
/**
21
 * A visitor to visit a Java annotation, in the following order: (<code>visit</code> | <code>visitEnum</code> |
22
 * <code>visitAnnotation</code> | <code>visitArray</code>)* <code>visitEnd</code>.
23
 */
24
public final class AnnotationVisitor {
25
    /**
26
     * The constant pool to which this annotation must be added.
27
     */
28
    @NonNull
29
    private final ConstantPoolGeneration cp;
30

31
    /**
32
     * The number of attribute values in this annotation.
33
     */
34
    @NonNegative
35
    private int attributeCount;
36

37
    /**
38
     * <code>true<code> if values are named, <code>false</code> otherwise. Annotation writers used for annotation
39
     * default and annotation arrays use unnamed values.
40
     */
41
    private final boolean named;
42

43
    /**
44
     * The annotation values in bytecode form. This byte vector only contains the values themselves, i.e. the number of
45
     * values must be stored as an unsigned short just before these bytes.
46
     */
47
    @NonNull
48
    private final ByteVector bv;
49

50
    /**
51
     * Where the number of values of this annotation must be stored in {@link #bv}.
52
     */
53
    @NonNegative
54
    private final int offset;
55

56
    /**
57
     * Next annotation visitor. This field is used to store annotation lists.
58
     */
59
    @Nullable
60
    private AnnotationVisitor next;
61

62
    /**
63
     * Previous annotation visitor. This field is used to store annotation lists.
64
     */
65
    @Nullable
66
    private AnnotationVisitor prev;
67

68
    public AnnotationVisitor(@NonNull ConstantPoolGeneration cp, @NonNull String typeDesc) {
1✔
69
        this.cp = cp;
1✔
70
        named = true;
1✔
71
        bv = new ByteVector();
1✔
72
        bv.putShort(cp.newUTF8(typeDesc));
1✔
73
        bv.putShort(0); // reserve space for value count
1✔
74
        offset = 2;
1✔
75
    }
1✔
76

77
    private AnnotationVisitor(@NonNull AnnotationVisitor parent, boolean named) {
1✔
78
        cp = parent.cp;
1✔
79
        this.named = named;
1✔
80
        bv = parent.bv;
1✔
81
        offset = getByteLength() - 2;
1✔
82
    }
1✔
83

84
    @NonNegative
85
    private int getByteLength() {
86
        return bv.getLength();
1✔
87
    }
88

89
    /**
90
     * Sets the visitor to the {@link #next} annotation.
91
     */
92
    public void setNext(@Nullable AnnotationVisitor next) {
93
        this.next = next;
1✔
94
    }
1✔
95

96
    /**
97
     * Visits a primitive, String, Class, or array value of the annotation.
98
     *
99
     * @param name
100
     *            the value name
101
     * @param value
102
     *            the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link Character}, {@link Short},
103
     *            {@link Integer}, {@link Long}, {@link Float}, {@link Double}, {@link String}, or {@link JavaType} of
104
     *            OBJECT or ARRAY sort; this value can also be an array of byte, boolean, short, char, int, long, float
105
     *            or double values (this is equivalent to using {@link #visitArray} and visiting each array element in
106
     *            turn, but is more convenient)
107
     */
108
    void visit(@Nullable String name, @NonNull Object value) {
109
        putName(name);
1✔
110

111
        if (value instanceof String) {
1✔
112
            putString('s', (String) value);
1✔
113
        } else if (putValueWhenPrimitive(value)) {
1✔
114
            // OK
115
        } else if (value instanceof JavaType) {
1!
116
            putType((JavaType) value);
1✔
117
        } else {
118
            putElementValuesWhenArray(value);
×
119
        }
120
    }
1✔
121

122
    private void putName(@Nullable String name) {
123
        attributeCount++;
1✔
124

125
        if (named) {
1✔
126
            // noinspection ConstantConditions
127
            putString(name);
1✔
128
        }
129
    }
1✔
130

131
    private boolean putValueWhenPrimitive(@NonNull Object value) {
132
        if (value instanceof Boolean) {
1✔
133
            putBoolean((Boolean) value);
1✔
134
        } else if (value instanceof Integer) {
1!
135
            putInteger('I', (Integer) value);
×
136
        } else if (value instanceof Double) {
1!
137
            putDouble((Double) value);
×
138
        } else if (value instanceof Float) {
1!
139
            putFloat((Float) value);
×
140
        } else if (value instanceof Long) {
1!
141
            putLong((Long) value);
×
142
        } else if (value instanceof Byte) {
1!
143
            putInteger('B', (Byte) value);
×
144
        } else if (value instanceof Character) {
1!
145
            putInteger('C', (Character) value);
×
146
        } else if (value instanceof Short) {
1!
147
            putInteger('S', (Short) value);
×
148
        } else {
149
            return false;
1✔
150
        }
151

152
        return true;
1✔
153
    }
154

155
    private void putItem(int typeCode, @NonNull Item item) {
156
        bv.put12(typeCode, item.index);
1✔
157
    }
1✔
158

159
    private void putBoolean(boolean value) {
160
        putInteger('Z', value ? 1 : 0);
1✔
161
    }
1✔
162

163
    private void putInteger(int typeCode, int value) {
164
        Item item = cp.newInteger(value);
1✔
165
        putItem(typeCode, item);
1✔
166
    }
1✔
167

168
    private void putDouble(double value) {
169
        Item item = cp.newDouble(value);
×
170
        putItem('D', item);
×
171
    }
×
172

173
    private void putFloat(float value) {
174
        Item item = cp.newFloat(value);
×
175
        putItem('F', item);
×
176
    }
×
177

178
    private void putLong(long value) {
179
        Item item = cp.newLong(value);
×
180
        putItem('J', item);
×
181
    }
×
182

183
    private void putType(@NonNull JavaType type) {
184
        String typeDescriptor = type.getDescriptor();
1✔
185
        putString('c', typeDescriptor);
1✔
186
    }
1✔
187

188
    private void putString(int b, @NonNull String value) {
189
        int itemIndex = cp.newUTF8(value);
1✔
190
        bv.put12(b, itemIndex);
1✔
191
    }
1✔
192

193
    private void putString(@NonNull String value) {
194
        int itemIndex = cp.newUTF8(value);
1✔
195
        bv.putShort(itemIndex);
1✔
196
    }
1✔
197

198
    private void putArrayLength(@NonNegative int length) {
199
        bv.put12('[', length);
1✔
200
    }
1✔
201

202
    private void putElementValuesWhenArray(@NonNull Object value) {
203
        if (value instanceof byte[]) {
×
204
            putArrayElementValues('B', value);
×
205
        } else if (value instanceof boolean[]) {
×
206
            putArrayElementValues('Z', value);
×
207
        } else if (value instanceof short[]) {
×
208
            putArrayElementValues('S', value);
×
209
        } else if (value instanceof char[]) {
×
210
            putArrayElementValues('C', value);
×
211
        } else if (value instanceof int[]) {
×
212
            putArrayElementValues('I', value);
×
213
        } else if (value instanceof long[]) {
×
214
            putArrayElementValues('J', value);
×
215
        } else if (value instanceof float[]) {
×
216
            putArrayElementValues('F', value);
×
217
        } else if (value instanceof double[]) {
×
218
            putArrayElementValues('D', value);
×
219
        }
220
    }
×
221

222
    private void putArrayElementValues(char elementType, @NonNull Object array) {
223
        int length = Array.getLength(array);
×
224
        putArrayLength(length);
×
225

226
        for (int i = 0; i < length; i++) {
×
227
            switch (elementType) {
×
228
                case 'J': {
229
                    long value = Array.getLong(array, i);
×
230
                    putLong(value);
×
231
                    break;
×
232
                }
233
                case 'F': {
234
                    float value = Array.getFloat(array, i);
×
235
                    putFloat(value);
×
236
                    break;
×
237
                }
238
                case 'D': {
239
                    double value = Array.getDouble(array, i);
×
240
                    putDouble(value);
×
241
                    break;
×
242
                }
243
                case 'Z': {
244
                    boolean value = Array.getBoolean(array, i);
×
245
                    putBoolean(value);
×
246
                    break;
×
247
                }
248
                default: {
249
                    int value = Array.getInt(array, i);
×
250
                    putInteger(elementType, value);
×
251
                    break;
×
252
                }
253
            }
254
        }
255
    }
×
256

257
    /**
258
     * Visits an enumeration value of the annotation.
259
     *
260
     * @param name
261
     *            the value name
262
     * @param desc
263
     *            the class descriptor of the enumeration class
264
     * @param value
265
     *            the actual enumeration value
266
     */
267
    void visitEnum(@Nullable String name, @NonNull String desc, @NonNull String value) {
268
        putName(name);
×
269
        putString('e', desc);
×
270
        putString(value);
×
271
    }
×
272

273
    /**
274
     * Visits a nested annotation value of the annotation.
275
     *
276
     * @param name
277
     *            the value name
278
     * @param desc
279
     *            the class descriptor of the nested annotation class
280
     *
281
     * @return a visitor to visit the actual nested annotation value
282
     */
283
    @NonNull
284
    AnnotationVisitor visitAnnotation(@Nullable String name, @NonNull String desc) {
285
        putName(name);
×
286

287
        // Write tag and type, and reserve space for value count.
288
        putString('@', desc);
×
289
        bv.putShort(0);
×
290

291
        return new AnnotationVisitor(this, true);
×
292
    }
293

294
    /**
295
     * Visits an array value of the annotation. Note that arrays of primitive types can be passed as value to
296
     * {@link #visit(String, Object)}.
297
     *
298
     * @param name
299
     *            the value name
300
     *
301
     * @return a visitor to visit the actual array value elements; the 'name' parameters passed to the methods of this
302
     *         visitor are ignored
303
     */
304
    @NonNull
305
    AnnotationVisitor visitArray(@Nullable String name) {
306
        putName(name);
1✔
307

308
        // Write tag, and reserve space for array size.
309
        putArrayLength(0);
1✔
310

311
        return new AnnotationVisitor(this, false);
1✔
312
    }
313

314
    /**
315
     * Visits the end of the annotation.
316
     */
317
    @SuppressWarnings("NumericCastThatLosesPrecision")
318
    void visitEnd() {
319
        byte[] data = bv.getData();
1✔
320
        data[offset] = (byte) (attributeCount >>> 8);
1✔
321
        data[offset + 1] = (byte) attributeCount;
1✔
322
    }
1✔
323

324
    /**
325
     * Returns the size of this annotation list.
326
     */
327
    @NonNegative
328
    public int getSize() {
329
        int size = 0;
1✔
330
        AnnotationVisitor annotation = this;
1✔
331

332
        while (annotation != null) {
1✔
333
            size += annotation.getByteLength();
1✔
334
            annotation = annotation.next;
1✔
335
        }
336

337
        return size;
1✔
338
    }
339

340
    /**
341
     * Puts the annotations of this annotation writer list into the given byte vector.
342
     */
343
    public void put(@NonNull ByteVector out) {
344
        AnnotationVisitor aw = this;
1✔
345
        AnnotationVisitor last = null;
1✔
346
        int n = 0;
1✔
347
        int size = 2;
1✔
348

349
        while (aw != null) {
1✔
350
            n++;
1✔
351
            size += aw.getByteLength();
1✔
352
            aw.prev = last;
1✔
353
            last = aw;
1✔
354
            aw = aw.next;
1✔
355
        }
356

357
        out.putInt(size);
1✔
358
        out.putShort(n);
1✔
359
        putFromLastToFirst(out, last);
1✔
360
    }
1✔
361

362
    private static void putFromLastToFirst(@NonNull ByteVector out, @Nullable AnnotationVisitor aw) {
363
        while (aw != null) {
1✔
364
            out.putByteVector(aw.bv);
1✔
365
            aw = aw.prev;
1✔
366
        }
367
    }
1✔
368

369
    /**
370
     * Puts the given annotation lists into the given byte vector.
371
     */
372
    public static void put(@NonNull ByteVector out, @NonNull AnnotationVisitor[] anns) {
373
        putNumberAndSizeOfAnnotations(out, anns);
1✔
374

375
        for (AnnotationVisitor ann : anns) {
1✔
376
            AnnotationVisitor last = putNumberOfAnnotations(out, ann);
1✔
377
            putFromLastToFirst(out, last);
1✔
378
        }
379
    }
1✔
380

381
    private static void putNumberAndSizeOfAnnotations(@NonNull ByteVector out, @NonNull AnnotationVisitor[] anns) {
382
        int numAnns = anns.length;
1✔
383
        int size = 1 + 2 * numAnns;
1✔
384

385
        for (AnnotationVisitor aw : anns) {
1✔
386
            if (aw != null) {
1✔
387
                size += aw.getSize();
1✔
388
            }
389
        }
390

391
        out.putInt(size).putByte(numAnns);
1✔
392
    }
1✔
393

394
    @Nullable
395
    private static AnnotationVisitor putNumberOfAnnotations(@NonNull ByteVector out, @Nullable AnnotationVisitor aw) {
396
        AnnotationVisitor last = null;
1✔
397
        int n = 0;
1✔
398

399
        while (aw != null) {
1✔
400
            n++;
1✔
401
            aw.prev = last;
1✔
402
            last = aw;
1✔
403
            aw = aw.next;
1✔
404
        }
405

406
        out.putShort(n);
1✔
407
        return last;
1✔
408
    }
409
}
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