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

moosetechnology / VerveineJ / 28750184792

05 Jul 2026 06:12PM UTC coverage: 52.626% (+0.2%) from 52.433%
28750184792

push

github

web-flow
Merge pull request #264 from moosetechnology/feat/record

Dealing with record declaration

2023 of 4018 branches covered (50.35%)

Branch coverage included in aggregate %.

44 of 58 new or added lines in 5 files covered. (75.86%)

1 existing line in 1 file now uncovered.

4469 of 8318 relevant lines covered (53.73%)

2.22 hits per line

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

80.05
/app/src/main/java/fr/inria/verveine/extractor/java/visitors/defvisitors/VisitorClassMethodDef.java
1
package fr.inria.verveine.extractor.java.visitors.defvisitors;
2

3
import java.security.MessageDigest;
4
import java.security.NoSuchAlgorithmException;
5
import java.util.ArrayList;
6
import java.util.Collection;
7
import java.util.List;
8

9
import org.apache.commons.codec.digest.DigestUtils;
10
import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
11
import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
12
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
13
import org.eclipse.jdt.core.dom.AssertStatement;
14
import org.eclipse.jdt.core.dom.Assignment;
15
import org.eclipse.jdt.core.dom.Block;
16
import org.eclipse.jdt.core.dom.CatchClause;
17
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
18
import org.eclipse.jdt.core.dom.CompilationUnit;
19
import org.eclipse.jdt.core.dom.ConstructorInvocation;
20
import org.eclipse.jdt.core.dom.ContinueStatement;
21
import org.eclipse.jdt.core.dom.DoStatement;
22
import org.eclipse.jdt.core.dom.EnhancedForStatement;
23
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
24
import org.eclipse.jdt.core.dom.EnumDeclaration;
25
import org.eclipse.jdt.core.dom.Expression;
26
import org.eclipse.jdt.core.dom.ExpressionStatement;
27
import org.eclipse.jdt.core.dom.FieldDeclaration;
28
import org.eclipse.jdt.core.dom.ForStatement;
29
import org.eclipse.jdt.core.dom.IMethodBinding;
30
import org.eclipse.jdt.core.dom.ITypeBinding;
31
import org.eclipse.jdt.core.dom.IfStatement;
32
import org.eclipse.jdt.core.dom.Initializer;
33
import org.eclipse.jdt.core.dom.MethodDeclaration;
34
import org.eclipse.jdt.core.dom.Modifier;
35
import org.eclipse.jdt.core.dom.RecordDeclaration;
36
import org.eclipse.jdt.core.dom.ReturnStatement;
37
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
38
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
39
import org.eclipse.jdt.core.dom.SwitchCase;
40
import org.eclipse.jdt.core.dom.SwitchStatement;
41
import org.eclipse.jdt.core.dom.SynchronizedStatement;
42
import org.eclipse.jdt.core.dom.ThrowStatement;
43
import org.eclipse.jdt.core.dom.TryStatement;
44
import org.eclipse.jdt.core.dom.TypeDeclaration;
45
import org.eclipse.jdt.core.dom.TypeLiteral;
46
import org.eclipse.jdt.core.dom.TypeParameter;
47
import org.eclipse.jdt.core.dom.VariableDeclaration;
48
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
49
import org.eclipse.jdt.core.dom.WhileStatement;
50
import org.moosetechnology.model.famix.famixjavaentities.AnnotationType;
51
import org.moosetechnology.model.famix.famixjavaentities.AnnotationTypeAttribute;
52
import org.moosetechnology.model.famix.famixjavaentities.ContainerEntity;
53
import org.moosetechnology.model.famix.famixjavaentities.Method;
54
import org.moosetechnology.model.famix.famixjavaentities.ParametricClass;
55
import org.moosetechnology.model.famix.famixtraits.TMethod;
56
import org.moosetechnology.model.famix.famixtraits.TWithMethods;
57
import org.moosetechnology.model.famix.famixtraits.TWithTypes;
58

59
import fr.inria.verveine.extractor.java.EntityDictionary;
60
import fr.inria.verveine.extractor.java.VerveineJOptions;
61
import fr.inria.verveine.extractor.java.utils.StubBinding;
62
import fr.inria.verveine.extractor.java.utils.Util;
63
import fr.inria.verveine.extractor.java.visitors.GetVisitedEntityAbstractVisitor;
64

65
/**
66
 * AST Visitor that defines all the (Famix) entities of interest
67
 * Famix entities are stored in a Map along with the IBindings to which they correspond
68
 */
69
public class VisitorClassMethodDef extends GetVisitedEntityAbstractVisitor {
70

71
    protected MessageDigest md5;
72

73
    public VisitorClassMethodDef(EntityDictionary dico, VerveineJOptions options) {
74
                super( dico, options);
4✔
75
        try {
76
            md5 = MessageDigest.getInstance("MD5");
4✔
77
        } catch (NoSuchAlgorithmException e) {
×
78
            e.printStackTrace();
×
79
            md5 = null;
×
80
        }
1✔
81
    }
1✔
82

83
        // VISITOR METHODS
84

85
        @Override
86
        public boolean visit(CompilationUnit node) {
87
                visitCompilationUnit(node);
4✔
88
                return super.visit(node);
4✔
89
        }
90

91
        @Override
92
        public void endVisit(CompilationUnit node) {
93
                endVisitCompilationUnit(node);
3✔
94
        }
1✔
95

96
        /*
97
         * Can only be a class or interface declaration
98
         * Local type: see comment of visit(ClassInstanceCreation node)
99
         */
100
        @Override
101
        public boolean visit(TypeDeclaration node) {
102
                //System.err.println("TRACE, Visiting TypeDeclaration: "+node.getName().getIdentifier());
103
                ITypeBinding bnd = (ITypeBinding) StubBinding.getDeclarationBinding(node);
4✔
104

105
                @SuppressWarnings("unchecked")
106
                List<TypeParameter> typeParameters = (List<TypeParameter>) node.typeParameters();
3✔
107

108
                // may be could use this.referredType instead of dico.ensureFamixClass ?
109
                org.moosetechnology.model.famix.famixtraits.TType fmx;
110
                if (bnd.isInterface()) {
3✔
111
                        fmx = dico.ensureFamixInterface(
7✔
112
                                bnd, 
113
                                /*name*/node.getName().getIdentifier(), 
4✔
114
                                (TWithTypes) 
115
                                /*owner*/context.top(), 
3✔
116
                                /*isGeneric*/typeParameters.size()>0,
6✔
117
                                node.getModifiers());
1✔
118
                } else if (dico.isThrowable(bnd)) {
5✔
119
                        fmx = dico.ensureFamixException(
7✔
120
                                bnd, 
121
                                /*name*/node.getName().getIdentifier(), 
4✔
122
                                (TWithTypes) 
123
                                /*owner*/context.top(), 
3✔
124
                                /*isGeneric*/typeParameters.size()>0,
4!
125
                                node.getModifiers());
1✔
126
                } else {
127
                        fmx = dico.ensureFamixClass(
6✔
128
                                        bnd, 
129
                                        /*name*/node.getName().getIdentifier(), 
4✔
130
                                        /*owner*/context.top(), 
2✔
131
                                        /*isGeneric*/typeParameters.size()>0,
6✔
132
                                        node.getModifiers());
1✔
133
                }
134
                if (fmx != null) {
2!
135
                        Util.recursivelySetIsStub(fmx, false);
3✔
136

137
                        // if it is a generic and some parameterizedTypes were created for it,
138
                        // they are marked as stub which is not right
139
                        if (typeParameters.size() > 0) {
3✔
140
                                for (ParametricClass candidate : dico.getEntityByName(ParametricClass.class,
14✔
141
                                                node.getName().getIdentifier())) {
2✔
142
                                        candidate.setIsStub(false);
4✔
143
                                }
1✔
144
                        }
145

146
                        this.context.pushType(fmx);
4✔
147

148
                        if (options.withAnchors()) {
4!
149
                                dico.addSourceAnchor(fmx, node);
6✔
150
                        }
151

152

153
                        return super.visit(node);
4✔
154
                } else {
155
                        return false;
×
156
                }
157
        }
158

159
        @Override
160
        public void endVisit(TypeDeclaration node) {
161
                this.context.popType();
4✔
162
                super.endVisit(node);
3✔
163
        }
1✔
164

165
        /*
166
         * Records are immutable data classes that require only the type and name of fields.
167
         * The equals, hashCode, and toString methods, as well as the private, final fields and public constructor, are generated by the Java compiler.
168
         * A record is always a final class never an interface or exception.
169
         */
170
        @Override
171
        public boolean visit(RecordDeclaration node) {
172
                //System.err.println("TRACE, Visiting RecordDeclaration: "+node.getName().getIdentifier());
173
                ITypeBinding bnd = (ITypeBinding) StubBinding.getDeclarationBinding(node);
4✔
174

175
                @SuppressWarnings("unchecked")
176
                List<TypeParameter> typeParameters = (List<TypeParameter>) node.typeParameters();
3✔
177

178
                org.moosetechnology.model.famix.famixjavaentities.Class fmx = dico.ensureFamixClass( bnd, /*name*/node.getName().getIdentifier(), /*owner*/context.top(), /*isGeneric*/typeParameters.size()>0, node.getModifiers());
17!
179

180
                if (fmx != null) {
2!
181
                        Util.recursivelySetIsStub(fmx, false);
3✔
182
                        fmx.setIsFinal(true);
4✔
183

184
                        // if it is a generic and some parameterizedTypes were created for it,
185
                        // they are marked as stub which is not right
186
                        if (typeParameters.size() > 0) {
3!
NEW
187
                                for (ParametricClass candidate : dico.getEntityByName(ParametricClass.class,
×
NEW
188
                                                node.getName().getIdentifier())) {
×
NEW
189
                                        candidate.setIsStub(false);
×
NEW
190
                                }
×
191
                        }
192

193
                        this.context.pushType(fmx);
4✔
194

195
                        if (options.withAnchors()) {
4!
196
                                dico.addSourceAnchor(fmx, node);
6✔
197
                        }
198

199
                        return super.visit(node);
4✔
200
                } else {
NEW
201
                        return false;
×
202
                }
203
        }
204

205
        @Override
206
        public void endVisit(RecordDeclaration node) {
207
                this.context.popType();
4✔
208
                super.endVisit(node);
3✔
209
        }
1✔
210

211
        /**
212
         * See field {@link VisitorClassMethodDef#anonymousSuperTypeName}<br>
213
         * We could test if it is a local type (inner/anonymous) and not define it in case it does not make any reference
214
         * to anything outside its owner class. But it would be a lot of work for probably little gain.
215
         */
216
        @Override
217
        public boolean visit(ClassInstanceCreation node) {
218
                //                System.err.println("TRACE, Visiting ClassInstanceCreation: " + node);
219
                possiblyAnonymousClassDeclaration(node);
3✔
220
                return super.visit(node);
4✔
221
        }
222

223
        /**
224
         * See field {@link VisitorClassMethodDef#anonymousSuperTypeName}
225
         */
226
        @Override
227
        public boolean visit(AnonymousClassDeclaration node) {
228
                //                System.err.println("TRACE, Visiting AnonymousClassDeclaration");
229
                org.moosetechnology.model.famix.famixjavaentities.Type fmx;
230
                ITypeBinding bnd = (ITypeBinding) StubBinding.getDeclarationBinding(node);
4✔
231

232
                int modifiers = (bnd != null) ? bnd.getModifiers() : EntityDictionary.UNKNOWN_MODIFIERS;
6!
233
                if (bnd.isInterface()) {
3!
234
                        fmx = this.dico.ensureFamixInterface(
×
235
                                        bnd, Util.stringForAnonymousName(getAnonymousSuperTypeName(), context), 
×
236
                                        (ContainerEntity) 
237
                                        /*owner*/context.top(), 
×
238
                                        /*isGeneric*/false, 
239
                                        modifiers);
240
                } else {
241
                        fmx = this.dico.ensureFamixClass(
6✔
242
                                        bnd, Util.stringForAnonymousName(getAnonymousSuperTypeName(), context), 
6✔
243
                                        (ContainerEntity) 
244
                                        /*owner*/context.top(), 
4✔
245
                                        /*isGeneric*/false, 
246
                                        modifiers);
247
                }
248

249
                if (fmx != null) {
2!
250
                        Util.recursivelySetIsStub(fmx, false);
3✔
251

252
                        if (options.withAnchors()) {
4!
253
                                dico.addSourceAnchor(fmx, node);
6✔
254
                        }
255
                        this.context.pushType(fmx);
4✔
256
                        return super.visit(node);
4✔
257
                } else {
258
                        return false;
×
259
                }
260
        }
261

262
        @Override
263
        public void endVisit(AnonymousClassDeclaration node) {
264
                if (!anonymousSuperTypeName.empty()) {
4✔
265
                        anonymousSuperTypeName.pop();
4✔
266
                }
267
                this.context.popType();
4✔
268
                super.endVisit(node);
3✔
269
        }
1✔
270

271
        @Override
272
        public boolean visit(EnumDeclaration node) {
273
//                System.err.println("TRACE, Visiting EnumDeclaration: "+node.getName().getIdentifier());
274
                ITypeBinding bnd = (ITypeBinding) StubBinding.getDeclarationBinding(node);
4✔
275

276
                org.moosetechnology.model.famix.famixjavaentities.Enum fmx = dico.ensureFamixEnum(bnd, node.getName().getIdentifier(), (TWithTypes) context.top());
12✔
277
                if (fmx != null) {
2!
278
                        Util.recursivelySetIsStub(fmx, false);
3✔
279

280
                        this.context.pushType(fmx);
4✔
281
                        if (options.withAnchors()) {
4!
282
                                dico.addSourceAnchor(fmx, node);
6✔
283
                        }
284
                        return super.visit(node);
4✔
285
                } else {
286
                        return false;
×
287
                }
288
        }
289

290
        @Override
291
        public void endVisit(EnumDeclaration node) {
292
                this.context.popType();
4✔
293
                super.endVisit(node);
3✔
294
        }
1✔
295

296
        @Override
297
        public boolean visit(AnnotationTypeDeclaration node) {
298
                ITypeBinding bnd = node.resolveBinding();
3✔
299
                AnnotationType fmx = dico.ensureFamixAnnotationType(bnd, node.getName().getIdentifier(), (ContainerEntity) context.top());
12✔
300
                if (fmx != null) {
2!
301
                        Util.recursivelySetIsStub(fmx, false);
3✔
302
                        if (options.withAnchors()) {
4!
303
                                dico.addSourceAnchor(fmx, node);
6✔
304
                        }
305

306
                        context.pushType(fmx);
4✔
307
                        return super.visit(node);
4✔
308
                }
309
                else {
310
                        context.pushType(null);
×
311
                        return false;
×
312
                }
313
        }
314

315
        @Override
316
        public void endVisit(AnnotationTypeDeclaration node) {
317
                this.context.popType();
4✔
318
                super.endVisit(node);
3✔
319
        }
1✔
320

321
        /**
322
     * MethodDeclaration ::=
323
     *     [ Javadoc ] { ExtendedModifier } [ &lt; TypeParameter { , TypeParameter } &gt; ] ( Type | void )
324
     *         Identifier (
325
     *             [ ReceiverParameter , ] [ FormalParameter { , FormalParameter } ]
326
     *         ) { Dimension }
327
     *         [ throws Type { , Type } ]
328
     *         ( Block | ; )
329
     *  Also includes ConstructorDeclaration (same thing without return type)
330
     *
331
         * Local type: same as {@link VisitorClassMethodDef#visit(ClassInstanceCreation)}, 
332
         * we create it even if it is a local method because there are too many ways it can access external things
333
         */
334
        @SuppressWarnings("unchecked")
335
        @Override
336
        public boolean visit(MethodDeclaration node) {
337
                IMethodBinding bnd = (IMethodBinding) StubBinding.getDeclarationBinding(node);
4✔
338
        Collection<String> paramTypes = new ArrayList<>();
4✔
339
        for (SingleVariableDeclaration param : (List<SingleVariableDeclaration>) node.parameters()) {
11✔
340
            paramTypes.add( Util.jdtTypeName(param.getType()));
6✔
341
        }
1✔
342

343
                Method fmx = dico.ensureFamixMethod(
6✔
344
                                bnd, 
345
                                node.getName().getIdentifier(), 
6✔
346
                                paramTypes, 
347
                                /*returnType*/null, 
348
                                /*owner*/(TWithMethods)context.topType(), 
3✔
349
                                node.getModifiers());
1✔
350

351
                if (fmx != null) {
2!
352
                        fmx.setIsStub(false);
4✔
353
                        // fmx.setBodyHash(this.computeHashForMethodBody(node));
354

355
                        this.context.pushMethod(fmx);
4✔
356

357
                        if (options.withAnchors()) {
4!
358
                                dico.addSourceAnchor(fmx, node);
6✔
359
                        }
360

361
                        if (node.getBody() != null) {
3✔
362
                                context.setTopMethodCyclo(1);
5✔
363
                        } else if(!Modifier.isNative(node.getModifiers())) {
4✔
364
                                // If the method is native then it is not abstract, as it has a concrete implementation in C/C++
365

366
                                // In interfaces you don't need to explicitly define the method as abstract
367
                                // However, if they don't have a body, they are!
368
                                fmx.setIsAbstract(true);
4✔
369
                        }
370
                        return super.visit(node);
4✔
371
                } else {
372
                        this.context.pushMethod(null);
×
373
                        return false;
×
374
                }
375
        }
376

377
        @Override
378
        public void endVisit(MethodDeclaration node) {
379
                closeMethodDeclaration();
2✔
380
                super.endVisit(node);
3✔
381
        }
1✔
382

383
        /**
384
     * BodyDeclaration ::=
385
     *                [ ... ]
386
     *                 FieldDeclaration
387
     *                 Initializer
388
     *                 MethodDeclaration (for methods and constructors)
389
     * Initializer ::=
390
     *      [ static ] Block
391
     */
392
    @Override
393
        public boolean visit(Initializer node) {
394
                Method fmx = (Method) createInitBlock(Modifier.isStatic(node.getModifiers()), true);
10✔
395
                // init-block don't have return type so no need to create a reference from this class to the "declared return type" class when classSummary is TRUE
396
                // also no parameters specified here, so no references to create either
397

398
                if (fmx != null) {
2!
399
            dico.setMethodModifiers(fmx, node.getModifiers());
6✔
400
            if (options.withAnchors()) {
4!
401
                    dico.addSourceAnchor(fmx, node);
6✔
402
                        }
403

404
                        if (node.getBody() != null) {
3!
405
                                context.setTopMethodCyclo(1);
4✔
406
                        }
407

408
                        return super.visit(node);
4✔
409
                } else {
410
                        this.context.pushMethod(null);   // because endVisit(Initializer) will pop it out
×
411
                        return false;
×
412
                }
413
        }
414

415
        @Override
416
        public void endVisit(Initializer node) {
417
                closeMethodDeclaration();
2✔
418
                super.endVisit(node);
3✔
419
        }
1✔
420

421
        @SuppressWarnings("unchecked")
422
        @Override
423
        public boolean visit(EnumConstantDeclaration node) {
424
                for (Expression expr : (List<Expression>)node.arguments()) {
11✔
425
                        if (expr != null) {
2!
426
                                createInitBlock(true , false); // Enum Constants are static
7✔
427
                                break;  // we created the INIT_BLOCK, no need to look for other declaration that would only ensure the same creation
1✔
428
                        }
429
                }
×
430
                return super.visit(node);
4✔
431
        
432
        }
433

434
    public void endVisit(EnumConstantDeclaration node) {
435
        closeOptionalInitBlock();
2✔
436
    }
1✔
437

438
        @SuppressWarnings("unchecked")
439
        @Override
440
        public boolean visit(FieldDeclaration node) {
441
                boolean hasInitBlock = false;
2✔
442
                for (VariableDeclaration varDecl : (List<VariableDeclaration>)node.fragments() ) {
11✔
443
                        if (varDecl.getInitializer() != null) {
3✔
444
                                createInitBlock(Modifier.isStatic(node.getModifiers()), false);
9✔
445
                                hasInitBlock = true;
2✔
446
                                break;  // we created the INIT_BLOCK, no need to look for other declaration that would only ensure the same creation
1✔
447
                        }
448
                }
1✔
449
                return hasInitBlock;
2✔
450
        }
451

452
    public void endVisit(FieldDeclaration node) {
453
        closeOptionalInitBlock();
2✔
454
    }
1✔
455

456
        @Override
457
        public boolean visit(AnnotationTypeMemberDeclaration node) {
458
//                System.err.println("TRACE, Visiting AnnotationTypeMemberDeclaration: "+node.getName().getIdentifier());
459
                IMethodBinding bnd = node.resolveBinding();
3✔
460

461
                // note"Annotation members looks like methods, but they are closer to attributes
462
                AnnotationTypeAttribute fmx = dico.ensureFamixAnnotationTypeAttribute(bnd, node.getName().getIdentifier(), (AnnotationType) context.topType());
12✔
463
                if (fmx != null) {
2!
464
                        fmx.setIsStub(false);
4✔
465
                        if (options.withAnchors()) {
4!
466
                                dico.addSourceAnchor(fmx, node);
6✔
467
                        }
468

469
                        context.pushAnnotationMember(fmx);
4✔
470
                        return super.visit(node);
4✔
471
                } else {
472
                        context.pushAnnotationMember(null);
×
473
                        return false;
×
474
                }
475
        }
476

477
        @Override
478
        public void endVisit(AnnotationTypeMemberDeclaration node) {
479
                this.context.popAnnotationMember();
4✔
480
                super.endVisit(node);
3✔
481
        }
1✔
482

483
        @Override
484
        public boolean visit(ConstructorInvocation node) {
485
                //                System.err.println("TRACE, Visiting ConstructorInvocation: ");
486
                this.context.addTopMethodNOS(1);
4✔
487
                return super.visit(node);
4✔
488
        }
489

490
        @Override
491
        public boolean visit(SuperConstructorInvocation node) {
492
                this.context.addTopMethodNOS(1);
4✔
493
                return super.visit(node);
4✔
494
        }
495

496
        // "SomeClass.class"
497
        public boolean visit(TypeLiteral node) {
498
                dico.ensureFamixMetaClass(null);
5✔
499
                return false;
2✔
500
        }
501

502
        @Override
503
        public boolean visit(ThrowStatement node) {
504
                this.context.addTopMethodNOS(1);
4✔
505
                return super.visit(node);
4✔
506
        }
507

508
        @Override
509
        public boolean visit(CatchClause node) {
510
                this.context.addTopMethodCyclo(1);
4✔
511
                return super.visit(node);
4✔
512
        }
513

514
        @Override
515
        public boolean visit(AssertStatement node) {
516
                this.context.addTopMethodNOS(1);
×
517
                return super.visit(node);
×
518
        }
519

520
        @Override
521
        public boolean visit(Assignment node) {
522
                this.context.addTopMethodNOS(1);
4✔
523
                return super.visit(node);
4✔
524
        }
525

526
        @Override
527
        public boolean visit(ContinueStatement node) {
528
                this.context.addTopMethodNOS(1);
×
529
                return super.visit(node);
×
530
        }
531

532
        @Override
533
        public boolean visit(DoStatement node) {
534
                this.context.addTopMethodCyclo(1);
×
535
                this.context.addTopMethodNOS(1);
×
536
                return super.visit(node);
×
537
        }
538

539
        @Override
540
        public boolean visit(ExpressionStatement node) {
541
                this.context.addTopMethodNOS(1);
4✔
542
                return super.visit(node);
4✔
543
        }
544

545
        @Override
546
        public boolean visit(EnhancedForStatement node) {
547
                this.context.addTopMethodCyclo(1);
4✔
548
                this.context.addTopMethodNOS(1);
4✔
549
                return super.visit(node);
4✔
550
        }
551

552
        @Override
553
        public boolean visit(ForStatement node) {
554
                this.context.addTopMethodCyclo(1);
4✔
555
                this.context.addTopMethodNOS(1);
4✔
556
                return super.visit(node);
4✔
557
        }
558

559
        @Override
560
        public boolean visit(IfStatement node) {
561
                this.context.addTopMethodCyclo(1);
4✔
562
                this.context.addTopMethodNOS(1);
4✔
563
                return super.visit(node);
4✔
564
        }
565

566
        @Override
567
        public boolean visit(ReturnStatement node) {
568
                this.context.addTopMethodNOS(1);
4✔
569
                return super.visit(node);
4✔
570
        }
571

572
        @Override
573
        public boolean visit(SwitchCase node) {
574
                this.context.addTopMethodCyclo(1);
4✔
575
                this.context.addTopMethodNOS(1);
4✔
576
                return super.visit(node);
4✔
577
        }
578

579
        @Override
580
        public boolean visit(SwitchStatement node) {
581
                this.context.addTopMethodNOS(1);
4✔
582
                return super.visit(node);
4✔
583
        }
584

585
        @Override
586
        public boolean visit(SynchronizedStatement node) {
587
                this.context.addTopMethodNOS(1);
×
588
                return super.visit(node);
×
589
        }
590

591
        @Override
592
        public boolean visit(TryStatement node) {
593
                this.context.addTopMethodCyclo(1);
4✔
594
                this.context.addTopMethodNOS(1);
4✔
595
                return super.visit(node);
4✔
596
        }
597

598
        @Override
599
        public boolean visit(VariableDeclarationStatement node) {
600
                this.context.addTopMethodNOS(1);
4✔
601
                return super.visit(node);
4✔
602
        }
603

604
        @Override
605
        public boolean visit(WhileStatement node) {
606
                this.context.addTopMethodCyclo(1);
4✔
607
                this.context.addTopMethodNOS(1);
4✔
608
                return super.visit(node);
4✔
609
        }
610

611
        // UTILITY METHODS
612

613
        private String computeHashForMethodBody(MethodDeclaration node) {
NEW
614
                Block body = node.getBody();
×
NEW
615
                if ( (body == null) || (md5 == null) ) {
×
NEW
616
            return "0";
×
617
        }
NEW
618
        byte[] bytes = node.getBody().toString().replaceAll("\\r|\\n|\\t", "").getBytes();
×
619

NEW
620
       return DigestUtils.md5Hex(bytes).toUpperCase();
×
621
        }
622

623
    /**
624
     * Ensures the creation of the fake method: {@link EntityDictionary#INIT_BLOCK_NAME}
625
     *
626
     * Used in the case of instance/class initializer and initializing expressions of FieldDeclarations and EnumConstantDeclarations
627
         */
628
        protected TMethod createInitBlock(Boolean isStatic, Boolean isInitializationBlock) {
629
                // putting field's initialization code in an INIT_BLOCK_NAME method
630
                Method ctxtMeth = (Method) this.context.topMethod();
5✔
631
                if (ctxtMeth != null && !ctxtMeth.getIsInitializer() && ctxtMeth.getIsClassSide() != isStatic) {
10!
632
                        ctxtMeth = null;
×
633
                } else {
634
                        if (ctxtMeth != null && ctxtMeth.getParentType() != context.topType()) {
8!
635
                                /* We are in a field initialization in an anonymous class created in another field initialization.
636
                                 * In this example, we are in the declaration of aField2:
637
                                 * class Class1 {
638
                                 *         class Class2 {}
639
                                 *  Class2 aField1 = new Class2() {
640
                                 *                 Class3 aField2 = xyz;
641
                                 *   }
642
                                 * }
643
                                 *
644
                                 * This means we have to create the Initializer of the inner class (in the example above, Class2::<Initializer>).
645
                                 */
646
                                ctxtMeth = null;
2✔
647
                        }
648
                }
649
                if (ctxtMeth == null) {
2!
650
                        ctxtMeth = dico.ensureFamixInitializer(
6✔
651
                                        (TWithMethods) context.topType(), isStatic, isInitializationBlock);
4✔
652
                        ctxtMeth.setIsStub(false);
4✔
653
                        ctxtMeth.setIsDead(false);
3✔
654
                        // initialization block doesn't have return type so no need to create a reference from its class to the "declared return type" class when classSummary is TRUE
655
                        pushInitBlockMethod(ctxtMeth);
3✔
656
                }
657
                return ctxtMeth;
2✔
658
        }
659

660
        /**
661
         * Special method InitBlock may be "created" in various steps,
662
         * mainly when attributes are declared+initialized with the result of a method call.<br>
663
         * In such a case, we need to recover the previous metric values to add to them
664
         * @param ctxtMeth -- the InitBlock FamixMethod
665
         */
666
        protected void pushInitBlockMethod(TMethod ctxtMeth) {
667
                int nos = (ctxtMeth.getNumberOfStatements() == null) ? 0 : ctxtMeth.getNumberOfStatements().intValue();
9✔
668
                int cyclo = (ctxtMeth.getCyclomaticComplexity() == null) ? 0 : ctxtMeth.getCyclomaticComplexity().intValue();
9✔
669
                this.context.pushMethod(ctxtMeth);
4✔
670
                if ((nos != 0) || (cyclo != 0)) {
4!
671
                        context.setTopMethodNOS(nos);
4✔
672
                        context.setTopMethodCyclo(cyclo);
4✔
673
                }
674
        }
1✔
675

676
        protected void closeOptionalInitBlock() {
677
                Method ctxtMeth = (Method)this.context.topMethod();
5✔
678
                if ((ctxtMeth != null) && ctxtMeth.getIsInitializer() && !ctxtMeth.getIsConstructor()) {
10!
679
                        closeMethodDeclaration();
2✔
680
                }
681
        }
1✔
682

683
        /**
684
         * When closing a method declaration, we need to take care of some metrics that are also collected
685
         */
686
        protected void closeMethodDeclaration() {
687
                if (context.topMethod() != null) {
4!
688
                        int cyclo = context.getTopMethodCyclo();
4✔
689
                        int nos = context.getTopMethodNOS();
4✔
690
                        Method fmx = (Method) this.context.popMethod();
5✔
691
                        if (fmx != null) {
2!
692
                                fmx.setNumberOfStatements(nos);
4✔
693
                                fmx.setCyclomaticComplexity(cyclo);
4✔
694
                        }
695
                }
696
        }
1✔
697

698
}
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