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

moosetechnology / VerveineJ / 20995145617

14 Jan 2026 01:05PM UTC coverage: 51.4% (+0.2%) from 51.203%
20995145617

push

github

web-flow
Merge pull request #190 from moosetechnology/some-bugs

fix #186, rolling back some of the changes in #184

1931 of 3948 branches covered (48.91%)

Branch coverage included in aggregate %.

13 of 14 new or added lines in 4 files covered. (92.86%)

2 existing lines in 2 files now uncovered.

4294 of 8163 relevant lines covered (52.6%)

2.12 hits per line

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

73.23
/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
        return visitEnumConstantDeclaration(node);
4✔
234
        }
235

236
        public void endVisit(EnumConstantDeclaration node) {
237
                endVisitEnumConstantDeclaration(node);
3✔
238
        }
1✔
239

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

246
                IMethodBinding bnd = node.resolveMethodBinding();
3✔
247

248
                String calledName = node.getName().getFullyQualifiedName();
4✔
249

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

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

267
                return super.visit(node);
4✔
268
        }
269

270
        @SuppressWarnings("unchecked")
271
        public boolean visit(SuperMethodInvocation node) {
272
                //System.err.println("visit(SuperMethodInvocation) ");
273
                TNamedEntity receiver = this.dico.ensureFamixImplicitVariable(
7✔
274
                                EntityDictionary.SUPER_NAME,
275
                                this.context.topType(),
3✔
276
                                context.topMethod());
1✔
277
                IMethodBinding bnd = node.resolveMethodBinding();
3✔
278
                String calledName = node.getName().getFullyQualifiedName();
4✔
279

280
                if (bnd == null) {
2✔
281
                        TType superClass = (TType) ((TWithInheritances) this.context.topType()).getSuperInheritances().iterator().next().getSuperclass();
11✔
282
                        methodInvocation(bnd, calledName, receiver, superClass, node.arguments());
9✔
283
                } else {
1✔
284
                        methodInvocation(bnd, calledName, receiver, /* owner */null, node.arguments());
9✔
285
                }
286

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

295
                return super.visit(node);
4✔
296
        }
297

298
        public boolean visit(ConstructorInvocation node) {
299
                //System.err.println("visit(ConstructorInvocation) ");
300
                // ConstructorInvocation (i.e. 'this(...)' ) happen in constructor, so the name
301
                // is the same
302

303
                int modifiers = (node.resolveConstructorBinding() != null) ? node.resolveConstructorBinding().getModifiers()
7!
304
                                : EntityDictionary.UNKNOWN_MODIFIERS;
1✔
305

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

313
                String signature = node.toString();
3✔
314
                if (signature.endsWith("\n")) {
4!
315
                        signature = signature.substring(0, signature.length() - 1);
8✔
316
                }
317
                if (signature.endsWith(";")) {
4!
318
                        signature = signature.substring(0, signature.length() - 1);
8✔
319
                }
320
                ImplicitVariable receiver = dico.ensureFamixImplicitVariable(
7✔
321
                                EntityDictionary.THIS_NAME,
322
                                context.topType(),
3✔
323
                                context.topMethod());
1✔
324

325
                TInvocation invok = dico.addFamixInvocation(context.topMethod(), invoked, receiver, signature,
12✔
326
                                context.getLastInvocation(), node.resolveConstructorBinding());
3✔
327
                context.setLastInvocation(invok);
4✔
328

329
                if (options.withAnchors(VerveineJOptions.AnchorOptions.assoc) && (invok != null)) {
5!
330
                        dico.addSourceAnchor(invok, node);
×
331
                }
332

333
                return super.visit(node);
4✔
334
        }
335

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

343
                // if (superC != null) {
344
                // invoked = this.dico.ensureFamixMethod(node.resolveConstructorBinding(),
345
                // superC.getName(), /*paramsType*/(Collection<String>) null, superC,
346
                // EntityDictionary.UNKNOWN_MODIFIERS, /*persistIt*/!classSummary);
347
                // }
348
                // else {
349
                invoked = this.dico.ensureFamixMethod(node.resolveConstructorBinding());
6✔
350
                // }
351

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

372
                return super.visit(node);
4✔
373
        }
374

375
        // UTILITY METHODS
376

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

393
                TMethod sender = this.context.topMethod();
4✔
394
                TMethod invoked;
395
                Invocation invok;
396

397
                // If the method is parametric, get the generic method.
398
                IMethodBinding actualCalledMethodBnd = (calledBnd == null ? null : calledBnd.getMethodDeclaration());
7✔
399

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

413
                Collection<String> unkwnArgs = new ArrayList<String>();
4✔
414
                if (l_args != null) {
2!
415
                        for (@SuppressWarnings("unused")
416
                        Expression a : l_args) {
10✔
417
                                unkwnArgs.add("?");
4✔
418
                        }
1✔
419
                }
420

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

423
                if ((receiver != null) && (receiver instanceof TStructuralEntity)) {
5✔
424
                        invoked = this.dico.ensureFamixMethod(actualCalledMethodBnd, calledName, unkwnArgs, /* retType */null,
12✔
425
                                        (TWithMethods) methOwner, modifiers);
426
                } else {
427
                        TType owner;
428

429
                        if (receiver != null)
2✔
430
                                owner = (TType) receiver;
4✔
431
                        else {
432
                                if (actualCalledMethodBnd != null && actualCalledMethodBnd.getDeclaringClass().isParameterizedType()) {
6!
433
                                        owner = this.dico.ensureFamixType(actualCalledMethodBnd.getDeclaringClass().getErasure());
×
434
                                } else {
435
                                        owner = methOwner;
2✔
436
                                }
437
                        }
438

439
                        // static method called on the class (or null receiver)
440
                        invoked = this.dico.ensureFamixMethod(actualCalledMethodBnd, calledName, unkwnArgs, /* retType */null,
11✔
441
                                        (TWithMethods) /* owner */owner, modifiers);
442
                }
443

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

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

475
                return invok;
2✔
476

477
        }
478

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

494
                // array[i].msg()
495
                if (NodeTypeChecker.isArrayAccess(expr)) {
3!
496
                        return getReceiver(((ArrayAccess) expr).getArray());
×
497
                }
498

499
                // new type[].msg()
500
                if (NodeTypeChecker.isArrayCreation(expr)) {
3!
501
                        return null;
×
502
                }
503

504
                // (variable = value).msg()
505
                if (NodeTypeChecker.isAssignment(expr)) {
3!
506
                        return getReceiver(((Assignment) expr).getLeftHandSide());
×
507
                }
508

509
                // ((type)expr).msg()
510
                if (NodeTypeChecker.isCastExpression(expr)) {
3!
511
                        return getReceiver(((CastExpression) expr).getExpression());
×
512
                }
513

514
                // new Class().msg()
515
                if (NodeTypeChecker.isClassInstanceCreation(expr)) {
3✔
516
                        return null;
2✔
517
                }
518

519
                // (cond-expr ? then-expr : else-expr).msg()
520
                if (NodeTypeChecker.isConditionalExpression(expr)) {
3!
521
                        // can be one or the other (then-expr/else-expr) so we choose one
522
                        TNamedEntity ret = getReceiver(((ConditionalExpression) expr).getThenExpression());
×
523
                        if (ret == null) {
×
524
                                // can as well try the other
525
                                ret = getReceiver(((ConditionalExpression) expr).getElseExpression());
×
526
                        }
527
                        return ret;
×
528
                }
529

530
                // field.msg()
531
                if (NodeTypeChecker.isFieldAccess(expr)) {
3✔
532
                        IVariableBinding bnd = ((FieldAccess) expr).resolveFieldBinding();
4✔
533
                        return dico.getEntityByKey(bnd);
5✔
534
                }
535

536
                // (left-expr oper right-expr).msg()
537
                if (NodeTypeChecker.isInfixExpression(expr)) {
3!
538
                        // anonymous receiver
539
                        return null;
×
540
                }
541

542
                // msg1().msg()
543
                if (NodeTypeChecker.isMethodInvocation(expr)) {
3✔
544
                        return null;
2✔
545
                }
546

547
                // name.msg()
548
                if (NodeTypeChecker.isName(expr)) {
3✔
549
                        // can be a class or a variable name
550
                        IBinding bnd = ((Name) expr).resolveBinding();
4✔
551
                        if (bnd == null) {
2✔
552
                                return null;
2✔
553
                        }
554
                        TNamedEntity ret = null;
2✔
555
                        if (bnd.getKind() == IBinding.TYPE) {
4✔
556
                                // msg() is a static method of Name so name should be a class, except if its an
557
                                // Enum
558
                                ret = dico.getEntityByKey(bnd);
5✔
559
                        }
560

561
                        if (bnd.getKind() == IBinding.VARIABLE) {
4✔
562
                                // a bit convoluted, but sometimes 'bnd' is not directly the binding of the
563
                                // variable's declaration from which the Famix entity was created
564
                                return dico.getEntityByKey(((IVariableBinding) bnd).getVariableDeclaration());
7✔
565
                        }
566

567
                        return ret;
2✔
568
                }
569

570
                // (expr).msg()
571
                if (NodeTypeChecker.isParenthesizedExpression(expr)) {
3!
572
                        return getReceiver(((ParenthesizedExpression) expr).getExpression());
×
573
                }
574

575
                // "string".msg()
576
                if (NodeTypeChecker.isStringLiteral(expr)) {
3✔
577
                        return null;
2✔
578
                }
579

580
                // <text block>.msg()
581
                // <text block> are created with triple quotes to allow defining multi-line string literals
582
                // they used to be reported as NullLiteral in JDT
583
                // In more modern version there is a Node type for them
584
                if (expr instanceof NullLiteral || ( expr.getNodeType() == ASTNode.TEXT_BLOCK) ) {
7!
585
                        return null;
2✔
586
                }
587

588
                // super.field.msg()
589
                if (NodeTypeChecker.isSuperFieldAccess(expr)) {
3!
590
                        return dico.getEntityByKey(((SuperFieldAccess) expr).resolveFieldBinding());
×
591
                }
592

593
                // super.msg1().msg()
594
                if (NodeTypeChecker.isSuperMethodInvocation(expr)) {
3!
595
                        return null;
×
596
                }
597

598
                // this.msg()
599
                if (NodeTypeChecker.isThisExpression(expr)) {
3✔
600
                        return this.dico.ensureFamixImplicitVariable(EntityDictionary.THIS_NAME, context.topType(),
10✔
601
                                        context.topMethod());
1✔
602
                }
603

604
                // type.class.msg()
605
                if (NodeTypeChecker.isTypeLiteral(expr)) {
3!
606
                        // similar to a field access
607
                        return dico.getFamixAttribute(null, "class", dico.ensureFamixMetaClass(null));
10✔
608
                }
609

610
                // ... OTHER POSSIBLE EXPRESSIONS ?
611
                System.err.println("WARNING: Unexpected receiver expression: " + expr.getClass().getName()
×
612
                                + " (method called is " + expr.getClass().getName() + ".aMethod(...))");
×
613
                return null;
×
614
        }
615

616
        /**
617
         * Tries its best to find the type of a receiver without using the bindings.
618
         * Most of the time, the type is that of the receiver, but not always (if there
619
         * is a cast or if receiver is null)
620
         *
621
         * @param expr     -- the Java expression describing the receiver
622
         * @param receiver -- the FAMIX Entity describing the receiver
623
         * @return the Famix Entity or null if could not find it
624
         */
625
        private TType getInvokedMethodOwner(Expression expr, TNamedEntity receiver) {
626
                // ((type)expr).msg()
627
                if (NodeTypeChecker.isCastExpression(expr)) {
3!
628
                        Type tcast = ((CastExpression) expr).getType();
×
629
                        return referredType(tcast, (ContainerEntity) this.context.top(), true);
×
630
                }
631

632
                // new Class().msg()
633
                else if (NodeTypeChecker.isClassInstanceCreation(expr)) {
3!
634
                        return this.classInstanceCreated;
×
635
                }
636

637
                // msg1().msg()
638
                else if (NodeTypeChecker.isMethodInvocation(expr)) {
3✔
639
                        IMethodBinding callerBnd = ((MethodInvocation) expr).resolveMethodBinding();
4✔
640
                        if (callerBnd != null) {
2!
641
                                return referredType(callerBnd.getReturnType(), (ContainerEntity) this.context.top(), true);
10✔
642
                        } else {
643
                                return null;
×
644
                        }
645
                }
646

647
                // (expr).msg()
648
                else if (NodeTypeChecker.isParenthesizedExpression(expr)) {
3!
649
                        return getInvokedMethodOwner(((ParenthesizedExpression) expr).getExpression(), receiver);
×
650
                }
651

652
                // "string".msg()
653
                else if (NodeTypeChecker.isStringLiteral(expr)) {
3!
654
                        return dico.ensureFamixType(/* binding */null, "String", dico.ensureFamixPackageJavaLang(null),
×
655
                                        /* context */null, EntityDictionary.UNKNOWN_MODIFIERS); // creating FamixClass java.lang.String
656
                }
657

658
                // super.msg1().msg()
659
                else if (NodeTypeChecker.isSuperMethodInvocation(expr)) {
3!
660
                        IMethodBinding superBnd = ((SuperMethodInvocation) expr).resolveMethodBinding();
×
661
                        if (superBnd != null) {
×
662
                                return this.referredType(superBnd.getReturnType(), (ContainerEntity) context.topType(), true);
×
663
                        } else {
664
                                return null;
×
665
                        }
666
                }
667

668
                // everything else, see the receiver
669
                else {
670
                        if (receiver == null) {
2✔
671
                                return null;
2✔
672
                        }
673
                        else if (receiver instanceof TTypedEntity) {
3!
674
                                return ((TTypedEntity) receiver).getDeclaredType();
4✔
675
                        } else if (receiver instanceof org.moosetechnology.model.famix.famixjavaentities.Type) {
×
676
                                return (org.moosetechnology.model.famix.famixjavaentities.Type) receiver;
×
677
                        }
678
                        // ... what else ?
679
                        else {
680
                                return null;
×
681
                        }
682
                }
683
        }
684

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