• 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

80.86
/main/src/main/java/mockit/asm/metadata/ClassMetadataReader.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.metadata;
7

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

11
import java.nio.charset.Charset;
12
import java.util.ArrayList;
13
import java.util.Collections;
14
import java.util.EnumSet;
15
import java.util.List;
16

17
import mockit.asm.jvmConstants.Access;
18

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

21
public final class ClassMetadataReader extends ObjectWithAttributes {
22
    private static final Charset UTF8 = Charset.forName("UTF-8");
1✔
23
    private static final ConstantPoolTag[] CONSTANT_POOL_TAGS = ConstantPoolTag.values();
1✔
24

25
    enum ConstantPoolTag { // values from JVM spec Table 4.4.A
1✔
26
        No0, // 0
1✔
27
        Utf8(2), // 1 (has variable size)
1✔
28
        No2, // 2
1✔
29
        Integer(4), // 3
1✔
30
        Float(4), // 4
1✔
31
        Long(8), // 5
1✔
32
        Double(8), // 6
1✔
33
        Class(2), // 7
1✔
34
        String(2), // 8
1✔
35
        FieldRef(4), // 9
1✔
36
        MethodRef(4), // 10
1✔
37
        InterfaceMethodRef(4), // 11
1✔
38
        NameAndType(4), // 12
1✔
39
        No13, No14, MethodHandle(3), // 15, added in Java 7
1✔
40
        MethodType(2), // 16, added in Java 7
1✔
41
        ConstantDynamic(4), // 17, added in Java 11
1✔
42
        InvokeDynamic(4), // 18, added in Java 7
1✔
43
        Module(2), // 19, added in Java 9
1✔
44
        Package(2); // 20, added in Java 9
1✔
45

46
        @NonNegative
47
        final int itemSize;
48

49
        ConstantPoolTag() {
1✔
50
            itemSize = 0;
1✔
51
        }
1✔
52

53
        ConstantPoolTag(@NonNegative int itemSize) {
1✔
54
            this.itemSize = itemSize;
1✔
55
        }
1✔
56
    }
57

58
    public enum Attribute {
1✔
59
        Annotations, Parameters, Signature
1✔
60
    }
61

62
    @NonNull
63
    private final byte[] code;
64
    @NonNull
65
    private final int[] cpItemCodeIndexes;
66
    @Nullable
67
    private final EnumSet<Attribute> attributesToRead;
68

69
    /**
70
     * The constant pool starts at index 10 in the code array; this is the end index, which must be computed as it's not
71
     * stored anywhere.
72
     */
73
    @NonNegative
74
    private final int cpEndIndex;
75

76
    @NonNegative
77
    private int fieldsEndIndex;
78
    @NonNegative
79
    private int methodsEndIndex;
80

81
    @NonNegative
82
    public static int readVersion(@NonNull byte[] code) {
83
        int byte0 = (code[4] & 0xFF) << 24;
×
84
        int byte1 = (code[5] & 0xFF) << 16;
×
85
        int byte2 = (code[6] & 0xFF) << 8;
×
86
        int byte3 = code[7] & 0xFF;
×
87
        return byte0 | byte1 | byte2 | byte3;
×
88
    }
89

90
    public ClassMetadataReader(@NonNull byte[] code) {
91
        this(code, null);
1✔
92
    }
1✔
93

94
    public ClassMetadataReader(@NonNull byte[] code, @Nullable EnumSet<Attribute> attributesToRead) {
1✔
95
        this.code = code;
1✔
96
        int cpItemCount = readUnsignedShort(8);
1✔
97
        int[] cpTable = new int[cpItemCount];
1✔
98
        cpItemCodeIndexes = cpTable;
1✔
99
        this.attributesToRead = attributesToRead;
1✔
100
        cpEndIndex = findEndIndexOfConstantPoolTable(cpTable);
1✔
101
    }
1✔
102

103
    @NonNegative
104
    private int readUnsignedShort(@NonNegative int codeIndex) {
105
        byte[] b = code;
1✔
106
        int i = codeIndex;
1✔
107
        int byte0 = (b[i] & 0xFF) << 8;
1✔
108
        i++;
1✔
109
        int byte1 = b[i] & 0xFF;
1✔
110
        return byte0 | byte1;
1✔
111
    }
112

113
    private int readInt(@NonNegative int codeIndex) {
114
        byte[] b = code;
1✔
115
        int i = codeIndex;
1✔
116
        int byte0 = (b[i] & 0xFF) << 24;
1✔
117
        i++;
1✔
118
        int byte1 = (b[i] & 0xFF) << 16;
1✔
119
        i++;
1✔
120
        int byte2 = (b[i] & 0xFF) << 8;
1✔
121
        i++;
1✔
122
        int byte3 = b[i] & 0xFF;
1✔
123
        return byte0 | byte1 | byte2 | byte3;
1✔
124
    }
125

126
    @NonNegative
127
    private int findEndIndexOfConstantPoolTable(@NonNull int[] cpTable) {
128
        byte[] b = code;
1✔
129
        int codeIndex = 10;
1✔
130

131
        for (int cpItemIndex = 1, n = cpTable.length; cpItemIndex < n; cpItemIndex++) {
1✔
132
            int tagValue = b[codeIndex];
1✔
133
            codeIndex++;
1✔
134
            ConstantPoolTag tag = CONSTANT_POOL_TAGS[tagValue];
1✔
135

136
            cpTable[cpItemIndex] = codeIndex;
1✔
137

138
            int cpItemSize = tag.itemSize;
1✔
139

140
            if (tag == ConstantPoolTag.Long || tag == ConstantPoolTag.Double) {
1✔
141
                cpItemIndex++;
1✔
142
            } else if (tag == ConstantPoolTag.Utf8) {
1✔
143
                int stringLength = readUnsignedShort(codeIndex);
1✔
144
                cpItemSize += stringLength;
1✔
145
            }
146

147
            codeIndex += cpItemSize;
1✔
148
        }
149

150
        return codeIndex;
1✔
151
    }
152

153
    @NonNegative
154
    public int getVersion() {
155
        return readVersion(code);
×
156
    }
157

158
    @NonNegative
159
    public int getAccessFlags() {
160
        return readUnsignedShort(cpEndIndex);
×
161
    }
162

163
    @NonNull
164
    public String getThisClass() {
165
        int cpClassIndex = readUnsignedShort(cpEndIndex + 2);
×
166
        return getTypeDescription(cpClassIndex);
×
167
    }
168

169
    @NonNull
170
    private String getTypeDescription(@NonNegative int cpClassIndex) {
171
        int cpClassCodeIndex = cpItemCodeIndexes[cpClassIndex];
1✔
172
        int cpDescriptionIndex = readUnsignedShort(cpClassCodeIndex);
1✔
173
        return getString(cpDescriptionIndex);
1✔
174
    }
175

176
    @NonNull
177
    private String getString(@NonNegative int cpStringIndex) {
178
        int codeIndex = cpItemCodeIndexes[cpStringIndex];
1✔
179
        int stringLength = readUnsignedShort(codeIndex);
1✔
180
        return new String(code, codeIndex + 2, stringLength, UTF8);
1✔
181
    }
182

183
    @Nullable
184
    public String getSuperClass() {
185
        int cpClassIndex = readUnsignedShort(cpEndIndex + 4);
1✔
186

187
        if (cpClassIndex == 0) {
1!
188
            return null;
×
189
        }
190

191
        return getTypeDescription(cpClassIndex);
1✔
192
    }
193

194
    @Nullable
195
    public String[] getInterfaces() {
196
        int codeIndex = cpEndIndex + 6;
1✔
197
        int interfaceCount = readUnsignedShort(codeIndex);
1✔
198

199
        if (interfaceCount == 0) {
1✔
200
            return null;
1✔
201
        }
202

203
        codeIndex += 2;
1✔
204

205
        String[] interfaces = new String[interfaceCount];
1✔
206

207
        for (int i = 0; i < interfaceCount; i++) {
1✔
208
            int cpInterfaceIndex = readUnsignedShort(codeIndex);
1✔
209
            codeIndex += 2;
1✔
210
            interfaces[i] = getTypeDescription(cpInterfaceIndex);
1✔
211
        }
212

213
        return interfaces;
1✔
214
    }
215

216
    private static class MemberInfo extends ObjectWithAttributes {
217
        @NonNegative
218
        public final int accessFlags;
219
        @NonNull
220
        public final String name;
221
        @NonNull
222
        public final String desc;
223
        @Nullable
224
        public String signature;
225

226
        MemberInfo(@NonNegative int accessFlags, @NonNull String name, @NonNull String desc,
227
                @NonNegative int attributeCount) {
1✔
228
            this.accessFlags = accessFlags;
1✔
229
            this.name = name;
1✔
230
            this.desc = desc;
1✔
231
        }
1✔
232

233
        public final boolean isStatic() {
234
            return (accessFlags & Access.STATIC) != 0;
1✔
235
        }
236

237
        public final boolean isAbstract() {
238
            return (accessFlags & Access.ABSTRACT) != 0;
1✔
239
        }
240

241
        public final boolean isSynthetic() {
242
            return (accessFlags & Access.SYNTHETIC) != 0;
1✔
243
        }
244
    }
245

246
    public static final class FieldInfo extends MemberInfo {
247
        FieldInfo(int accessFlags, @NonNull String name, @NonNull String desc, @NonNegative int attributeCount) {
248
            super(accessFlags, name, desc, attributeCount);
×
249
        }
×
250
    }
251

252
    @NonNull
253
    public List<FieldInfo> getFields() {
254
        int codeIndex = cpEndIndex + 6;
×
255
        int interfaceCount = readUnsignedShort(codeIndex);
×
256
        codeIndex += 2 + 2 * interfaceCount;
×
257

258
        int fieldCount = readUnsignedShort(codeIndex);
×
259
        codeIndex += 2;
×
260

261
        List<FieldInfo> fields;
262

263
        if (fieldCount == 0) {
×
264
            fields = Collections.emptyList();
×
265
        } else {
266
            fields = new ArrayList<>(fieldCount);
×
267

268
            for (int i = 0; i < fieldCount; i++) {
×
269
                int accessFlags = readUnsignedShort(codeIndex);
×
270
                codeIndex += 2;
×
271

272
                int cpNameIndex = readUnsignedShort(codeIndex);
×
273
                codeIndex += 2;
×
274
                String fieldName = getString(cpNameIndex);
×
275

276
                int cpDescIndex = readUnsignedShort(codeIndex);
×
277
                codeIndex += 2;
×
278
                String fieldDesc = getString(cpDescIndex);
×
279

280
                int attributeCount = readUnsignedShort(codeIndex);
×
281
                codeIndex += 2;
×
282

283
                FieldInfo fieldInfo = new FieldInfo(accessFlags, fieldName, fieldDesc, attributeCount);
×
284
                codeIndex = readAttributes(attributeCount, fieldInfo, codeIndex);
×
285
                fields.add(fieldInfo);
×
286
            }
287
        }
288

289
        fieldsEndIndex = codeIndex;
×
290
        return fields;
×
291
    }
292

293
    @NonNegative
294
    private int readAttributes(@NonNegative int attributeCount, @Nullable ObjectWithAttributes attributeOwner,
295
            @NonNegative int codeIndex) {
296
        EnumSet<Attribute> attributes = attributesToRead;
1✔
297
        boolean readAnnotations = false;
1✔
298

299
        if (attributes == null) {
1✔
300
            // noinspection AssignmentToMethodParameter
301
            attributeOwner = null;
1✔
302
        } else {
303
            readAnnotations = attributes.contains(Attribute.Annotations);
1✔
304
        }
305

306
        MethodInfo method = attributeOwner instanceof MethodInfo ? (MethodInfo) attributeOwner : null;
1✔
307

308
        for (int i = 0; i < attributeCount; i++) {
1✔
309
            int cpNameIndex = readUnsignedShort(codeIndex);
1✔
310
            codeIndex += 2;
1✔
311
            String attributeName = getString(cpNameIndex);
1✔
312

313
            int attributeLength = readInt(codeIndex);
1✔
314
            codeIndex += 4;
1✔
315

316
            if (attributeOwner != null) {
1✔
317
                if (method != null) {
1!
318
                    method.readAttributes(attributeName, codeIndex);
1✔
319
                }
320

321
                if (readAnnotations && "RuntimeVisibleAnnotations".equals(attributeName)) {
1✔
322
                    attributeOwner.annotations = readAnnotations(codeIndex);
1✔
323
                }
324
            }
325

326
            codeIndex += attributeLength;
1✔
327
        }
328

329
        return codeIndex;
1✔
330
    }
331

332
    public static final class AnnotationInfo {
333
        @NonNull
334
        public final String name;
335

336
        AnnotationInfo(@NonNull String name) {
1✔
337
            this.name = name;
1✔
338
        }
1✔
339
    }
340

341
    @NonNull
342
    private List<AnnotationInfo> readAnnotations(@NonNegative int codeIndex) {
343
        int numAnnotations = readUnsignedShort(codeIndex);
1✔
344
        codeIndex += 2;
1✔
345

346
        List<AnnotationInfo> annotationInfos = new ArrayList<>(numAnnotations);
1✔
347

348
        for (int i = 0; i < numAnnotations; i++) {
1✔
349
            codeIndex = readAnnotation(annotationInfos, codeIndex);
1✔
350
        }
351

352
        return annotationInfos;
1✔
353
    }
354

355
    @NonNegative
356
    private int readAnnotation(@NonNull List<AnnotationInfo> currentAnnotations, @NonNegative int codeIndex) {
357
        int cpTypeIndex = readUnsignedShort(codeIndex);
1✔
358
        codeIndex += 2;
1✔
359

360
        String annotationTypeDesc = getString(cpTypeIndex);
1✔
361

362
        readUnsignedShort(codeIndex);
1✔
363
        codeIndex += 2;
1✔
364

365
        // for (int i = 0; i < numElementValuePairs; i++) {
366
        // int cpElementNameIndex = readUnsignedShort(codeIndex);
367
        // codeIndex += 2;
368
        //
369
        // int tag = code[codeIndex++];
370
        // // TODO: continue implementing
371
        // }
372

373
        AnnotationInfo annotation = new AnnotationInfo(annotationTypeDesc);
1✔
374
        currentAnnotations.add(annotation);
1✔
375

376
        return codeIndex;
1✔
377
    }
378

379
    @NonNegative
380
    private int getFieldsEndIndex() {
381
        int codeIndex = fieldsEndIndex;
1✔
382

383
        if (codeIndex == 0) {
1!
384
            codeIndex = cpEndIndex + 6;
1✔
385
            int interfaceCount = readUnsignedShort(codeIndex);
1✔
386
            codeIndex += 2 + 2 * interfaceCount;
1✔
387

388
            int fieldCount = readUnsignedShort(codeIndex);
1✔
389
            codeIndex += 2;
1✔
390

391
            for (int i = 0; i < fieldCount; i++) {
1✔
392
                codeIndex += 6;
1✔
393

394
                int attributeCount = readUnsignedShort(codeIndex);
1✔
395
                codeIndex += 2;
1✔
396

397
                codeIndex = readAttributes(attributeCount, null, codeIndex);
1✔
398
            }
399

400
            fieldsEndIndex = codeIndex;
1✔
401
        }
402

403
        return codeIndex;
1✔
404
    }
405

406
    public final class MethodInfo extends MemberInfo {
1✔
407
        @Nullable
408
        public String[] parameters;
409

410
        MethodInfo(int accessFlags, @NonNull String name, @NonNull String desc, @NonNegative int attributeCount) {
1✔
411
            super(accessFlags, name, desc, attributeCount);
1✔
412
        }
1✔
413

414
        public boolean isMethod() {
415
            return name.charAt(0) != '<';
1✔
416
        }
417

418
        public boolean isConstructor() {
419
            return "<init>".equals(name);
×
420
        }
421

422
        void readAttributes(@NonNull String attributeName, @NonNegative int codeIndex) {
423
            assert attributesToRead != null;
1!
424

425
            if ("Code".equals(attributeName)) {
1✔
426
                if (attributesToRead.contains(Attribute.Parameters)) {
1✔
427
                    readParameters(codeIndex);
1✔
428
                }
429
            } else if ("Signature".equals(attributeName) && attributesToRead.contains(Attribute.Signature)) {
1✔
430
                readSignature(codeIndex);
1✔
431
            }
432
        }
1✔
433

434
        private void readParameters(@NonNegative int codeIndex) {
435
            codeIndex += 4;
1✔
436

437
            int codeLength = readInt(codeIndex);
1✔
438
            codeIndex += 4 + codeLength;
1✔
439

440
            int exceptionTableLength = readUnsignedShort(codeIndex);
1✔
441
            codeIndex += 2 + 8 * exceptionTableLength;
1✔
442

443
            int attributeCount = readUnsignedShort(codeIndex);
1✔
444
            codeIndex += 2;
1✔
445

446
            readParameters(attributeCount, codeIndex);
1✔
447
        }
1✔
448

449
        private void readParameters(@NonNegative int attributeCount, @NonNegative int codeIndex) {
450
            for (int i = 0; i < attributeCount; i++) {
1✔
451
                int cpNameIndex = readUnsignedShort(codeIndex);
1✔
452
                codeIndex += 2;
1✔
453
                String attributeName = getString(cpNameIndex);
1✔
454

455
                int attributeLength = readInt(codeIndex);
1✔
456
                codeIndex += 4;
1✔
457

458
                if ("LocalVariableTable".equals(attributeName)) {
1✔
459
                    parameters = readParametersFromLocalVariableTable(codeIndex);
1✔
460
                    break;
1✔
461
                }
462

463
                codeIndex += attributeLength;
1✔
464
            }
465
        }
1✔
466

467
        @Nullable
468
        private String[] readParametersFromLocalVariableTable(@NonNegative int codeIndex) {
469
            int localVariableTableLength = readUnsignedShort(codeIndex);
1✔
470
            codeIndex += 2;
1✔
471

472
            int arraySize = getSumOfArgumentSizes(desc);
1✔
473

474
            if (arraySize == 0) {
1✔
475
                return null;
1✔
476
            }
477

478
            if (!isStatic()) {
1✔
479
                arraySize++;
1✔
480
            }
481

482
            String[] parameterNames = new String[arraySize];
1✔
483

484
            for (int i = 0; i < localVariableTableLength; i++) {
1✔
485
                codeIndex += 4;
1✔
486

487
                int cpLocalVarNameIndex = readUnsignedShort(codeIndex);
1✔
488
                codeIndex += 2;
1✔
489
                String localVarName = getString(cpLocalVarNameIndex);
1✔
490

491
                if ("this".equals(localVarName)) {
1✔
492
                    codeIndex += 4;
1✔
493
                    continue;
1✔
494
                }
495

496
                codeIndex += 2;
1✔
497

498
                int localVarIndex = readUnsignedShort(codeIndex);
1✔
499
                codeIndex += 2;
1✔
500

501
                if (localVarIndex < arraySize) {
1✔
502
                    parameterNames[localVarIndex] = localVarName;
1✔
503
                }
504
            }
505

506
            return compactArray(parameterNames);
1✔
507
        }
508

509
        @NonNegative
510
        private int getSumOfArgumentSizes(@NonNull String memberDesc) {
511
            int sum = 0;
1✔
512
            int i = 1;
1✔
513

514
            while (true) {
515
                char c = memberDesc.charAt(i);
1✔
516
                i++;
1✔
517

518
                switch (c) {
1✔
519
                    case ')':
520
                        return sum;
1✔
521
                    case 'L':
522
                        while (memberDesc.charAt(i) != ';') {
1✔
523
                            i++;
1✔
524
                        }
525
                        i++;
1✔
526
                        sum++;
1✔
527
                        break;
1✔
528
                    case '[':
529
                        while ((c = memberDesc.charAt(i)) == '[') {
1!
530
                            i++;
×
531
                        }
532
                        if (isDoubleSizeType(c)) { // if the array element type is double size...
1!
533
                            i++;
×
534
                            sum++; // ...then count it here, otherwise let the outer loop count it
×
535
                        }
536
                        break;
537
                    default:
538
                        if (isDoubleSizeType(c)) {
1✔
539
                            sum += 2;
1✔
540
                        } else {
541
                            sum++;
1✔
542
                        }
543
                        break;
544
                }
545
            }
1✔
546
        }
547

548
        private boolean isDoubleSizeType(char typeCode) {
549
            return typeCode == 'D' || typeCode == 'J';
1✔
550
        }
551

552
        @Nullable
553
        private String[] compactArray(@NonNull String[] arrayPossiblyWithNulls) {
554
            int n = arrayPossiblyWithNulls.length;
1✔
555
            int j = n - 1;
1✔
556
            int i = 0;
1✔
557

558
            while (i < j) {
1✔
559
                if (arrayPossiblyWithNulls[i] == null) {
1✔
560
                    System.arraycopy(arrayPossiblyWithNulls, i + 1, arrayPossiblyWithNulls, i, j - i);
1✔
561
                    arrayPossiblyWithNulls[j] = null;
1✔
562
                    j--;
1✔
563
                } else {
564
                    i++;
1✔
565
                }
566
            }
567

568
            return n == 1 && arrayPossiblyWithNulls[0] == null ? null : arrayPossiblyWithNulls;
1!
569
        }
570

571
        private void readSignature(@NonNegative int codeIndex) {
572
            int cpSignatureIndex = readUnsignedShort(codeIndex);
1✔
573
            signature = getString(cpSignatureIndex);
1✔
574
        }
1✔
575
    }
576

577
    @NonNull
578
    public List<MethodInfo> getMethods() {
579
        int codeIndex = getFieldsEndIndex();
1✔
580
        int methodCount = readUnsignedShort(codeIndex);
1✔
581
        codeIndex += 2;
1✔
582

583
        List<MethodInfo> methods = new ArrayList<>(methodCount);
1✔
584

585
        for (int i = 0; i < methodCount; i++) {
1✔
586
            int accessFlags = readUnsignedShort(codeIndex);
1✔
587
            codeIndex += 2;
1✔
588

589
            int cpNameIndex = readUnsignedShort(codeIndex);
1✔
590
            codeIndex += 2;
1✔
591
            String methodName = getString(cpNameIndex);
1✔
592

593
            int cpDescIndex = readUnsignedShort(codeIndex);
1✔
594
            codeIndex += 2;
1✔
595
            String methodDesc = getString(cpDescIndex);
1✔
596

597
            int attributeCount = readUnsignedShort(codeIndex);
1✔
598
            codeIndex += 2;
1✔
599

600
            MethodInfo methodInfo = new MethodInfo(accessFlags, methodName, methodDesc, attributeCount);
1✔
601
            codeIndex = readAttributes(attributeCount, methodInfo, codeIndex);
1✔
602
            methods.add(methodInfo);
1✔
603
        }
604

605
        methodsEndIndex = codeIndex;
1✔
606
        return methods;
1✔
607
    }
608

609
    @NonNegative
610
    private int getMethodsEndIndex() {
611
        int codeIndex = methodsEndIndex;
×
612

613
        if (codeIndex == 0) {
×
614
            codeIndex = getFieldsEndIndex();
×
615

616
            int methodCount = readUnsignedShort(codeIndex);
×
617
            codeIndex += 2;
×
618

619
            for (int i = 0; i < methodCount; i++) {
×
620
                codeIndex += 6;
×
621

622
                int attributeCount = readUnsignedShort(codeIndex);
×
623
                codeIndex += 2;
×
624

625
                codeIndex = readAttributes(attributeCount, null, codeIndex);
×
626
            }
627

628
            methodsEndIndex = codeIndex;
×
629
        }
630

631
        return codeIndex;
×
632
    }
633

634
    @NonNull
635
    public List<AnnotationInfo> getAnnotations() {
636
        if (annotations == null) {
×
637
            int codeIndex = getMethodsEndIndex();
×
638
            int attributeCount = readUnsignedShort(codeIndex);
×
639
            codeIndex += 2;
×
640

641
            readAttributes(attributeCount, this, codeIndex);
×
642

643
            if (annotations == null) {
×
644
                annotations = Collections.emptyList();
×
645
            }
646
        }
647

648
        return annotations;
×
649
    }
650
}
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