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

moosetechnology / VerveineJ / 16644586796

31 Jul 2025 08:58AM UTC coverage: 50.681%. Remained the same
16644586796

Pull #150

github

web-flow
Merge 0e7ee8fa9 into 4823e9af5
Pull Request #150: fix #149

1893 of 3964 branches covered (47.75%)

Branch coverage included in aggregate %.

1 of 2 new or added lines in 1 file covered. (50.0%)

4283 of 8222 relevant lines covered (52.09%)

2.08 hits per line

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

72.35
/app/src/main/java/fr/inria/verveine/extractor/java/visitors/refvisitors/VisitorInvocRef.java
1
package fr.inria.verveine.extractor.java.visitors.refvisitors;
2

3
import fr.inria.verveine.extractor.java.EntityDictionary;
4
import fr.inria.verveine.extractor.java.VerveineJOptions;
5
import fr.inria.verveine.extractor.java.utils.NodeTypeChecker;
6
import fr.inria.verveine.extractor.java.utils.StubBinding;
7
import fr.inria.verveine.extractor.java.utils.Util;
8
import org.eclipse.jdt.core.dom.Type;
9
import org.eclipse.jdt.core.dom.*;
10
import org.moosetechnology.model.famix.famixjavaentities.*;
11
import org.moosetechnology.model.famix.famixtraits.*;
12

13
import java.io.RandomAccessFile;
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.List;
17

18
public class VisitorInvocRef extends AbstractRefVisitor {
19

20
        /**
21
         * Useful to keep the FamixType created in the specific case of "new
22
         * SomeClass().someMethod()"
23
         */
24
        private final org.moosetechnology.model.famix.famixjavaentities.Type classInstanceCreated = null;
3✔
25

26
        /**
27
         * The source code of the visited AST.
28
         * Used to find back the contents of non-javadoc comments
29
         */
30
        protected RandomAccessFile source;
31

32
        /**
33
         * Whether a variable access is lhs (write) or not
34
         */
35
        protected boolean inAssignmentLHS = false;
3✔
36

37
        public VisitorInvocRef(EntityDictionary dico, VerveineJOptions options) {
38
                super(dico, options);
4✔
39
        }
1✔
40

41
        // VISITOR METHODS
42

43
        public boolean visit(CompilationUnit node) {
44
                //System.err.println("visit(CompilationUnit) ");
45
                visitCompilationUnit(node);
4✔
46
                return super.visit(node);
4✔
47
        }
48

49
        public void endVisit(CompilationUnit node) {
50
                //System.err.println("endVisit(CompilationUnit) ");
51
                endVisitCompilationUnit(node);
3✔
52
        }
1✔
53

54
        /*
55
         * Can only be a class or interface declaration
56
         * Local type: see comment of visit(ClassInstanceCreation node)
57
         */
58
        public boolean visit(TypeDeclaration node) {
59
                //System.err.println("visit(TypeDeclaration) ");
60
                if (visitTypeDeclaration(node) != null) {
4!
61
                        return super.visit(node);
4✔
62
                } else {
63
                        return false;
×
64
                }
65
        }
66

67
        public void endVisit(TypeDeclaration node) {
68
                //System.err.println("endVisit(TypeDeclaration) ");
69
                endVisitTypeDeclaration(node);
3✔
70
        }
1✔
71

72
        /**
73
         * Creates an invocation to the constructor of the class
74
         *
75
         * <pre>
76
         * ClassInstanceCreation ::=
77
         *         [ Expression . ]
78
         *             new [ &lt; Type { , Type } &gt; ]
79
         *             Type ( [ Expression { , Expression } ] )
80
         *             [ AnonymousClassDeclaration ]
81
         * </pre>
82
         */
83
        @SuppressWarnings("unchecked")
84
        public boolean visit(ClassInstanceCreation node) {
85
                //System.err.println("visit(ClassInstanceCreation) ");
86
                String typName;
87
                TType fmx;
88

89
                possiblyAnonymousClassDeclaration(node);
3✔
90

91
                if (node.getAnonymousClassDeclaration() != null) {
3✔
92
                        ITypeBinding bnd = (ITypeBinding) StubBinding.getDeclarationBinding(node.getAnonymousClassDeclaration());
5✔
93
                        fmx = this.dico.getFamixClass(bnd, Util.stringForAnonymousName(getAnonymousSuperTypeName(), context),
12✔
94
                                        /* owner */(ContainerEntity) context.top());
2✔
95
                        typName = fmx.getName();
3✔
96
                } else {
1✔
97
                        Type clazz = node.getType();
3✔
98
                        fmx = referredType(clazz, (ContainerEntity) context.top(), true);
9✔
99

100
                        // create an invocation to the constructor
101
                        if (fmx == null) {
2!
102
                                typName = findTypeName(clazz);
×
103
                        } else {
104
                                typName = fmx.getName();
3✔
105
                        }
106
                }
107

108
                methodInvocation(node.resolveConstructorBinding(), typName, /* receiver */null, /* methOwner */fmx,
9✔
109
                                (List<Expression>) node.arguments());
1✔
110
                Invocation lastInvok = (Invocation) context.getLastInvocation();
5✔
111
                if (options.withAnchors(VerveineJOptions.AnchorOptions.assoc)
8!
112
                                && (lastInvok != null)
113
                                && (lastInvok.getSender() == context.topMethod())
6!
114
                                && (lastInvok.getReceiver() == null)
3!
115
                                && (lastInvok.getSignature().startsWith(typName))) {
4!
116
                        dico.addSourceAnchor(lastInvok, node);
6✔
117
                }
118
                return super.visit(node);
4✔
119
        }
120

121
        public boolean visit(AnonymousClassDeclaration node) {
122
                //System.err.println("visit(AnonymousClassDeclaration) ");
123
                if (visitAnonymousClassDeclaration(node) != null) {
4!
124
                        return super.visit(node);
4✔
125
                } else {
126
                        return false;
×
127
                }
128
        }
129

130
        public void endVisit(AnonymousClassDeclaration node) {
131
                //System.err.println("endVisit(AnonymousClassDeclaration) ");
132
                endVisitAnonymousClassDeclaration(node);
3✔
133
        }
1✔
134

135
        public boolean visit(EnumDeclaration node) {
136
                //System.err.println("visit(EnumDeclaration) ");
137
                if (visitEnumDeclaration(node) != null) {
4!
138
                        return super.visit(node);
4✔
139
                } else {
140
                        return false;
×
141
                }
142
        }
143

144
        public void endVisit(EnumDeclaration node) {
145
                //System.err.println("endVisit(EnumDeclaration) ");
146
                endVisitEnumDeclaration(node);
3✔
147
        }
1✔
148

149
        public boolean visit(AnnotationTypeDeclaration node) {
150
                //System.err.println("visit(AnnotationTypeDeclaration) ");
151
                if (visitAnnotationTypeDeclaration(node) != null) {
4!
152
                        return super.visit(node);
4✔
153
                } else {
154
                        return false;
×
155
                }
156
        }
157

158
        public void endVisit(AnnotationTypeDeclaration node) {
159
                //System.err.println("endVisit(AnnotationTypeDeclaration) ");
160
                endVisitAnnotationTypeDeclaration(node);
3✔
161
        }
1✔
162

163
        public boolean visit(AnnotationTypeMemberDeclaration node) {
164
                //System.err.println("visit(AnnotationTypeMemberDeclaration) ");
165
                if (visitAnnotationTypeMemberDeclaration(node) != null) {
4!
166
                        return super.visit(node);
4✔
167
                } else {
168
                        return false;
×
169
                }
170
        }
171

172
        public void endVisit(AnnotationTypeMemberDeclaration node) {
173
                //System.err.println("endVisit(AnnotationTypeMemberDeclaration) ");
174
                this.context.popAnnotationMember();
4✔
175
                super.endVisit(node);
3✔
176
        }
1✔
177

178
        public boolean visit(MethodDeclaration node) {
179
                //System.err.println("visit(MethodDeclaration): " + node.getName().getIdentifier());
180
                TMethod fmx = visitMethodDeclaration(node);
4✔
181

182
                if (fmx != null) {
2!
183
                        if (node.getBody() != null) {
3✔
184
                                context.setLastInvocation(null);
4✔
185
                        }
186
                        return super.visit(node);
4✔
187
                } else {
188
                        return false;
×
189
                }
190
        }
191

192
        @Override
193
        public void endVisit(MethodDeclaration node) {
194
                //System.err.println("endVisit(MethodDeclaration) ");
195
                endVisitMethodDeclaration(node);
3✔
196
        }
1✔
197

198
        @Override
199
        public boolean visit(Initializer node) {
200
                //System.err.println("visit(Initializer) ");
201
                if (visitInitializer(node) != null) {
4!
202
                        return super.visit(node);
4✔
203
                } else {
204
                        return false;
×
205
                }
206
        }
207

208
        @Override
209
        public void endVisit(Initializer node) {
210
                //System.err.println("endVisit(Initializer) ");
211
                endVisitInitializer(node);
3✔
212
        }
1✔
213

214
        /**
215
         * FieldDeclaration ::=
216
         * [Javadoc] { ExtendedModifier } Type VariableDeclarationFragment
217
         * { , VariableDeclarationFragment } ;
218
         */
219
        @Override
220
        public boolean visit(FieldDeclaration node) {
221
                //System.err.println("visit(FieldDeclaration) ");
222
                hasInitBlock(node); // to recover optional EntityDictionary.INIT_BLOCK_NAME method
4✔
223
                return true;
2✔
224
        }
225

226
        @Override
227
        public void endVisit(FieldDeclaration node) {
228
                //System.err.println("endVisit(FieldDeclaration) ");
229
                endVisitFieldDeclaration(node);
3✔
230
        }
1✔
231

232
        public boolean visit(EnumConstantDeclaration node) {
233
                //System.err.println("visit(EnumConstantDeclaration) ");
234
                return visitEnumConstantDeclaration(node);
4✔
235
        }
236

237
        public void endVisit(EnumConstantDeclaration node) {
238
                //.err.println("endVisit(EnumConstantDeclaration) ");
239
                endVisitEnumConstantDeclaration(node);
3✔
240
        }
1✔
241

242
        @SuppressWarnings("unchecked")
243
        public boolean visit(MethodInvocation node) {
244
                //System.err.println("visit(MethodInvocation): " + node.getName().getFullyQualifiedName());
245
                Expression callingExpr = node.getExpression();
3✔
246
                TNamedEntity receiver = getReceiver(callingExpr);
4✔
247

248
                IMethodBinding bnd = node.resolveMethodBinding();
3✔
249

250
                String calledName = node.getName().getFullyQualifiedName();
4✔
251

252
                if (bnd == null) {
2✔
253
                        methodInvocation(bnd, calledName, receiver, getInvokedMethodOwner(callingExpr, receiver), node.arguments());
13✔
254
                } else {
255
                        methodInvocation(bnd, calledName, receiver, /* owner */null, node.arguments());
9✔
256
                }
257

258
                // TODO could be TInvocation but it does not extends THassignature and we need
259
                // it a bit latter (see 'lastInvok.getSignature()')
260
                Invocation lastInvocation = (Invocation) context.getLastInvocation();
5✔
261
                if (options.withAnchors(VerveineJOptions.AnchorOptions.assoc)
8!
262
                                // check that lastInvocation correspond to current one
263
                                && (lastInvocation != null) && (lastInvocation.getSender() == context.topMethod())
6!
264
                                && (lastInvocation.getReceiver() == receiver)
4!
265
                                && (lastInvocation.getSignature().startsWith(calledName))) {
4!
266
                        dico.addSourceAnchor(lastInvocation, node);
6✔
267
                }
268

269
                return super.visit(node);
4✔
270
        }
271

272
        @SuppressWarnings("unchecked")
273
        public boolean visit(SuperMethodInvocation node) {
274
                //System.err.println("visit(SuperMethodInvocation) ");
275
                // ConstructorInvocation (i.e. 'this(...)' ) happen in constructor, so the name
276
                // is the same
277
                TNamedEntity receiver = this.dico.ensureFamixImplicitVariable(
7✔
278
                                EntityDictionary.SUPER_NAME,
279
                                this.context.topType(),
3✔
280
                                context.topMethod());
1✔
281
                IMethodBinding bnd = node.resolveMethodBinding();
3✔
282
                String calledName = node.getName().getFullyQualifiedName();
4✔
283

284
                if (bnd == null) {
2✔
285
                        TType superClass = (TType) ((TWithInheritances) this.context.topType()).getSuperInheritances().iterator()
6✔
286
                                        .next();
×
287
                        methodInvocation(bnd, calledName, receiver, superClass, node.arguments());
×
288
                } else {
×
289
                        methodInvocation(bnd, calledName, receiver, /* owner */null, node.arguments());
9✔
290
                }
291

292
                Invocation lastInvok = (Invocation) context.getLastInvocation();
5✔
293
                if (options.withAnchors(VerveineJOptions.AnchorOptions.assoc)
5!
294
                                // check that lastInvocation correspond to current one
295
                                && (lastInvok != null) && (lastInvok.getSender() == context.topMethod())
×
296
                                && (lastInvok.getReceiver() == receiver) && (lastInvok.getSignature().startsWith(calledName))) {
×
297
                        dico.addSourceAnchor(lastInvok, node);
×
298
                }
299

300
                return super.visit(node);
4✔
301
        }
302

303
        public boolean visit(ConstructorInvocation node) {
304
                //System.err.println("visit(ConstructorInvocation) ");
305
                // ConstructorInvocation (i.e. 'this(...)' ) happen in constructor, so the name
306
                // is the same
307

308
                int modifiers = (node.resolveConstructorBinding() != null) ? node.resolveConstructorBinding().getModifiers()
7!
309
                                : EntityDictionary.UNKNOWN_MODIFIERS;
1✔
310

311
                String name = context.topMethod().getName();
5✔
312
                TMethod invoked = dico.ensureFamixMethod(node.resolveConstructorBinding(), name,
11✔
313
                                /* paramTypes */null, /* retType */null, (TWithMethods) /* owner */context.topType(), modifiers);
3✔
314
                // constructor don't have return type so no need to create a reference from this
315
                // class to the "declared return type" class when classSummary is TRUE
316
                // also no parameters specified here, so no references to create for them either
317

318
                String signature = node.toString();
3✔
319
                if (signature.endsWith("\n")) {
4!
320
                        signature = signature.substring(0, signature.length() - 1);
8✔
321
                }
322
                if (signature.endsWith(";")) {
4!
323
                        signature = signature.substring(0, signature.length() - 1);
8✔
324
                }
325
                ImplicitVariable receiver = dico.ensureFamixImplicitVariable(
7✔
326
                                EntityDictionary.SELF_NAME,
327
                                context.topType(),
3✔
328
                                context.topMethod());
1✔
329

330
                TInvocation invok = dico.addFamixInvocation(context.topMethod(), invoked, receiver, signature,
12✔
331
                                context.getLastInvocation(), node.resolveConstructorBinding());
3✔
332
                context.setLastInvocation(invok);
4✔
333

334
                if (options.withAnchors(VerveineJOptions.AnchorOptions.assoc) && (invok != null)) {
5!
335
                        dico.addSourceAnchor(invok, node);
×
336
                }
337

338
                return super.visit(node);
4✔
339
        }
340

341
        public boolean visit(SuperConstructorInvocation node) {
342
                //System.err.println("visit(SuperConstructorInvocation) ");
343
                // ConstructorInvocation (i.e. 'super(...)' ) happen in constructor, so the name
344
                // is that of the superclass
345
                // Class superC = superClass();
346
                Method invoked = null;
2✔
347

348
                // if (superC != null) {
349
                // invoked = this.dico.ensureFamixMethod(node.resolveConstructorBinding(),
350
                // superC.getName(), /*paramsType*/(Collection<String>) null, superC,
351
                // EntityDictionary.UNKNOWN_MODIFIERS, /*persistIt*/!classSummary);
352
                // }
353
                // else {
354
                invoked = this.dico.ensureFamixMethod(node.resolveConstructorBinding());
6✔
355
                // }
356

357
                if (invoked != null) {
2✔
358
                        String signature = node.toString();
3✔
359
                        if (signature.endsWith("\n")) {
4!
360
                                signature = signature.substring(0, signature.length() - 1);
8✔
361
                        }
362
                        if (signature.endsWith(";")) {
4!
363
                                signature = signature.substring(0, signature.length() - 1);
8✔
364
                        }
365
                        ImplicitVariable receiver = dico.ensureFamixImplicitVariable(
7✔
366
                                        EntityDictionary.SUPER_NAME,
367
                                        context.topType(),
3✔
368
                                        context.topMethod());
1✔
369
                        Invocation invok = dico.addFamixInvocation(context.topMethod(), invoked, receiver, signature,
12✔
370
                                        context.getLastInvocation(), node.resolveConstructorBinding());
3✔
371
                        context.setLastInvocation(invok);
4✔
372
                        if (options.withAnchors(VerveineJOptions.AnchorOptions.assoc)) {
5!
373
                                dico.addSourceAnchor(invok, node);
×
374
                        }
375
                }
376

377
                return super.visit(node);
4✔
378
        }
379

380
        // UTILITY METHODS
381

382
        /**
383
         * Handles an invocation of a method by creating the corresponding Famix Entity.
384
         *
385
         * @param calledBnd  -- a binding for the method invoked
386
         * @param calledName of the method invoked
387
         * @param receiver   of the call, i.e. the object to which the message is sent
388
         * @param methOwner  -- owner of the method invoked. Might be a subtype of the
389
         *                   receiver's type
390
         * @param l_args     -- list of the method's parameters
391
         *                   TODO Why are Invocations, Accesses and References not
392
         *                   created through a method in JavaDictionnary ?
393
         */
394
        private Invocation methodInvocation(IMethodBinding calledBnd, String calledName, TNamedEntity receiver,
395
                        TType methOwner, Collection<Expression> l_args) {
396
                //System.err.println("methodInvocation(): " + calledName);
397

398
                TMethod sender = this.context.topMethod();
4✔
399
                TMethod invoked;
400
                Invocation invok;
401

402
                // If the method is parametric, get the generic method.
403
                IMethodBinding actualCalledMethodBnd = (calledBnd == null ? null : calledBnd.getMethodDeclaration());
7✔
404

405
                if ((receiver != null) && (receiver.getName().equals("class")) && (actualCalledMethodBnd != null)
10!
406
                                && (actualCalledMethodBnd.getDeclaringClass() == null)) {
2!
407
                        /* bug with JDT apparently has to do with invoking a method of a meta-class */
408
                        // humm ... we do not create the FamixInvocation ? Seems like a bug ...
409
                        return null;
×
410
                } else if ((actualCalledMethodBnd != null) && (actualCalledMethodBnd.isAnnotationMember())) {
5✔
411
                        // if this is not an AnnotationType member, it is similar to creating a
412
                        // FamixAttribute access
413
                        return null;
2✔
414
                } else if (sender == null) {
2!
415
                        return null;
×
416
                }
417

418
                Collection<String> unkwnArgs = new ArrayList<String>();
4✔
419
                if (l_args != null) {
2!
420
                        for (@SuppressWarnings("unused")
421
                        Expression a : l_args) {
10✔
422
                                unkwnArgs.add("?");
4✔
423
                        }
1✔
424
                }
425

426
                int modifiers = (actualCalledMethodBnd != null) ? actualCalledMethodBnd.getModifiers() : EntityDictionary.UNKNOWN_MODIFIERS;
7✔
427

428
                if ((receiver != null) && (receiver instanceof TStructuralEntity)) {
5✔
429
                        invoked = this.dico.ensureFamixMethod(actualCalledMethodBnd, calledName, unkwnArgs, /* retType */null,
12✔
430
                                        (TWithMethods) methOwner, modifiers);
431
                } else {
432
                        TType owner;
433

434
                        if (receiver != null)
2✔
435
                                owner = (TType) receiver;
4✔
436
                        else {
437
                                if (actualCalledMethodBnd != null && actualCalledMethodBnd.getDeclaringClass().isParameterizedType()) {
6!
438
                                        owner = this.dico.ensureFamixType(actualCalledMethodBnd.getDeclaringClass().getErasure());
×
439
                                } else {
440
                                        owner = methOwner;
2✔
441
                                }
442
                        }
443

444
                        // static method called on the class (or null receiver)
445
                        invoked = this.dico.ensureFamixMethod(actualCalledMethodBnd, calledName, unkwnArgs, /* retType */null,
11✔
446
                                        (TWithMethods) /* owner */owner, modifiers);
447
                }
448

449
                String signature = "";
2✔
450
                if (actualCalledMethodBnd != null && actualCalledMethodBnd.isParameterizedMethod()) {
5!
451
                        signature += "<";
×
452
                        int size = ((ParametricMethod) invoked).getTypeParameters().size();
×
453
                        int i = 0;
×
454
                        for (TTypeParameter param : ((ParametricMethod) invoked).getTypeParameters()) {
×
455
                                signature += ((TNamedEntity) param).getName() + (i < size - 1 ? "," : "");
×
456
                                i++;
×
457
                        }
×
458
                        signature += "> ";
×
459
                }
460
                signature += calledName + "(";
4✔
461

462
                if (l_args != null) {
2!
463
                        boolean first = true;
2✔
464
                        for (Expression a : l_args) {
10✔
465
                                if (first) {
2✔
466
                                        signature += a.toString();
5✔
467
                                        first = false;
3✔
468
                                } else {
469
                                        signature += "," + a.toString();
5✔
470
                                }
471
                        }
1✔
472
                }
473
                signature += ")";
3✔
474
                
475
                invok = dico.addFamixInvocation(sender, invoked, (TInvocationsReceiver) receiver, signature,
11✔
476
                                context.getLastInvocation(), calledBnd);
2✔
477
                // TODO add FileAnchor to Invocation
478
                context.setLastInvocation(invok);
4✔
479

480
                return invok;
2✔
481

482
        }
483

484
        /**
485
         * Finds and/or create the Famix Entity receiving a message
486
         * Can be: ImplicitVariable (this, super), GlobalVariable, LocalVariable,
487
         * Attribute, UnknownVariable, Parameter
488
         * 
489
         * @param expr -- the Java expression describing the receiver
490
         * @return the Famix Entity or null if could not find it
491
         */
492
        @SuppressWarnings("static-access")
493
        private TNamedEntity getReceiver(Expression expr) {
494
                // msg(), same as ThisExpression
495
                if (expr == null) {
2✔
496
                        return this.dico.ensureFamixImplicitVariable(dico.SELF_NAME, this.context.topType(), context.topMethod());
14✔
497
                }
498

499
                // array[i].msg()
500
                if (NodeTypeChecker.isArrayAccess(expr)) {
3!
501
                        return getReceiver(((ArrayAccess) expr).getArray());
×
502
                }
503

504
                // new type[].msg()
505
                if (NodeTypeChecker.isArrayCreation(expr)) {
3!
506
                        // System.err.println("WARNING: Ignored receiver expression in method call:
507
                        // ArrayCreation");
508
                        return null;
×
509
                }
510

511
                // (variable = value).msg()
512
                if (NodeTypeChecker.isAssignment(expr)) {
3!
513
                        return getReceiver(((Assignment) expr).getLeftHandSide());
×
514
                }
515

516
                // ((type)expr).msg()
517
                if (NodeTypeChecker.isCastExpression(expr)) {
3!
518
                        return getReceiver(((CastExpression) expr).getExpression());
×
519
                }
520

521
                // new Class().msg()
522
                if (NodeTypeChecker.isClassInstanceCreation(expr)) {
3✔
523
                        return null;
2✔
524
                }
525

526
                // (cond-expr ? then-expr : else-expr).msg()
527
                if (NodeTypeChecker.isConditionalExpression(expr)) {
3!
528
                        // can be one or the other (then-expr/else-expr) so we choose one
529
                        TNamedEntity ret = getReceiver(((ConditionalExpression) expr).getThenExpression());
×
530
                        if (ret == null) {
×
531
                                // can as well try the other
532
                                ret = getReceiver(((ConditionalExpression) expr).getElseExpression());
×
533
                        }
534
                        return ret;
×
535
                }
536

537
                // field.msg()
538
                if (NodeTypeChecker.isFieldAccess(expr)) {
3✔
539
                        IVariableBinding bnd = ((FieldAccess) expr).resolveFieldBinding();
4✔
540
                        TNamedEntity fld = (TNamedEntity) dico.getEntityByKey(bnd);
5✔
541
                        /*
542
                         * StructuralEntity fld = ensureAccessedStructEntity(bnd, ((FieldAccess)
543
                         * expr).getName().getIdentifier(),
544
                         * /*type* /null, /*owner* /null, /*accessor* /null);
545
                         */
546
                        return fld;
2✔
547
                }
548

549
                // (left-expr oper right-expr).msg()
550
                if (NodeTypeChecker.isInfixExpression(expr)) {
3!
551
                        // anonymous receiver
552
                        return null;
×
553
                }
554

555
                // msg1().msg()
556
                if (NodeTypeChecker.isMethodInvocation(expr)) {
3✔
557
                        return null;
2✔
558
                }
559

560
                // name.msg()
561
                if (NodeTypeChecker.isName(expr)) {
3✔
562
                        // can be a class or a variable name
563
                        IBinding bnd = ((Name) expr).resolveBinding();
4✔
564
                        if (bnd == null) {
2✔
565
                                return null;
2✔
566
                        }
567
                        TNamedEntity ret = null;
2✔
568
                        if (bnd.getKind() == IBinding.TYPE) {
4✔
569
                                // msg() is a static method of Name so name should be a class, except if its an
570
                                // Enum
571
                                ret = (TNamedEntity) dico.getEntityByKey(bnd);
5✔
572
                        }
573

574
                        if (bnd.getKind() == IBinding.VARIABLE) {
4✔
575
                                // a bit convoluted, but sometimes 'bnd' is not directly the binding of the
576
                                // variable's declaration from which the Famix entity was created
577
                                return (TNamedEntity) dico.getEntityByKey(((IVariableBinding) bnd).getVariableDeclaration());
7✔
578
                        }
579

580
                        return ret;
2✔
581
                }
582

583
                // (expr).msg()
584
                if (NodeTypeChecker.isParenthesizedExpression(expr)) {
3!
585
                        return getReceiver(((ParenthesizedExpression) expr).getExpression());
×
586
                }
587

588
                // "string".msg()
589
                if (NodeTypeChecker.isStringLiteral(expr)) {
3✔
590
                        return null;
2✔
591
                }
592

593
                // <text block>.msg()
594
                // <text block> are created with triple quotes to allow defining multi-line string literals
595
                // they are reported as NullLiteral in JDT and there does not seem to be a better way to test them
596
                if (expr instanceof NullLiteral) {
3!
NEW
597
                        return null;
×
598
                }
599

600
                // super.field.msg()
601
                if (NodeTypeChecker.isSuperFieldAccess(expr)) {
3!
602
                        return (TNamedEntity) dico.getEntityByKey(((SuperFieldAccess) expr).resolveFieldBinding());
×
603
                        /*
604
                         * return ensureAccessedStructEntity(((SuperFieldAccess)
605
                         * expr).resolveFieldBinding(),
606
                         * ((SuperFieldAccess) expr).getName().getIdentifier(), /*typ* /null, /*owner*
607
                         * /null, /*accessor* /null);
608
                         */
609
                }
610

611
                // super.msg1().msg()
612
                if (NodeTypeChecker.isSuperMethodInvocation(expr)) {
3!
613
                        return null;
×
614
                }
615

616
                // this.msg()
617
                if (NodeTypeChecker.isThisExpression(expr)) {
3✔
618
                        return this.dico.ensureFamixImplicitVariable(EntityDictionary.SELF_NAME, context.topType(),
10✔
619
                                        context.topMethod());
1✔
620
                }
621

622
                // type.class.msg()
623
                if (NodeTypeChecker.isTypeLiteral(expr)) {
3!
624
                        // similar to a field access
625
                        return dico.getFamixAttribute(null, "class", dico.ensureFamixMetaClass(null));
10✔
626
                }
627

628
                // ... OTHER POSSIBLE EXPRESSIONS ?
629
                System.err.println("WARNING: Unexpected receiver expression: " + expr.getClass().getName()
×
630
                                + " (method called is" + expr.getClass().getName() + ".aMethod(...))");
×
631
                return null;
×
632
        }
633

634
        /**
635
         * Tries its best to find the type of a receiver without using the bindings.
636
         * Most of the time, the type is that of the receiver, but not always (if there
637
         * is a cast or if receiver is null)
638
         *
639
         * @param expr     -- the Java expression describing the receiver
640
         * @param receiver -- the FAMIX Entity describing the receiver
641
         * @return the Famix Entity or null if could not find it
642
         */
643
        private TType getInvokedMethodOwner(Expression expr, TNamedEntity receiver) {
644
                // ((type)expr).msg()
645
                if (NodeTypeChecker.isCastExpression(expr)) {
3!
646
                        Type tcast = ((CastExpression) expr).getType();
×
647
                        return referredType(tcast, (ContainerEntity) this.context.top(), true);
×
648
                }
649

650
                // new Class().msg()
651
                else if (NodeTypeChecker.isClassInstanceCreation(expr)) {
3!
652
                        return this.classInstanceCreated;
×
653
                }
654

655
                // msg1().msg()
656
                else if (NodeTypeChecker.isMethodInvocation(expr)) {
3✔
657
                        IMethodBinding callerBnd = ((MethodInvocation) expr).resolveMethodBinding();
4✔
658
                        if (callerBnd != null) {
2!
659
                                return referredType(callerBnd.getReturnType(), (ContainerEntity) this.context.top(), true);
10✔
660
                        } else {
661
                                return null;
×
662
                        }
663
                }
664

665
                // (expr).msg()
666
                else if (NodeTypeChecker.isParenthesizedExpression(expr)) {
3!
667
                        return getInvokedMethodOwner(((ParenthesizedExpression) expr).getExpression(), receiver);
×
668
                }
669

670
                // "string".msg()
671
                else if (NodeTypeChecker.isStringLiteral(expr)) {
3!
672
                        return dico.ensureFamixType(/* binding */null, "String", dico.ensureFamixPackageJavaLang(null),
×
673
                                        /* context */null, EntityDictionary.UNKNOWN_MODIFIERS); // creating FamixClass java.lang.String
674
                }
675

676
                // super.msg1().msg()
677
                else if (NodeTypeChecker.isSuperMethodInvocation(expr)) {
3!
678
                        IMethodBinding superBnd = ((SuperMethodInvocation) expr).resolveMethodBinding();
×
679
                        if (superBnd != null) {
×
680
                                return this.referredType(superBnd.getReturnType(), (ContainerEntity) context.topType(), true);
×
681
                        } else {
682
                                return null;
×
683
                        }
684
                }
685

686
                // everything else, see the receiver
687
                else {
688
                        if (receiver == null) {
2✔
689
                                return null;
2✔
690
                        }
691
                        /*
692
                         * else if (receiver instanceof ImplicitVariable) {
693
                         * if (receiver.getName().equals(EntityDictionary.SELF_NAME)) {
694
                         * return context.topType();
695
                         * }
696
                         * else { // receiver.getName().equals(EntityDictionary.SUPER_NAME)
697
                         * return
698
                         * context.topType().getSuperInheritances().iterator().next().getSuperclass();
699
                         * }
700
                         * }
701
                         */
702
                        else if (receiver instanceof TTypedEntity) {
3!
703
                                return ((TTypedEntity) receiver).getDeclaredType();
4✔
704
                        } else if (receiver instanceof org.moosetechnology.model.famix.famixjavaentities.Type) {
×
705
                                return (org.moosetechnology.model.famix.famixjavaentities.Type) receiver;
×
706
                        }
707
                        // ... what else ?
708
                        else {
709
                                return null;
×
710
                        }
711
                }
712
        }
713

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