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

moosetechnology / VerveineJ / 16692655354

02 Aug 2025 10:24AM UTC coverage: 50.841% (+0.2%) from 50.681%
16692655354

Pull #152

github

web-flow
Merge a8d2b8a6d into a52993031
Pull Request #152: Issue/151

1909 of 3968 branches covered (48.11%)

Branch coverage included in aggregate %.

25 of 30 new or added lines in 1 file covered. (83.33%)

116 existing lines in 2 files now uncovered.

4289 of 8223 relevant lines covered (52.16%)

2.09 hits per line

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

73.31
/app/src/main/java/fr/inria/verveine/extractor/java/EntityDictionary.java
1
package fr.inria.verveine.extractor.java;
2

3
import java.util.ArrayList;
4
import java.util.Arrays;
5
import java.util.Collection;
6
import java.util.ConcurrentModificationException;
7
import java.util.Hashtable;
8
import java.util.Iterator;
9
import java.util.LinkedList;
10
import java.util.List;
11
import java.util.Map;
12
import java.util.stream.Collectors;
13

14
import org.eclipse.jdt.core.dom.ASTNode;
15
import org.eclipse.jdt.core.dom.CompilationUnit;
16
import org.eclipse.jdt.core.dom.IBinding;
17
import org.eclipse.jdt.core.dom.IMethodBinding;
18
import org.eclipse.jdt.core.dom.IPackageBinding;
19
import org.eclipse.jdt.core.dom.ITypeBinding;
20
import org.eclipse.jdt.core.dom.IVariableBinding;
21
import org.eclipse.jdt.core.dom.MethodDeclaration;
22
import org.eclipse.jdt.core.dom.Modifier;
23
import org.moosetechnology.model.famix.famixjavaentities.*;
24
import org.moosetechnology.model.famix.famixjavaentities.Class;
25
import org.moosetechnology.model.famix.famixjavaentities.Enum;
26
import org.moosetechnology.model.famix.famixjavaentities.Exception;
27
import org.moosetechnology.model.famix.famixjavaentities.Package;
28
import org.moosetechnology.model.famix.famixtraits.TAccessible;
29
import org.moosetechnology.model.famix.famixtraits.TAnnotationInstance;
30
import org.moosetechnology.model.famix.famixtraits.TAssociation;
31
import org.moosetechnology.model.famix.famixtraits.TAttribute;
32
import org.moosetechnology.model.famix.famixtraits.TCanBeClassSide;
33
import org.moosetechnology.model.famix.famixtraits.TCanBeFinal;
34
import org.moosetechnology.model.famix.famixtraits.TCanBeStub;
35
import org.moosetechnology.model.famix.famixtraits.TCanImplement;
36
import org.moosetechnology.model.famix.famixtraits.THasVisibility;
37
import org.moosetechnology.model.famix.famixtraits.TImplementable;
38
import org.moosetechnology.model.famix.famixtraits.TImplementation;
39
import org.moosetechnology.model.famix.famixtraits.TInheritance;
40
import org.moosetechnology.model.famix.famixtraits.TInvocationsReceiver;
41
import org.moosetechnology.model.famix.famixtraits.TMethod;
42
import org.moosetechnology.model.famix.famixtraits.TNamedEntity;
43
import org.moosetechnology.model.famix.famixtraits.TParametricEntity;
44
import org.moosetechnology.model.famix.famixtraits.TParametricAssociation;
45
import org.moosetechnology.model.famix.famixtraits.TReference;
46
import org.moosetechnology.model.famix.famixtraits.TSourceEntity;
47
import org.moosetechnology.model.famix.famixtraits.TStructuralEntity;
48
import org.moosetechnology.model.famix.famixtraits.TThrowable;
49
import org.moosetechnology.model.famix.famixtraits.TType;
50
import org.moosetechnology.model.famix.famixtraits.TTypeArgument;
51
import org.moosetechnology.model.famix.famixtraits.TTypedEntity;
52
import org.moosetechnology.model.famix.famixtraits.TWithAccesses;
53
import org.moosetechnology.model.famix.famixtraits.TWithAnnotationInstances;
54
import org.moosetechnology.model.famix.famixtraits.TWithAttributes;
55
import org.moosetechnology.model.famix.famixtraits.TWithComments;
56
import org.moosetechnology.model.famix.famixtraits.TWithInheritances;
57
import org.moosetechnology.model.famix.famixtraits.TWithLocalVariables;
58
import org.moosetechnology.model.famix.famixtraits.TWithMethods;
59
import org.moosetechnology.model.famix.famixtraits.TWithTypes;
60

61
import ch.akuhn.fame.Repository;
62
import fr.inria.verveine.extractor.java.utils.ImplicitVarBinding;
63
import fr.inria.verveine.extractor.java.utils.Util;
64

65
/**
66
 * A dictionary of FamixJava entities to help create them and find them back
67
 * Entities are mapped to keys which are the "binding" provided by the JDT pars
68
 * 
69
 * @author anquetil
70
 */
71
public class EntityDictionary {
72

73
        /**
74
         * A property added to CompilationUnits to record the name of the source file they belong to.
75
         * Used to create FileAnchors
76
         */
77
        public static final String SOURCE_FILENAME_PROPERTY = "verveine-source-filename";
78

79
        public static final String DEFAULT_PCKG_NAME = "<Default Package>";
80
        public static final String STUB_METHOD_CONTAINER_NAME = "<StubMethodContainer>";
81
        public static final String SELF_NAME = "self";
82
        public static final String SUPER_NAME = "super";
83
        
84
        public static final String OBJECT_NAME = "Object";
85
        public static final String METACLASS_NAME = "Class";
86
        public static final String OBJECT_PACKAGE_NAME = "java.lang";
87
        public static final String ARRAYS_NAME = "default[]";
88
        public static final String INIT_BLOCK_NAME = "<Initializer>";
89
        public static final String ANONYMOUS_NAME_PREFIX = "_Anonymous";
90

91
        public static final int UNKNOWN_MODIFIERS = 0;
92
        public static final String MODIFIER_ABSTRACT = "abstract";
93
        public static final String MODIFIER_PUBLIC   = "public";
94
        public static final String MODIFIER_PRIVATE  = "private";
95
        public static final String MODIFIER_PROTECTED= "protected";
96
        public static final String MODIFIER_PACKAGE = "package";
97
        public static final String MODIFIER_FINAL    = "final";
98
        public static final String MODIFIER_STATIC    = "static";
99
        public static final String MODIFIER_TRANSIENT = "transient";
100
        public static final String MODIFIER_VOLATILE = "volatile";
101
        public static final String MODIFIER_SYNCHRONIZED = "synchronized";
102

103
        /**
104
         * An MSE marker for methods
105
         */
106
        public static final String CONSTRUCTOR_KIND_MARKER = "constructor";
107

108
        /**
109
         * The FAMIX repository where all FAMIX entities are created and stored
110
         */
111
        protected Repository famixRepo;
112

113
        /**
114
         * A dictionary to map a key (provided by the user) to FAMIX Entity
115
         */
116
        protected Map<IBinding,TNamedEntity> keyToEntity;
117
        /**
118
         * A reverse dictionary (see {@link #keyToEntity}) to find the key of an entity.
119
         */
120
        protected Map<TNamedEntity,IBinding> entityToKey;
121

122
        /**
123
         * Another dictionary to map a name to FAMIX Entities with this name
124
         */
125
        protected Map<String,Collection<TNamedEntity>> nameToEntity;
126

127
        /**
128
         * Yet another dictionary for implicit variables ('self' and 'super')
129
         * Because they are implicit, they may not have a binding provided by the parser,
130
         * or may have the same binding than their associated type so they can't be kept easily in {@link #keyToEntity}
131
         */
132
        @Deprecated
133
        protected Map<Type,ImplicitVars> typeToImpVar;
134

135
        /**
136
         * Used to keep the two possible ImplicitVariable for a given Class binding
137
         * @author anquetil
138
         */
139
        @Deprecated
140
        protected class ImplicitVars {
×
141
                public ImplicitVariable self_iv;
142
                public ImplicitVariable super_iv;
143
        }
144
        
145
        /**
146
         * Result of utility methods for checking matching between two entities
147
         */
148
        private enum CheckResult {
3✔
149
                MATCH, UNDECIDED, FAIL;
18✔
150
        }
151

152

153
        /** Constructor taking a FAMIX repository
154
         * @param famixRepo
155
         */
156
        public EntityDictionary(Repository famixRepo) {
2✔
157
                        this.famixRepo = famixRepo;
3✔
158
                        
159
                        this.keyToEntity = new Hashtable<IBinding,TNamedEntity>();
5✔
160
                        this.entityToKey = new Hashtable<TNamedEntity,IBinding>();
5✔
161
                        this.nameToEntity = new Hashtable<String,Collection<TNamedEntity>>();
5✔
162
                        this.typeToImpVar = new Hashtable<Type,ImplicitVars>();
5✔
163
                        
164
                        if (! this.famixRepo.isEmpty()) {
4✔
165
                                recoverExistingRepository();
2✔
166
                        }
167
                }
1✔
168

169
          public void mapKey(IBinding bnd, NamedEntity fmx) {
170
                mapEntityToKey(bnd, fmx);
×
171
        }
×
172

173
        /**
174
         * Resets the dictionnary in a proper state after loading entities from an existing MSE file:
175
         * <UL>
176
         * <li>map all named entities to their names in <b>mapName</b></li>
177
         * <li>reset some boolean properties (e.g. <b>isStub</b>) that are false (they are not saved in the mse file and therefore not initialized)</li>
178
         * </ul>
179
         */
180
        protected void recoverExistingRepository() {
181
                for (NamedEntity ent : famixRepo.all(NamedEntity.class)) {
13✔
182
                        mapEntityToName( ent.getName(), ent);
5✔
183
                        // for the Exception to be raised, the return value must be tested
184
                        try { if (((TCanBeStub) ent).getIsStub()) {} }
5✔
185
                        catch (NullPointerException e) { ((TCanBeStub)ent).setIsStub(Boolean.FALSE); }
6✔
186
                }
1✔
187

188
                for (Access acc : famixRepo.all(Access.class)) {
13✔
189
                        // for the Exception to be raised, the return value must be tested
190
                        try { if (acc.getIsWrite()) {}        }
4✔
191
                        catch (NullPointerException e) { acc.setIsWrite(Boolean.FALSE); }
5✔
192
                }
1✔
193
        }
1✔
194

195
        protected void mapEntityToName(String name, TNamedEntity ent) {
196
                
197
                Collection<TNamedEntity> l_ent = nameToEntity.get(name);
6✔
198
                if (l_ent == null) {
2✔
199
                        l_ent = new LinkedList<TNamedEntity>();
4✔
200
                }
201
                l_ent.add(ent);
4✔
202
                nameToEntity.put(name, l_ent);
6✔
203
        }
1✔
204

205
        public void removeEntity( NamedEntity ent) {
206
                IBinding key;
207
                key = entityToKey.get(ent);
6✔
208
                if (key != null) {
2✔
209
                        entityToKey.remove(ent);
5✔
210
                        keyToEntity.remove(key);
5✔
211
                }
212

213
                Collection<TNamedEntity> l_ent = nameToEntity.get(ent.getName());
7✔
214
                if (l_ent != null) {
2✔
215
                        l_ent.remove(ent);
4✔
216
                }
217

218
                famixRepo.getElements().remove(ent);
6✔
219
        }
1✔
220
        
221
        protected void mapEntityToKey(IBinding key, TNamedEntity ent) {
222
                TNamedEntity old = keyToEntity.get(key);
6✔
223
                if (old != null) {
2!
224
                        entityToKey.remove(old);
×
225
                }
226
                keyToEntity.put(key, ent);
6✔
227
                entityToKey.put(ent, key);
6✔
228
        }
1✔
229
        
230
        /**
231
         * Returns all the Famix Entity with the given name and class 
232
         * @param fmxClass -- the subtype of Famix Entity we are looking for
233
         * @param name -- the name of the entity
234
         * @return the Collection of Famix Entities with the given name and class (possibly empty)
235
         */
236
        @SuppressWarnings("unchecked")
237
        public <T extends TNamedEntity> Collection<T> getEntityByName(java.lang.Class<T> fmxClass, String name) {
238
                Collection<T> ret = new LinkedList<T>();
4✔
239
                Collection<TNamedEntity> l_name = nameToEntity.get(name);
6✔
240
                
241
                if (l_name != null ) {
2✔
242
                        for (TNamedEntity obj : l_name) {
10✔
243
                                if (fmxClass.isInstance(obj)) {
4✔
244
                                        ret.add((T) obj);
4✔
245
                                }
246
                        }
1✔
247
                }
248

249
                return ret;
2✔
250
        }
251

252
        /**
253
         * Returns the Famix Entity associated to the given key.
254
         * <b>Note</b>: Be careful that ImplicitVariables share the same binding as their associated Class and cannot be retrieved with this method.
255
         * In such a case, this method will always retrieve the Class associated to the key.
256
         * To get an ImplicitVariable from the key, use {@link #getImplicitVariableByBinding(IBinding, String)}
257
         * @param key -- the key
258
         * @return the Famix Entity associated to the binding or null if not found
259
         */
260
        public TNamedEntity getEntityByKey(IBinding key) {
261
                if (key == null) {
2✔
262
                        return null;
2✔
263
                }
264
                else {
265
                        return keyToEntity.get(key);
6✔
266
                }
267
        }
268

269
        /**
270
         * Returns the key associated to a Famix Entity.
271
         * @param e -- the Named entity
272
         * @return the key associated to this entity or null if none
273
         */
274
        public IBinding getEntityKey(TNamedEntity e) {
275
                return entityToKey.get(e);
6✔
276
        }
277

278
        /**
279
         * Creates and returns a FAMIX Entity of the type <b>fmxjava.lang.Class</b>.
280
         * The Entity is always created.
281
         * @param fmxClass -- the FAMIX class of the instance to create
282
         * @param name -- the name of the new instance must not be null (and this is not tested)
283
         * @return the FAMIX Entity or null in case of a FAMIX error
284
         */
285
        protected <T extends TNamedEntity & TSourceEntity> T createFamixEntity(java.lang.Class<T> fmxClass, String name) {
286
                T fmx = null;
2✔
287

288
                if (name == null) {
2!
289
                        return null;
×
290
                }
291
                
292
                try {
293
                        fmx = fmxClass.getDeclaredConstructor().newInstance();
9✔
294
                } catch (java.lang.Exception e) {
×
295
                        System.err.println("Unexpected error, could not create a FAMIX entity: "+e.getMessage());
×
296
                        e.printStackTrace();
×
297
                }
1✔
298
                
299
                if (fmx != null) {
2!
300
                        fmx.setName(name);
3✔
301
                        if (fmx instanceof TCanBeStub) {
3!
302
                                ((TCanBeStub)fmx).setIsStub(Boolean.TRUE);
4✔
303
                        }
304

305
                        mapEntityToName(name, fmx);
4✔
306
                        
307
                        // put new entity in Famix repository
308
                        famixRepoAdd((Entity) fmx);
4✔
309
                }
310

311
                return fmx;
2✔
312
        }
313
        
314
        /**
315
         * Returns a Famix Entity of the type <b>fmxjava.lang.Class</b> and maps it to its binding <b>bnd</b> (if not null).
316
         * The Entity is created if it did not exist.
317
         * @param fmxClass -- the Famix class of the instance to create
318
         * @param bnd -- the binding to map to the new instance
319
         * @param name -- the name of the new instance (used if <pre>{@code bnd == null}</pre>)
320
         * @return the Famix Entity or null if <b>bnd</b> was null or in case of a Famix error
321
         */
322
        @SuppressWarnings("unchecked")
323
        protected <T extends TNamedEntity & TSourceEntity> T ensureFamixEntity(java.lang.Class<T> fmxClass, IBinding bnd, String name) {
324
                T fmx = null;
2✔
325
                
326
                /* 
327
                 * Unfortunately different entities with the same name and same type may exist
328
                 * e.g. 2 parameters of 2 different methods but having the same name
329
                 * so we cannot recover just from the name
330
                 */
331
                
332
                if (bnd != null) {
2✔
333
                        fmx = (T) getEntityByKey(bnd);
4✔
334
                        if (fmx != null) {
2✔
335
                                return fmx;
2✔
336
                        }
337
                }
338
                // else
339
                fmx = createFamixEntity(fmxClass, name);
5✔
340
                if ( (bnd != null) && (fmx != null) ) {
4!
341
                        keyToEntity.put(bnd, fmx);
6✔
342
                        entityToKey.put(fmx, bnd);
6✔
343
                }
344
                
345
                return fmx;
2✔
346
        }
347

348
        /**
349
         * Adds an already created Entity to the Famix repository
350
         * Used mainly for non-NamedEntity, for example relationships
351
         * @param e -- the Famix entity to add to the repository
352
         */
353
        public void famixRepoAdd(Entity e) {
354
                this.famixRepo.add(e);
4✔
355
        }
1✔
356

357

358
        /**
359
         * Returns a Famix ParametricClass with the given <b>name</b>, creating it if it does not exist yet
360
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
361
         * @param name -- the name of the Famix Class
362
         * @return the Famix Class or null in case of a Famix error
363
         */
364
        public ParametricClass ensureFamixParametricClass(ITypeBinding key, String name, TWithTypes owner) {
365
                ParametricClass fmx = ensureFamixEntity(ParametricClass.class, key, name);
7✔
366
                if(key != null) {
2✔
367
                        for (ITypeBinding tp : key.getErasure().getTypeParameters()) {
18✔
368
                                // If there is a type parameter, then fmx will be a Famix ParametricClass
369
                                // note: in Famix, the owner of the TypeParameter is the ParametricClass
370
                                TypeParameter fmxParam = ensureFamixTypeParameter(tp,
5✔
371
                                                tp.getName(), fmx);
2✔
372
                                fmxParam.setGenericEntity((TParametricEntity)fmx);
3✔
373
                                if (fmxParam != null) {
2!
374
                                        fmxParam.setIsStub(fmx.getIsStub());
4✔
375
                                }
376
                        }
377
                }
378
                
379
                fmx.setTypeContainer(owner);
3✔
380
                return fmx;
2✔
381
        }
382

383
        /**
384
         * Returns a Famix ParametricInterface with the given <b>name</b>, creating it if it does not exist yet
385
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
386
         * @param name -- the name of the Famix Class
387
         * @return the Famix Class or null in case of a Famix error
388
         */
389
        public ParametricInterface ensureFamixParametricInterface(ITypeBinding key, String name, TWithTypes owner) {
390
                ParametricInterface fmx = ensureFamixEntity(ParametricInterface.class, key, name);
7✔
391
                if(key != null) {
2!
392
                        for (ITypeBinding tp : key.getTypeParameters()) {
17✔
393
                                // If there is a type parameter, then fmx will be a Famix ParametricInterface
394
                                // note: in Famix, the owner of the TypeParameter is the ParametricInterface
395
                                TypeParameter fmxParam = ensureFamixTypeParameter(tp,
5✔
396
                                                tp.getName(), fmx);
2✔
397
                                fmxParam.setGenericEntity((ParametricInterface)fmx);
3✔
398
                                if (fmxParam != null) {
2!
399
                                        fmxParam.setIsStub(false);
4✔
400
                                }
401
                        }
402
                }
403
                fmx.setTypeContainer(owner);
3✔
404
                return fmx;
2✔
405
        }
406

407
        public AnnotationInstanceAttribute createFamixAnnotationInstanceAttribute(AnnotationTypeAttribute att, String value) {
408
                AnnotationInstanceAttribute fmx = null;
2✔
409
                if ( (att != null) && (value != null) ) {
4!
410
                        fmx = new AnnotationInstanceAttribute();
4✔
411
                        fmx.setAnnotationTypeAttribute(att);
3✔
412
                        fmx.setValue(value);
3✔
413
                        this.famixRepo.add(fmx);
4✔
414
                }
415
                return fmx;
2✔
416
        }
417

418
        public AnnotationInstance addFamixAnnotationInstance(TWithAnnotationInstances fmx, AnnotationType annType, Collection<AnnotationInstanceAttribute> annAtts) {
419
                AnnotationInstance inst = null;
2✔
420
                if ( (fmx != null) && (annType != null) ) {
4!
421
                        inst = new AnnotationInstance();
4✔
422
                        inst.setAnnotatedEntity(fmx);
3✔
423
                        inst.setAnnotationType(annType);
3✔
424
                        inst.addAttributes(annAtts);
3✔
425
                        this.famixRepo.add(inst);
4✔
426
                }
427
                return inst;
2✔
428
        }
429

430
        ///// ensure Famix Relationships /////
431

432
        /**
433
         * Returns a Famix Inheritance relationship between two Famix Classes creating it if needed
434
         * @param sup -- the super class
435
         * @param sub -- the sub class
436
         * @param prev -- previous inheritance relationship in the same context
437
         * @return the Inheritance relationship
438
         */
439
        public Inheritance ensureFamixInheritance(TWithInheritances sup, TWithInheritances sub, TAssociation prev, ITypeBinding supBnd) {
440
                if ( (sup == null) || (sub == null) ) {
4!
441
                        return null;
×
442
                }
443

444
                // Does the inheritance already exist?
445
                for (TInheritance i : (sup).getSubInheritances()) {                        
11✔
446
                        if (i.getSubclass() == sub) {
4✔
447
                                return (Inheritance) i;
3✔
448
                        }
449
                }
1✔
450

451
                Inheritance inh;
452
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5✔
453
                        inh = (ParametricInheritance)buildFamixParametricAssociation(new ParametricInheritance(), supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
13✔
454
                } else {
455
                        inh = new Inheritance();
4✔
456
                }
457

458
                inh.setSuperclass(sup);
3✔
459
                inh.setSubclass(sub);
3✔
460
                chainPrevNext(prev, inh);
4✔
461
                famixRepoAdd(inh);
3✔
462
                return inh;
2✔
463
        }
464
        
465
        /**
466
         * Creates the concretization between the type parameters of the generic entity that is target of an association 
467
         * and the concrete types that concretize them in this association.
468
         * @param association -- the association that must be linked to # or several concretizations
469
         * @param genericTypes -- the collection of type parameters declared in the generic entity
470
         * @param typeArguments -- the collection of concrete types linked to this association
471
         * @return the parametric association
472
         */
473
        public  <T extends TParametricEntity> TParametricAssociation buildFamixParametricAssociation(TParametricAssociation association, ITypeBinding[] genericTypes, ITypeBinding[] typeArguments
474
        ) {
475
                
476
                Iterator<ITypeBinding> genericIterator = Arrays.asList(genericTypes).iterator();
4✔
477
                Iterator<ITypeBinding> concreteIterator = Arrays.asList(typeArguments).iterator();
4✔
478

479
                while (concreteIterator.hasNext() && genericIterator.hasNext()) {
6!
480
                        TTypeArgument typeArgument = (TTypeArgument)ensureFamixType(concreteIterator.next());
7✔
481
                        TypeParameter typeParameter = (TypeParameter)ensureFamixType(genericIterator.next());
7✔
482

483
                        Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5✔
484
                        association.addConcretization(concretization);
3✔
485
                }
1✔
486

487
                return association;
2✔
488
        }
489

490
        /**
491
         * Returns a Famix Concretization relationship between a Concrete Type and a ParameterType
492
         * @param typeArgument -- the concrete type
493
         * @param typeParameter -- the generic type parameter
494
         * @return the Concretization relationship
495
         */
496
        public Concretization ensureFamixConcretization(TTypeArgument typeArgument, TypeParameter typeParameter ) {
497
                if ( (typeArgument == null) || (typeParameter == null) ) {
4!
498
                        return null;
×
499
                }
500

501
                Concretization concretization = new Concretization();
4✔
502
                concretization.setTypeArgument(typeArgument);
3✔
503
                concretization.setTypeParameter(typeParameter);
3✔
504

505
                famixRepoAdd(concretization);
3✔
506
                return concretization;
2✔
507
        }
508
        
509
                /**
510
         * Returns a Famix Implementation relationship between two Famix Classes creating it if needed
511
         * @param myInterface -- the implemented interface
512
         * @param implementingClass -- the implementing class
513
         * @param prev -- previous inheritance relationship in the same context
514
         * @return the Inheritance relationship
515
         */
516
        public Implementation ensureFamixImplementation(TImplementable myInterface, TCanImplement implementingClass, TAssociation prev, ITypeBinding supBnd) {
517
                if ( (myInterface == null) || (implementingClass == null) ) {
4!
518
                        return null;
×
519
                }
520

521
                for (TImplementation imp : myInterface.getImplementations()) {
11✔
522
                        if (imp.getImplementingClass() == implementingClass) {
4✔
523
                                return (Implementation) imp;
3✔
524
                        }
525
                }
1✔
526
                
527
                Implementation implementation;
528
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5!
529
                        implementation = (ParametricImplementation)buildFamixParametricAssociation(new ParametricImplementation(), supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
13✔
530
                } else {
531
                        implementation = new Implementation();
4✔
532
                }
533

534
                implementation.setImplementingClass(implementingClass);
3✔
535
                implementation.setMyInterface(myInterface);
3✔
536
                chainPrevNext(prev, implementation);
4✔
537
                famixRepoAdd(implementation);
3✔
538
                return implementation;
2✔
539
        }
540

541
        public void ensureImplementedInterfaces(ITypeBinding bnd, TType fmx, TWithTypes owner, TAssociation lastAssociation) {
542
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17✔
543
                        TType superTyp;
544
                        if(intbnd.isClass()){
3✔
545
                                superTyp = this.ensureFamixInterface(intbnd, intbnd.getName(), null, intbnd.isGenericType() || intbnd.isParameterizedType() || intbnd.isRawType(), intbnd.getModifiers());
20!
546
                        }else {
547
                                superTyp = this.ensureFamixType(intbnd);
4✔
548
                        }
549
                        
550
                        if (bnd.isInterface()) {
3✔
551
                                // in Java "subtyping" link between 2 interfaces is call inheritance 
552
                                lastAssociation = ensureFamixInheritance((TWithInheritances)superTyp, (TWithInheritances)fmx, lastAssociation, intbnd);
10✔
553
                        }
554
                        else {
555
                                lastAssociation = ensureFamixImplementation((TImplementable)superTyp, (TCanImplement)fmx, lastAssociation, intbnd);
9✔
556
                        }
557
                }
558
        }
1✔
559

560
        /**
561
         * Returns a Famix Reference between two Famix Entities creating it if needed.<br>
562
         * If <code>prev == null</code> and a similar reference already exist (same <code>src</code>, same <code>tgt</code>), does not create a new one
563
         * @param src -- source of the reference
564
         * @param tgt -- target of the reference
565
         * @param prev -- previous reference relationship in the same context
566
         * @return the FamixReference
567
         */
568
        public Reference addFamixReference(Method src, TType tgt, TAssociation prev, ITypeBinding referredTypeBnd) {
569
                Reference ref;
570
                
571
                if ( (src == null) || (tgt == null) ) {
4!
572
                        return null;
×
573
                }
574

575
                if (prev == null) {
2✔
576
                        for (TReference existingRef : src.getOutgoingReferences()) {
7!
577
                                if (existingRef.getReferredEntity() == tgt) {
×
578
                                        return (Reference) existingRef;
×
579
                                }
580
                        }
×
581
                }
582

583
                /* issue <href="https://github.com/moosetechnology/VerveineJ/issues/146">146</href> an expression like <code>char[].class</code> is a <code>Class</code>
584
                 * gives referredTypeBnd.isParameterizedType() == true.
585
                 * We test <code>tgt instanceof PrimitiveType</code> to avoid this case */
586
                if (referredTypeBnd != null && referredTypeBnd.isParameterizedType() && ! (tgt instanceof PrimitiveType)) { // Needs checks and tests.
8✔
587
                        ref = (ParametricReference)buildFamixParametricAssociation(new ParametricReference(), referredTypeBnd.getErasure().getTypeParameters(), referredTypeBnd.getTypeArguments());
13✔
588
                } else {
589
                        ref = new Reference();
4✔
590
                }
591

592
                ref.setReferredEntity(tgt);
3✔
593
                ref.setReferencer(src);
3✔
594
                chainPrevNext(prev,ref);
4✔
595
                famixRepoAdd(ref);
3✔
596

597
                return ref;
2✔
598
        }
599

600
        /**
601
         * Returns a Famix Invocation between two Famix Entities creating it if needed
602
         * @param tMethod of the invocation
603
         * @param invoked -- method invoked
604
         * @param receiver of the invocation
605
         * @param signature -- i.e. actual invocation code
606
         * @param prev -- previous invocation relationship in the same context
607
         * @return the FamixInvocation
608
         */
609
        public Invocation addFamixInvocation(TMethod tMethod, TMethod invoked, TInvocationsReceiver receiver, String signature, TAssociation prev, IMethodBinding invokedBnd) {
610
                if ( (tMethod == null) || (invoked == null) ) {
4!
611
                        return null;
×
612
                }
613
                Invocation invocation;
614
                if (invokedBnd != null && invokedBnd.isParameterizedMethod()) {
5✔
615
                        invocation = (ParametricInvocation)buildFamixParametricAssociation(new ParametricInvocation(), invokedBnd.getMethodDeclaration().getTypeParameters(), invokedBnd.getTypeArguments());
13✔
616
                } else if ( invokedBnd != null && invokedBnd.isConstructor() && invokedBnd.getMethodDeclaration().getDeclaringClass().isGenericType()) {
10✔
617
                        invocation = (ParametricInvocation)buildFamixParametricAssociation(new ParametricInvocation(), invokedBnd.getMethodDeclaration().getDeclaringClass().getTypeParameters(), invokedBnd.getDeclaringClass().getTypeArguments());
15✔
618
                } else {
619
                        invocation = new Invocation();
4✔
620
                }
621

622
                invocation.setReceiver(receiver);
3✔
623
                invocation.setSender(tMethod);
3✔
624
                invocation.setSignature((signature == null) ? invoked.getSignature() : signature);
5!
625
                invocation.addCandidates(invoked);
3✔
626
                chainPrevNext(prev,invocation);
4✔
627
                famixRepoAdd(invocation);
3✔
628
                
629
                return invocation;
2✔
630
        }
631

632
        /**
633
         * Returns a Famix Access between two Famix Entities creating it if needed
634
         * @param accessor -- the entity (presumably a method) accessing the attribute
635
         * @param var -- the variable accessed
636
         * @param isWrite -- whether this is an access for reading or writing in the variable
637
         * @param prev -- previous access relationship in the same context
638
         * @return the FamixAccess
639
         */
640
        public Access addFamixAccess(TWithAccesses accessor, TStructuralEntity var, boolean isWrite, TAssociation prev) {
641
                if ( (accessor == null) || (var == null) ) {
4!
642
                        return null;
×
643
                }
644
                Access acc = new Access();
4✔
645
                acc.setAccessor(accessor);
3✔
646
                acc.setVariable((TAccessible) var);
3✔
647
                acc.setIsWrite(isWrite);
4✔
648
                chainPrevNext(prev, acc);
4✔
649
                famixRepoAdd(acc);
3✔
650
                
651
                return acc;
2✔
652
        }
653

654
        protected void chainPrevNext(TAssociation prev, TAssociation next) {
655
                if (prev != null) {
2✔
656
                        next.setPrevious(prev);  // not yet implemented in importer
3✔
657
                }
658
        }
1✔
659
        
660
        /**
661
         * Returns a Famix DeclaredException between a method and an Exception that it declares to throw
662
         * @param meth -- the method throwing the exception
663
         * @param excep -- the exception declared to be thrown
664
         * @return the DeclaredException
665
         */
666
        public TThrowable createFamixDeclaredException(Method meth, TThrowable excep) {
667
                if ( (meth == null) || (excep == null) ) {
4!
668
                        return null;
×
669
                }
670
                //org.moosetechnology.model.famixjava.famixjavaentities.Exception decl = new org.moosetechnology.model.famixjava.famixjavaentities.Exception();
671
                // decl.setExceptionClass(excep);
672
                // excep.getDeclaringEntities().add(meth);
673
                // famixRepoAdd(excep);
674
                meth.getDeclaredExceptions().add(excep);
5✔
675
                return excep;
2✔
676
        }
677

678
        /**
679
         * Returns a Famix CaughtException between a method and an Exception that is caught
680
         * @param meth -- the method catching the exception
681
         * @param excep -- the exception caught
682
         * @return the CaughtException
683
         */
684
        public TThrowable createFamixCaughtException(Method meth, TThrowable excep) {
685
                if ( (meth == null) || (excep == null) ) {
4!
686
                        return null;
×
687
                }
688
                // CaughtException decl = new CaughtException();
689
                // decl.setExceptionClass(excep);
690
                // decl.setDefiningEntity(meth);
691
                // famixRepoAdd(decl);
692
                meth.getCaughtExceptions().add(excep);
5✔
693
                return excep;
2✔
694
        }
695

696
        /**
697
         * Returns a Famix ThrownException between a method and an Exception that it (actually) throws.
698
         * Note: DeclaredException indicates that the method declares it can throw the exception,
699
         * here we state that the exception is actually thrown
700
         * @param meth -- the method throwing the exception
701
         * @param excep -- the exception thrown
702
         * @return the ThrownException
703
         */
704
        public TThrowable createFamixThrownException(Method meth, TThrowable excep) {
705
                if ( (meth == null) || (excep == null) ) {
4!
706
                        return null;
×
707
                }
708
                // ThrownException decl = new ThrownException();
709
                // decl.setExceptionClass(excep);
710
                // decl.setDefiningEntity(meth);
711
                // famixRepoAdd(decl);
712
                meth.getThrownExceptions().add(excep);
5✔
713
                return excep;
2✔
714
        }
715

716

717
        /**
718
         * Returns a Famix EntityTyping between a typed entity and a type.
719
         * @param typedEntity -- the typed entity
720
         * @param declaredType -- the declared type
721
         * @return the FamixEntityTyping
722
         */
723
        public EntityTyping ensureFamixEntityTyping(ITypeBinding declaredTypeBnd, TTypedEntity typedEntity, TType declaredType) {
724
                if ( (typedEntity == null) || (declaredType == null) ) {
4!
725
                        return null;
2✔
726
                }
727
                EntityTyping typing;
728
                if (declaredTypeBnd != null && declaredTypeBnd.isParameterizedType()) {
5✔
729
                        typing = (ParametricEntityTyping)buildFamixParametricAssociation(new ParametricEntityTyping(), declaredTypeBnd.getErasure().getTypeParameters(), declaredTypeBnd.getTypeArguments());
13✔
730
                } else {
731
                        typing = new EntityTyping();
4✔
732
                }
733
                typing.setTypedEntity(typedEntity);
3✔
734
                typing.setDeclaredType(declaredType);
3✔
735
                famixRepoAdd(typing);
3✔
736
                
737
                return typing;
2✔
738
        }
739

740

741
        ///// Special Case: ImplicitVariables /////
742

743
        /**
744
         * Returns the Famix ImplicitVariable associated to the given binding and name (self or super).
745
         * See also {@link #getEntityByKey(IBinding)}
746
         * @param bnd -- the binding
747
         * @return the Famix Entity associated to the binding or null if not found
748
         */
749
        @Deprecated
750
        public ImplicitVariable getImplicitVariableByBinding(IBinding bnd, String iv_name) {
751
                return getImplicitVariableByType((Class)getEntityByKey(bnd), iv_name);
×
752
        }
753
        
754
        /**
755
         * Returns the Famix ImplicitVariable associated to the given FamixType.
756
         * @param type -- the FamixType
757
         * @param name -- name of the ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
758
         * @return the Famix ImplicitVariable associated to the Type or null if not found
759
         */
760
        @Deprecated
761
        public ImplicitVariable getImplicitVariableByType(Type type, String name) {
762
                ImplicitVars iv = typeToImpVar.get(type);
×
763
                ImplicitVariable ret = null;
×
764
                
765
                if (iv == null) {
×
766
                        iv = new ImplicitVars();
×
767
                }
768
                
769
                if (name.equals(SELF_NAME)) {
×
770
                        ret = iv.self_iv;
×
771
                }
772
                else if (name.equals(SUPER_NAME)) {
×
773
                        ret = iv.super_iv;
×
774
                }
775

776
                return ret;
×
777
        }
778

779
        ///// Special Case: "Uniq" Entities /////
780

781
        /**
782
         * Creates or recovers a Famix Named Entity uniq for the given name.
783
         * For some specific entities we don't allow two of them with the same name.
784
         * This is the case e.g. for the default package, or the Java class "Object" and its package "java.lang".
785
         * @param fmxClass -- the Famix class of the instance to create
786
         * @param key -- a potential binding for the entity
787
         * @param name -- the name of the new instance (used if <pre>{@code bnd == null}</pre>)
788
         * @return the uniq Famix Entity for this binding and/or name
789
         */
790
        @SuppressWarnings("unchecked")
791
        public <T extends NamedEntity> T ensureFamixUniqEntity(java.lang.Class<T> fmxClass, IBinding key, String name) {
792
                T fmx = null;
2✔
793
                
794
                if (name == null) {
2!
795
                        return null;
×
796
                }
797
                
798
                if (key != null) {
2✔
799
                        fmx = (T) getEntityByKey(key);
5✔
800
                }
801
                
802
                if (fmx == null) {
2✔
803
                        Collection<T> l = getEntityByName( fmxClass, name);
5✔
804
                        if (l.size() > 0) {
3✔
805
                                fmx = l.iterator().next();
6✔
806
                        }
807
                        else {
808
                                fmx = createFamixEntity(fmxClass, name);
6✔
809
                        }
810
                        
811
                        if (key != null) {
2✔
812
                                // may happen for example if the entity was first created without binding
813
                                // and we find a binding for it later
814
                                keyToEntity.put(key, fmx);
6✔
815
                        }
816
                }
817

818
                return fmx;
2✔
819
        }
820

821
        /**
822
         * Creates or recovers the Famix Class that will own all stub methods (for which the real owner is unknown)
823
         *
824
         * @return a Famix class
825
         */
826
        public Class ensureFamixClassStubOwner() {
827
                Class fmx =  ensureFamixUniqEntity(Class.class, null, STUB_METHOD_CONTAINER_NAME);
7✔
828
                if (fmx != null) {
2!
829
                        fmx.setTypeContainer( ensureFamixPackageDefault());
4✔
830
                }
831
                ensureFamixInheritance(ensureFamixClassObject(null), fmx, /*prev*/null, null);
9✔
832

833
                return fmx;
2✔
834
        }
835

836
        public Type searchTypeInContext(String name, TWithTypes ctxt) {
837
                if (ctxt == null) {
×
838
                        return null;
×
839
                }
840
                
841
                for (TType candidate : ctxt.getTypes()) {
×
842
                        if (((TNamedEntity)candidate).getName().equals(name) ) {
×
843
                                return (Type) candidate;
×
844
                        }
845
                }
×
846
                
847
                return searchTypeInContext(name, Util.getOwner((TNamedEntity)ctxt));
×
848
        }
849

850
        /**
851
         * Returns a Famix Package associated with its IPackageBinding and/or fully qualified name.
852
         * The Entity is created if it does not exist.
853
         * We assume that Namespaces must be uniq for a given name
854
         * Also creates or recovers recusively it's parent namespaces.<br>
855
         * At least one of <b>bnd</b> and <b>name</b> must be non null.
856
         *
857
         * @param bnd  -- the JDT Binding that may be used as a uniq key to recover this namespace
858
         * @param name -- fully qualified name of the namespace (e.g. 'java.lang')
859
         * @return the Famix Namespace found or created. May return null in case of a Famix error
860
         */
861
        public Package ensureFamixPackage(IPackageBinding bnd, String name) {
862
                Package fmx = null;
2✔
863
                Package parent = null;
2✔
864

865
                if ((name == null) && (bnd != null)) {
4!
866
                        name = bnd.getName();
3✔
867
                }
868

869
                if ((name == null) || name.equals("")) {
6!
870
                        return ensureFamixPackageDefault();
3✔
871
                } else {
872
                        /* Note: Packages are created with their fully-qualified name to simplify recovering when we don't have a binding
873
                         * (for example when creating parent packages of a package we have a binding for).
874
                         * Because the preferred solution in Moose is to give their simple names to packages, they must be post-processed when
875
                         * all is said and done. */
876
                        fmx = ensureFamixUniqEntity(Package.class, bnd, name);
7✔
877
                        String parentName = removeLastPartOfPackageName(name);
4✔
878
                        if (parentName.length() > 0) {
3✔
879
                                parent = ensureFamixPackage(null, parentName);
5✔
880
                                // set the parentscope relationship
881
                                if ((parent != null) && (fmx != null) && (fmx.getParentPackage() == null)) {
7!
882
                                        parent.addChildEntities(fmx);
3✔
883
                                }
884
                        }
885
                }
886

887
                return fmx;
2✔
888
        }
889

890
        /**
891
         * Creates or recovers a default Famix Package.
892
         * Because this package does not really exist, it has no binding.
893
         *
894
         * @return a Famix Namespace
895
         */
896
        public Package ensureFamixPackageDefault() {
897
                Package fmx = ensureFamixUniqEntity(Package.class, null, DEFAULT_PCKG_NAME);
7✔
898

899
                return fmx;
2✔
900
        }
901

902
        /**
903
         * Creates or recovers a Famix Package for the package of Java class "Object" (i.e. "java.lang").
904
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
905
         *
906
         * @param bnd -- a potential binding for the "java.lang" package
907
         * @return a Famix Namespace for "java.lang"
908
         */
909
        public Package ensureFamixPackageJavaLang(IPackageBinding bnd) {
910
                Package fmx = this.ensureFamixPackage(bnd, OBJECT_PACKAGE_NAME);
5✔
911

912
                return fmx;
2✔
913
        }
914

915
        /**
916
         * Returns the Package with {@link #DEFAULT_PCKG_NAME} or <code>null</code> if not found
917
         */
918
        public Package getFamixPackageDefault() {
919
                Collection<Package> l = getEntityByName(Package.class, DEFAULT_PCKG_NAME);
5✔
920
                if (l.size() > 0) {
3!
921
                        return l.iterator().next();
5✔
922
                } else {
923
                        return null;
×
924
                }
925
        }
926

927
        /**
928
         * Returns a Famix Type with the given <b>name</b>, creating it if it does not exist yet.
929
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
930
         * @param bnd -- binding for the type to create
931
         * @param name of the type
932
         * @param owner of the type
933
         * @param ctxt -- context of use of the type
934
         */
935
        public TType ensureFamixType(ITypeBinding bnd, String name, TWithTypes owner, TWithTypes ctxt, int modifiers) {
936
                
937
                TType fmx = null;
2✔
938

939
                if (bnd == null) {
2✔
940
                        if (name == null) {
2!
941
                                return null;
2✔
942
                        }
943
                        fmx = searchTypeInContext(name, ctxt); // WildCard Types don't have binding
×
944
                        if (fmx != null) {
×
945
                                return fmx;
×
946
                        }
947

948
                        if ( (owner != null) && (owner instanceof TParametricEntity) ) {
×
949
                                return this.ensureFamixTypeParameter(null, name, owner);
×
950
                        }
951
                        else {
952
                                fmx = ensureFamixEntity(Type.class, bnd, name);
×
953
                                fmx.setTypeContainer(owner);
×
954
                                return fmx;
×
955
                        }
956
                }
957

958
                // bnd != null
959

960
                fmx = (TType) getEntityByKey(bnd);
5✔
961
                if (fmx != null) {
2✔
962
                        return fmx;
2✔
963
                }
964

965
                if (bnd.isArray()) {
3!
966
                        bnd = bnd.getElementType();
×
967
                }
968

969
                if (bnd.isPrimitive()) {
3✔
970
                        return this.ensureFamixPrimitiveType(bnd, name);
5✔
971
                }
972

973
                if (bnd.isEnum()) {
3!
974
                        return this.ensureFamixEnum(bnd, name, (ContainerEntity) owner);
×
975
                }
976

977
                if ((bnd.isRawType() || bnd.isGenericType()) && !bnd.isInterface() ) {
9✔
978
                        return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
10✔
979
                }
980
                
981
                if (bnd.isAnnotation()) {
3!
982
                        return this.ensureFamixAnnotationType(bnd, name, (ContainerEntity) owner);
×
983
                }
984

985
                if (bnd.isInterface()) {
3✔
986
                        return this.ensureFamixInterface(bnd, name, owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
19✔
987
                }
988

989
                if (isThrowable(bnd)) {
4✔
990
                        return this.ensureFamixException(bnd, name, owner, /*isGeneric*/false, modifiers);
8✔
991
                }
992
                if (bnd.isClass()) {
3✔
993
                        return this.ensureFamixClass(bnd, name, (TNamedEntity) owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
20!
994
                }
995
                if(bnd.isWildcardType()) {
3✔
996
                        return this.ensureFamixWildcardType(bnd, name, (TParametricEntity)owner, ctxt);
8✔
997
                }
998

999
                //otherwise (none of the above)
1000

1001
                if (name == null) {
2✔
1002
                        name = bnd.getName();
3✔
1003
                }
1004

1005
                if (owner == null) {
2!
1006
                        owner = (TWithTypes) this.ensureOwner(bnd);
5✔
1007
                }
1008

1009
                if (bnd.isTypeVariable() ) {
3!
1010
                        fmx = ensureFamixTypeParameter(bnd, name, owner);
6✔
1011
                        return fmx;
2✔
1012
                }
1013

1014
                fmx = ensureFamixEntity(Type.class, bnd, name);
×
1015
                fmx.setTypeContainer(owner);
×
1016
                return fmx;
×
1017
        }
1018

1019
        public TType ensureFamixType(ITypeBinding bnd, TWithTypes context) {
1020
                int modifiers = extractModifierOfTypeFrom(bnd);
4✔
1021
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8✔
1022
        }
1023
        
1024
        public TType ensureFamixType(ITypeBinding bnd) {
1025
                return ensureFamixType(bnd, /*ctxt*/null);
5✔
1026
        }
1027

1028
        private int extractModifierOfTypeFrom(ITypeBinding bnd) {
1029
                int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
7✔
1030
                return modifiers;
2✔
1031
        }
1032

1033
        public boolean isThrowable(ITypeBinding bnd) {
1034
                if (bnd == null) {
2!
1035
                        return false;
×
1036
                }
1037
                if (bnd.getQualifiedName().equals("java.lang.Throwable")) {
5✔
1038
                        return true;
2✔
1039
                } else if (bnd.getQualifiedName().equals("java.lang.Object")) {
5✔
1040
                        return false;
2✔
1041
                }
1042
                else {
1043
                        return isThrowable(bnd.getSuperclass());
5✔
1044
                }
1045
        }
1046

1047
        /**
1048
         * Returns a Famix Class associated with the ITypeBinding.
1049
         * The Entity is created if it does not exist.
1050
         * @param name -- the name of the FAMIX Method (MUST NOT be null, but this is not checked)
1051
         * @param owner -- type defining the method (should not be null, but it will work if it is) 
1052
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1053
         */
1054
        @SuppressWarnings("deprecation")
1055
        public Class ensureFamixClass(ITypeBinding bnd, String name, TNamedEntity owner, boolean isGeneric, int modifiers) {
1056
                Class fmx = null;
2✔
1057

1058
                // --------------- some special cases
1059
                if (bnd != null) {
2✔
1060
                        if (bnd.isArray()) {
3!
1061
                                bnd = bnd.getElementType();
×
1062
                        }
1063

1064
                        // for inner classes defined in generics !!! For others should not change anything
1065
                        bnd = bnd.getErasure();
3✔
1066
                }
1067

1068
                // ---------------- to avoid useless computations if we can
1069
                fmx = (Class) getEntityByKey(bnd);
5✔
1070
                if (fmx != null) {
2✔
1071
                        return fmx;
2✔
1072
                }
1073

1074
                // --------------- name
1075
                if (name == null) {
2✔
1076
                        if (bnd == null) {
2!
1077
                                return null;  // not much we can do
×
1078
                        } else if (!bnd.isAnonymous()) {
3!
1079
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5✔
1080
                        } else { // anonymous class
1081
                                if (bnd.getSuperclass() != null) {
×
1082
                                        name = bnd.getSuperclass().getName();
×
1083
                                }
1084
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1085
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1086
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1087
                                                name = bnd.getInterfaces()[0].getName();
×
1088
                                        }
1089
                                        else {
1090
                                                name = "???";
×
1091
                                        }
1092
                                }
1093
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1094
                        }
1095
                }
1096

1097
                if (name.equals(OBJECT_NAME)) { // TODO && owner == java.lang
4✔
1098
                        return ensureFamixClassObject(bnd);
4✔
1099
                }
1100

1101
                // --------------- owner
1102
                if (owner == null) {
2✔
1103
                        if (bnd != null) {
2✔
1104
                                owner = ensureOwner(bnd);
4✔
1105
                        }
1106
                        /*                                owner = ensureFamixPackageDefault();
1107
                        } else {*/
1108
                }
1109

1110
                // --------------- recover from name ?
1111
                if (owner != null) {
2✔
1112
                        for (Class candidate : this.getEntityByName(Class.class, name)) {
13✔
1113
                                if (matchAndMapClass(bnd, name, (ContainerEntity) owner, candidate)) {
8✔
1114
                                        fmx = candidate;
2✔
1115
                                        break;
1✔
1116
                                }
1117
                        }
1✔
1118
                }
1119

1120
                // ---------------- create
1121
                if (fmx == null) {
2✔
1122
                        if (isGeneric) {
2✔
1123
                                fmx = ensureFamixParametricClass(bnd, name, (TWithTypes) owner);
8✔
1124
                        }
1125
                        else {
1126
                                fmx = ensureFamixEntity(Class.class, bnd, name);
7✔
1127
                                fmx.setTypeContainer((TWithTypes)owner);
4✔
1128
                        }
1129
                }
1130

1131
                if (fmx!=null) {
2!
1132
                        // we just created it or it was not bound, so we make sure it has the right information in it
1133
                        if (bnd != null) {
2✔
1134
                                setClassModifiers(fmx, bnd.getDeclaredModifiers());
5✔
1135
                        }
1136
                        TAssociation lastAssoc = null;
2✔
1137

1138
                        if (bnd != null) {
2✔
1139
                                ITypeBinding supbnd = bnd.getSuperclass();
3✔
1140
                                if (supbnd != null) {
2✔
1141
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11✔
1142
                                }
1143
                                else {
1144
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixClassObject(null), fmx, lastAssoc, null);
9✔
1145
                                }
1146
                                ensureImplementedInterfaces(bnd, fmx, (TWithTypes) owner, lastAssoc);
7✔
1147
                        }
1148
                }
1149

1150
                return fmx;
2✔
1151
        }
1152

1153
        /**
1154
         * Returns a Famix Exception associated with the ITypeBinding.
1155
         * The Entity is created if it does not exist.
1156
         * @param name -- the name of the Famix Exception (MUST NOT be null, but this is not checked)
1157
         * @param owner -- type defining the Exception (should not be null, but it will work if it is) 
1158
         *
1159
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1160
         */
1161
        public <T extends TWithTypes & TNamedEntity> Exception ensureFamixException(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1162
                Exception fmx = null;
2✔
1163

1164
                // --------------- some special cases
1165
                if (bnd != null) {
2✔
1166
                        if (bnd.isArray()) {
3!
1167
                                bnd = bnd.getElementType();
×
1168
                        }
1169

1170
                        // for inner classes defined in generics !!! For others should not change anything
1171
                        bnd = bnd.getErasure();
3✔
1172
                }
1173

1174
                // ---------------- to avoid useless computations if we can
1175
                fmx = (Exception) getEntityByKey(bnd);
5✔
1176
                if (fmx != null) {
2✔
1177
                        return fmx;
2✔
1178
                }
1179

1180
                // --------------- name
1181
                if (name == null) {
2✔
1182
                        if (bnd == null) {
2!
1183
                                return null;  // not much we can do
×
1184
                        } else if (!bnd.isAnonymous()) {
3!
1185
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5✔
1186
                        } else { // anonymous class
1187
                                if (bnd.getSuperclass() != null) {
×
1188
                                        name = bnd.getSuperclass().getName();
×
1189
                                }
1190
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1191
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1192
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1193
                                                name = bnd.getInterfaces()[0].getName();
×
1194
                                        }
1195
                                        else {
1196
                                                name = "???";
×
1197
                                        }
1198
                                }
1199
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1200
                        }
1201
                }
1202

1203
                // --------------- owner
1204
                if (owner == null) {
2✔
1205
                        if (bnd == null) {
2✔
1206
                                owner = ensureFamixPackageDefault();
4✔
1207
                        } else {
1208
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1209
                        }
1210
                }
1211

1212
                // --------------- recover from name ?
1213
                for (Exception candidate : this.getEntityByName(Exception.class, name)) {
13✔
1214
                        if (matchAndMapClass(bnd, name, (T) owner, candidate)) {
8!
UNCOV
1215
                                fmx = candidate;
×
UNCOV
1216
                                break;
×
1217
                        }
1218
                }
1✔
1219

1220
                // ---------------- create
1221
                if (fmx == null) {
2!
1222
                        fmx = ensureFamixEntity(Exception.class, bnd, name);
7✔
1223
                        fmx.setTypeContainer(owner);
3✔
1224
                }
1225

1226
                if (fmx!=null) {
2!
1227
                        // we just created it or it was not bound, so we make sure it has the right information in it
1228
                        TAssociation lastAssoc = null;
2✔
1229
                        if (bnd != null) {
2✔
1230
                                ITypeBinding supbnd = bnd.getSuperclass();
3✔
1231
                                if (supbnd != null) {
2!
1232
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11✔
1233
                                }
1234
                                else {
1235
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixClassObject(null), fmx, lastAssoc, null);
×
1236
                                }
1237
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssoc);
6✔
1238
                        }
1239
                }
1240

1241
                return fmx;
2✔
1242
        }
1243

1244
        /**
1245
         * Returns a FAMIX Interface with the given <b>name</b>, creating it if it does not exist yet.
1246
         * @param name -- the name of the FAMIX Method (MUST NOT be null, but this is not checked)
1247
         * @param owner -- type defining the method (should not be null, but it will work if it is) 
1248
         * @return the FAMIX Class or null in case of a FAMIX error
1249
         */
1250
        public <T extends TWithTypes & TNamedEntity> Interface ensureFamixInterface(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1251
                Interface fmx = null;
2✔
1252

1253
                // --------------- some special cases
1254
                if (bnd != null) {
2!
1255
                        if (bnd.isArray()) {
3!
1256
                                bnd = bnd.getElementType();
×
1257
                        }
1258

1259
                        // for inner classes defined in generics !!! For others should not change anything
1260
                        bnd = bnd.getErasure();
3✔
1261
                }
1262

1263
                // ---------------- to avoid useless computations if we can
1264
                fmx = (Interface) getEntityByKey(bnd);
5✔
1265
                if (fmx != null) {
2✔
1266
                        return fmx;
2✔
1267
                }
1268

1269
                // --------------- name
1270
                if (name == null) {
2✔
1271
                        if (bnd == null) {
2!
1272
                                return null;  // not much we can do
×
1273
                        } else if (!bnd.isAnonymous()) {
3!
1274
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5✔
1275
                        } else { // anonymous class
1276
                                if (bnd.getSuperclass() != null) {
×
1277
                                        name = bnd.getSuperclass().getName();
×
1278
                                }
1279
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1280
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1281
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1282
                                                name = bnd.getInterfaces()[0].getName();
×
1283
                                        }
1284
                                        else {
1285
                                                name = "???";
×
1286
                                        }
1287
                                }
1288
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1289
                        }
1290
                }
1291

1292
                // --------------- owner
1293
                if (owner == null) {
2✔
1294
                        if (bnd == null) {
2!
1295
                                owner = ensureFamixPackageDefault();
×
1296
                        } else {
1297
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1298
                        }
1299
                }
1300

1301
                // --------------- recover from name ?
1302
                for (Interface candidate : this.getEntityByName(Interface.class, name)) {
13✔
1303
                        if (matchAndMapInterface(bnd, name, (T) owner, candidate)) {
8✔
1304
                                fmx = candidate;
2✔
1305
                                break;
1✔
1306
                        }
1307
                }
1✔
1308

1309
                // ---------------- create
1310
                if (fmx == null) {
2✔
1311
                        if (isGeneric) {
2✔
1312
                                fmx = ensureFamixParametricInterface(bnd, name, owner);
7✔
1313
                        }
1314
                        else {
1315
                                fmx = ensureFamixEntity(Interface.class, bnd, name);
7✔
1316
                                fmx.setTypeContainer(owner);
3✔
1317
                        }
1318
                }
1319

1320
                if (fmx!=null) {
2!
1321
                        // we just created it or it was not bound, so we make sure it has the right information in it
1322
                        if (bnd != null) {
2!
1323
                                setInterfaceModifiers(fmx, bnd.getModifiers());
5✔
1324
                        }
1325
                        TAssociation lastAssociation = null;
2✔
1326
                        if (bnd != null) {
2!
1327
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssociation);
6✔
1328
                        }
1329
                }
1330
                return fmx;
2✔
1331
        }
1332

1333
        public TType asClass(TType excepFmx) {
NEW
1334
                Class tmp = null;
×
NEW
1335
                IBinding key = null;
×
1336
                try {
NEW
1337
                        TWithTypes owner = (TWithTypes) Util.getOwner(excepFmx);
×
1338
                        owner.getTypes().remove(excepFmx);
×
1339
                        removeEntity((NamedEntity) excepFmx);
×
1340

1341
                        key = entityToKey.get((NamedEntity) excepFmx);
×
1342
                        tmp = ensureFamixEntity(Class.class, key, excepFmx.getName());
×
1343
                        tmp.setTypeContainer((ContainerEntity)owner);
×
1344

1345
                        tmp.addMethods(((TWithMethods) excepFmx).getMethods());
×
1346
                        if (excepFmx instanceof TWithAttributes) {
×
1347
                                tmp.addAttributes(((TWithAttributes) excepFmx).getAttributes());
×
1348
                        }
1349

1350
                        if (key != null) {
×
1351
                                setClassModifiers(tmp, key.getModifiers());
×
1352
                        }
1353

1354
                        if (excepFmx instanceof TWithInheritances) {
×
1355
                                tmp.addSuperInheritances(((TWithInheritances) excepFmx).getSuperInheritances());
×
UNCOV
1356
                                tmp.addSubInheritances(((TWithInheritances) excepFmx).getSubInheritances());
×
1357
                        }
1358
                        tmp.setSourceAnchor(excepFmx.getSourceAnchor());
×
1359
                        tmp.addAnnotationInstances(((NamedEntity) excepFmx).getAnnotationInstances());
×
1360
                        // tmp.addComments(excepFmx.getComments());
UNCOV
1361
                        tmp.addIncomingReferences(excepFmx.getIncomingReferences());
×
1362
                        tmp.setIsStub(excepFmx.getIsStub());
×
1363
                        tmp.addTypes(((ContainerEntity) excepFmx).getTypes());
×
1364
                }
1365
                catch( ConcurrentModificationException e) {
×
1366
                        e.printStackTrace();
×
1367
                }
×
1368

1369
                return tmp;
×
1370
        }
1371

1372
        public TThrowable asException(TType fmxType) {
1373
                if (fmxType instanceof Exception) {
3✔
1374
                        return (Exception) fmxType;
3✔
1375
                }
1376
                if(fmxType instanceof TypeParameter) {
3✔
1377
                        return (TypeParameter) fmxType;
3✔
1378
                }
1379

1380
                Exception fmxException = null;
2✔
1381
                IBinding key = null;
2✔
1382

1383
                try {
1384
                        key = entityToKey.get((NamedEntity) fmxType);
7✔
1385

1386
                        /* Remove entity immediatly so that its key and name are not "reassigned" in the various cache dictionnaries
1387
                         * the object still exists and its properties are still accessible */
1388
                        removeEntity((NamedEntity) fmxType);
4✔
1389

1390
                        TWithTypes owner = fmxType.getTypeContainer();
3✔
1391
                        fmxType.setTypeContainer(null);
3✔
1392
                        fmxException = ensureFamixException((ITypeBinding) key, fmxType.getName(), owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
10✔
1393

1394
                        fmxException.addMethods( new ArrayList<>( ((TWithMethods)fmxType).getMethods() ) );
8✔
1395
                        if (fmxType instanceof TWithAttributes) {
3!
1396
                                fmxException.addAttributes( new ArrayList<>( ((TWithAttributes)fmxType).getAttributes() ) );
8✔
1397
                        }
1398

1399
                        if (fmxType instanceof TWithInheritances) {
3!
1400
                                fmxException.addSuperInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSuperInheritances() ) );
8✔
1401
                                fmxException.addSubInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSubInheritances() ) );
8✔
1402
                        }
1403
                        fmxException.setSourceAnchor(fmxType.getSourceAnchor());
4✔
1404
                        fmxException.addAnnotationInstances( new ArrayList<>( ((NamedEntity)fmxType).getAnnotationInstances() ) );
8✔
1405
                        fmxException.addIncomingReferences( new ArrayList<>( fmxType.getIncomingReferences() ) );
7✔
1406
                        fmxException.setIsStub(fmxType.getIsStub());
4✔
1407
                        fmxException.addTypes( new ArrayList<>( ((ContainerEntity) fmxType).getTypes() ) );
8✔
1408
                }
NEW
1409
                catch( ConcurrentModificationException e) {
×
NEW
1410
                        e.printStackTrace();
×
1411
                }
1✔
1412

1413
                return (TThrowable)fmxException;
2✔
1414
        }
1415

1416
        /**
1417
         * helper method, we know the type exists, ensureFamixClass will recover it
1418
         */
1419
        public Class getFamixClass(ITypeBinding bnd, String name, TNamedEntity owner) {
1420
                return ensureFamixClass(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1421
        }
1422

1423
        /**
1424
         * helper method, we know the type exists, ensureFamixInterface will recover it
1425
         */
1426
        public Interface getFamixInterface(ITypeBinding bnd, String name, ContainerEntity owner) {
1427
                return ensureFamixInterface(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1428
        }
1429

1430
        /**
1431
         * helper method, we know the type exists, ensureFamixInterface will recover it
1432
         */
1433
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1434
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1435
        }
1436

1437
        /**
1438
         * Ensures a famix entity for the owner of a binding.<br>
1439
         * This owner can be a method, a class or a namespace
1440
         * @param bnd -- binding for the owned entity
1441
         * @return a famix entity for the owner
1442
         */
1443
        private TNamedEntity ensureOwner(ITypeBinding bnd) {
1444
                TNamedEntity owner = null;
2✔
1445
                IMethodBinding parentMtd = bnd.getDeclaringMethod();
3✔
1446
                if (parentMtd != null) {
2✔
1447
                        owner = this.ensureFamixMethod(parentMtd);  // cast needed to desambiguate the call
5✔
1448
                }
1449
                else {
1450
                        ITypeBinding parentClass = bnd.getDeclaringClass();
3✔
1451
                        if (parentClass != null) {
2✔
1452
                                TType tmpOwn = this.ensureFamixType(parentClass);
4✔
1453
                                if (tmpOwn instanceof ParametricClass) {
3✔
1454
                                        owner =  (TNamedEntity) ((ParametricClass) tmpOwn);
4✔
1455
                                }
1456
                                else {
1457
                                        owner = tmpOwn;
2✔
1458
                                }
1459
                        }
1✔
1460
                        else {
1461
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1462
                                if (parentPckg != null) {
2!
1463
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1464
                                } else {
UNCOV
1465
                                        owner = this.ensureFamixPackageDefault();
×
1466
                                }
1467
                        }
1468
                }
1469
                return owner;
2✔
1470
        }
1471

1472

1473
        /**
1474
         * Returns a FAMIX PrimitiveType with the given <b>name</b>, creating it if it does not exist yet
1475
         * We assume that PrimitiveType must be uniq for a given name
1476
         * @param name -- the name of the FAMIX PrimitiveType
1477
         * @return the FAMIX PrimitiveType or null in case of a FAMIX error
1478
         */
1479
        public PrimitiveType ensureFamixPrimitiveType(ITypeBinding bnd, String name) {
1480
                if (name == null) {
2✔
1481
                        if (bnd == null) {
2!
UNCOV
1482
                                return null;
×
1483
                        } else {
1484
                                name = bnd.getName();
3✔
1485
                        }
1486
                }
1487
                return ensureFamixUniqEntity(PrimitiveType.class, bnd, name);
7✔
1488
        }
1489

1490
        public <T extends TWithTypes & TNamedEntity> org.moosetechnology.model.famix.famixjavaentities.Enum ensureFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1491
                org.moosetechnology.model.famix.famixjavaentities.Enum fmx = null;
2✔
1492

1493
                // --------------- to avoid useless computations if we can
1494
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5✔
1495
                if (fmx != null) {
2✔
1496
                        return fmx;
2✔
1497
                }
1498

1499
                // --------------- name
1500
                if (name == null) {
2✔
1501
                        if (bnd == null) {
2!
UNCOV
1502
                                return null;
×
1503
                        }
1504
                        else {
1505
                                name = bnd.getName();
3✔
1506
                        }
1507
                }
1508

1509
                // --------------- owner
1510
                if (owner == null) {
2✔
1511
                        if (bnd == null) {
2!
UNCOV
1512
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1513
                        } else {
1514
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1515
                        }
1516
                }
1517

1518
                // --------------- recover from name ?
1519
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9!
UNCOV
1520
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
UNCOV
1521
                                fmx = candidate;
×
UNCOV
1522
                                break;
×
1523
                        }
1524
                }
×
1525

1526
                if (fmx == null) {
2!
1527
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7✔
1528
                        fmx.setTypeContainer(owner);
3✔
1529
                }
1530

1531
                if ((fmx != null) && (bnd != null) ) {
4!
1532
                        setVisibility(fmx, bnd.getModifiers());
5✔
1533
                }
1534

1535
                return fmx;
2✔
1536
        }
1537

1538
        /**
1539
         * helper method, we know the type exists, ensureFamixEnum will recover it
1540
         */
1541
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1542
                return ensureFamixEnum(bnd, name, owner);
6✔
1543
        }
1544

1545
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1546
                EnumValue fmx = null;
2✔
1547

1548
                // --------------- to avoid useless computations if we can
1549
                fmx = (EnumValue)getEntityByKey(bnd);
5✔
1550
                if (fmx != null) {
2✔
1551
                        return fmx;
2✔
1552
                }
1553

1554
                // --------------- name
1555
                if (name == null) {
2!
UNCOV
1556
                        if (bnd == null) {
×
UNCOV
1557
                                return null;
×
1558
                        }
1559
                        else {
1560
                                name = bnd.getName();
×
1561
                        }
1562
                }
1563

1564
                // --------------- owner
1565
                if (owner == null) {
2✔
1566
                        if (bnd == null) {
2!
UNCOV
1567
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1568
                        }
1569
                        else {
1570
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7✔
1571
                        }
1572
                }
1573

1574
                // --------------- recover from name ?
1575
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9!
UNCOV
1576
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
UNCOV
1577
                                fmx = candidate;
×
UNCOV
1578
                                break;
×
1579
                        }
1580
                }
×
1581
                if (fmx == null) {
2!
1582
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7✔
1583
                        fmx.setParentEnum(owner);
3✔
1584
                }
1585

1586
                if (fmx!=null) {
2!
1587
                        fmx.setParentEnum(owner);
3✔
1588
                }
1589

1590
                return fmx;
2✔
1591
        }
1592

1593
        /**
1594
         * helper method, we know the type enumValue, ensureFamixEnumValue will recover it
1595
         */
1596
        public EnumValue getFamixEnumValue(IVariableBinding bnd, String name, Enum owner) {
UNCOV
1597
                return ensureFamixEnumValue(bnd, name, owner);
×
1598
        }
1599

1600
        /**
1601
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1602
         */
1603
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1604
                AnnotationType fmx = null;
2✔
1605

1606
                // --------------- to avoid useless computations if we can
1607
                fmx = (AnnotationType)getEntityByKey(bnd);
5✔
1608
                if (fmx != null) {
2✔
1609
                        return fmx;
2✔
1610
                }
1611

1612
                // --------------- name
1613
                if (name == null) {
2✔
1614
                        if (bnd == null) {
2!
UNCOV
1615
                                return null;
×
1616
                        }
1617
                        else {
1618
                                name = bnd.getName();
3✔
1619
                        }
1620
                }
1621

1622
                // --------------- owner
1623
                if (owner == null) {
2✔
1624
                        if (bnd == null) {
2!
UNCOV
1625
                                owner = ensureFamixPackageDefault();
×
1626
                        }
1627
                        else {
1628
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1629
                                if (parentPckg != null) {
2!
1630
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1631
                                } else {
UNCOV
1632
                                        owner = this.ensureFamixPackageDefault();
×
1633
                                }
1634
                        }
1635
                }
1636

1637
                // --------------- recover from name ?
1638
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13✔
1639
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7✔
1640
                                fmx = candidate;
2✔
1641
                                break;
1✔
1642
                        }
1643
                }
1✔
1644

1645
                // --------------- create
1646
                if (fmx == null) {
2✔
1647
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7✔
1648
                        fmx.setAnnotationTypesContainer(owner);
3✔
1649
                }
1650

1651
                if ( (fmx!=null) && (bnd != null) ) {
4!
1652
                        // Not supported in Famix
1653

1654
                        // setVisibility(fmx, bnd.getModifiers());
1655
                }
1656

1657
                return fmx;
2✔
1658
        }
1659

1660
        /**
1661
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1662
         */
1663
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1664
                return ensureFamixAnnotationType(bnd, name, owner);
6✔
1665
        }
1666

1667
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1668
                AnnotationTypeAttribute fmx = null;
2✔
1669

1670
                // --------------- to avoid useless computations if we can
1671
                fmx = (AnnotationTypeAttribute)getEntityByKey(bnd);
5✔
1672
                if (fmx != null) {
2✔
1673
                        return fmx;
2✔
1674
                }
1675

1676
                // --------------- name
1677
                if (name == null) {
2!
UNCOV
1678
                        if (bnd == null) {
×
UNCOV
1679
                                return null;
×
1680
                        }
1681
                        else {
1682
                                name = bnd.getName();
×
1683
                        }
1684
                }
1685

1686
                // --------------- owner
1687
                if (owner == null) {
2!
UNCOV
1688
                        if (bnd == null) {
×
UNCOV
1689
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1690
                        }
1691
                        else {
1692
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
1693
                                if (parentType != null) {
×
UNCOV
1694
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1695
                                }
1696
                                else  {
1697
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1698
                                }
1699
                        }
1700
                }
1701

1702
                // --------------- recover from name ?
1703
                for (AnnotationTypeAttribute candidate : getEntityByName(AnnotationTypeAttribute.class, name) ) {
13✔
1704
                        // JDT treats annotation type attributes as methods ...
1705
                        // checkAndMapMethod wants a signature as 2nd argument so we add empty param list
1706
                        if ( (bnd != null) && matchAndMapMethod(bnd, name+"()", null, owner, candidate) ) {
11!
UNCOV
1707
                                fmx = candidate;
×
UNCOV
1708
                                break;
×
1709
                        }
1710
                        // if the binding is null, the annotationTypeAttribute migth have been created
1711
                        else if ( (bnd == null) && matchAndMapVariable(null, name, owner, candidate)) {
2!
1712
                                fmx = candidate;
×
UNCOV
1713
                                break;
×
1714
                        }
1715
                }
1✔
1716

1717
                if (fmx == null) {
2!
1718
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7✔
1719
                        fmx.setParentType(owner);
3✔
1720
                }
1721

1722
                if ( (fmx!=null) && (bnd != null) ) {
4!
1723
                        // Not suopp
1724

1725
                        // setVisibility(fmx, bnd.getModifiers());
1726
                }
1727

1728
                return fmx;
2✔
1729
        }
1730

1731
        /**
1732
         * helper method, we know the attribute exists, ensureFamixAnnotationTypeAttribute will recover it
1733
         */
1734
        public AnnotationTypeAttribute getFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1735
                return ensureFamixAnnotationTypeAttribute( bnd, name, owner);
6✔
1736
        }
1737
        
1738
        
1739
        /**
1740
         * Returns a FAMIX Wildcard with its bounds
1741
         * @param bnd
1742
         * @param name
1743
         * @param owner
1744
         * @return
1745
         */
1746
        public Wildcard ensureFamixWildcardType(ITypeBinding bnd, String name, TParametricEntity owner, TWithTypes ctxt) {
1747
                Wildcard fmx = this.ensureFamixEntity(Wildcard.class, bnd, bnd.getName());
8✔
1748
                if(bnd.getBound() != null) {
3✔
1749
                        Type bound = (Type) this.ensureFamixType(bnd.getBound()); 
6✔
1750
                        if(bnd.isUpperbound()) {
3✔
1751
                                fmx.setUpperBound(bound);
3✔
1752
                                bound.addUpperBoundedWildcards(fmx);
4✔
1753
                        }else{
1754
                                fmx.setLowerBound(bound);
3✔
1755
                                bound.addLowerBoundedWildcards(fmx);
3✔
1756
                        }
1757
                }
1758
                return fmx;
2✔
1759
        }
1760

1761
        /**
1762
         * Returns a Famix TypeParameter (created by a Famix ParametricEntity) with the given <b>name</b>, creating it if it does not exist yet
1763
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public
1764
         * @param name -- the name of the Famix TypeParameter
1765
         * @return the Famix TypeParameter or null in case of a Famix error
1766
         */
1767
        public TypeParameter ensureFamixTypeParameter(ITypeBinding bnd,        String name, TWithTypes owner) {
1768
                TypeParameter fmx = null;
2✔
1769

1770
                // --------------- to avoid useless computations if we can
1771
                fmx = (TypeParameter)getEntityByKey(bnd);
5✔
1772
                if (fmx != null) {
2✔
1773
                        return fmx;
2✔
1774
                }
1775

1776
                // --------------- name
1777
                if (name == null) {
2✔
1778
                        if (bnd == null) {
2!
UNCOV
1779
                                return null;
×
1780
                        }
1781
                        else {
1782
                                name = bnd.getName();
3✔
1783
                        }
1784
                }
1785

1786
                // --------------- owner
1787
                if (owner == null) {
2!
UNCOV
1788
                        if (bnd == null) {
×
UNCOV
1789
                                owner = null;  // not really sure what to do here
×
1790
                        }
1791
                        else {
1792
                                if (bnd.getDeclaringClass() != null) {
×
1793
                                        owner = (TWithTypes) this.ensureFamixType(bnd.getDeclaringClass());
×
UNCOV
1794
                                }else if(bnd.getDeclaringMethod() != null) {
×
UNCOV
1795
                                        owner = (TWithTypes) this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1796
                                }
1797
                                else {
1798
                                        owner = null;  // not really sure what to do here
×
1799
                                }
1800
                        }
1801
                }
1802

1803
                // --------------- recover from name ?
1804
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13✔
1805
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8✔
1806
                                fmx = (TypeParameter) candidate;
3✔
1807
                                break;
1✔
1808
                        }
1809
                }
1✔
1810

1811
                // --------------- create
1812
                if (fmx == null) {
2✔
1813
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7✔
1814
                        if(bnd != null && bnd.getSuperclass() != null) {
5!
1815
                                Type upperBound = (Type)ensureFamixType(bnd.getSuperclass());
6✔
1816
                                fmx.setUpperBound(upperBound);
3✔
1817
                        }
1818
                        if(bnd != null && bnd.getInterfaces().length > 0) {
6✔
1819
                                for(ITypeBinding intbnd: bnd.getInterfaces()) {
17✔
1820
                                        Type upperBound = (Type)ensureFamixType(intbnd);
5✔
1821
                                        fmx.setUpperBound(upperBound);
3✔
1822
                                }
1823
                        }
1824
                        fmx.setTypeContainer((ContainerEntity) owner);
4✔
1825
                }
1826

1827
                return fmx;
2✔
1828
        }
1829

1830

1831
        public IBinding getTypeParameterOwner(ITypeBinding typeParameterBinding, IBinding currentOwner) {
1832
                
1833

1834

UNCOV
1835
                return currentOwner;
×
1836
        }
1837

1838

1839

1840
        /**
1841
         * Checks whether the existing unmapped Famix Namespace matches the binding.
1842
         * Checks that the candidate has the same name as the JDT bound package, and checks recursively that owners also match.
1843
         *
1844
         * @param bnd       -- a JDT binding that we are trying to match to the candidate
1845
         * @param name      of the package
1846
         * @param owner     of the package
1847
         * @param candidate -- a Famix Entity
1848
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1849
         */
1850
        private boolean matchAndMapPackage(IPackageBinding bnd, String name, Package owner, NamedEntity candidate) {
1851
                if (!(candidate instanceof Package)) {
3!
UNCOV
1852
                        return false;
×
1853
                }
1854

1855
                // check whether bnd and candidate are already bound
1856
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1857
                if (res == CheckResult.MATCH) {
3✔
1858
                        return true;
2✔
1859
                } else if (res == CheckResult.FAIL) {
3!
UNCOV
1860
                        return false;
×
1861
                }
1862

1863
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7✔
1864
                        return false;
2✔
1865
                }
1866

1867
                // names match, not need to look at owner because names of Namespaces are their fully qualified name
1868
                conditionalMapToKey(bnd, candidate);
4✔
1869
                return true;
2✔
1870
        }
1871

1872
        /**
1873
         * Checks whether the existing unmapped Famix Type matches the binding.
1874
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1875
         * We also check that the actual class of the candidate matches (can be a sub-class of FamixType).
1876
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1877
         * @param name of the type
1878
         * @param owner of the type
1879
         * @param candidate -- a Famix NamedEntity (Class, Type, PrimitiveType, Enum, AnnotationType)
1880
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1881
         */
1882
        private <T extends TWithTypes & TNamedEntity> boolean matchAndMapType(ITypeBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
1883
                if (! (candidate instanceof Type) ) {
3!
UNCOV
1884
                        return false;
×
1885
                }
1886

1887
                // check whether bnd and candidate are already bound
1888
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1889
                if (res == CheckResult.MATCH) {
3✔
1890
                        return true;
2✔
1891
                }
1892
                else if (res == CheckResult.FAIL) {
3✔
1893
                        return false;
2✔
1894
                }
1895

1896
                if ( (bnd != null) && (bnd.isArray()) ) {
5!
UNCOV
1897
                                bnd = bnd.getElementType();
×
1898
                }
1899

1900
                // checking names
1901
                if ( (bnd != null) && (bnd.isParameterizedType() || bnd.isRawType()) ) {
8!
UNCOV
1902
                        name = bnd.getErasure().getName();
×
1903
                }
1904
                else if (bnd != null) {
2✔
1905
                        name = bnd.getName();
3✔
1906
                }
1907
                // else name = name
1908
                if (checkNameMatch(null, name, candidate) == CheckResult.FAIL) {
7✔
1909
                        return false;
2✔
1910
                }
1911

1912
                // special case of primitive types
1913
                if (candidate instanceof PrimitiveType) {
3!
UNCOV
1914
                        if ( (bnd != null) && bnd.isPrimitive() ) {
×
1915
                                // names are equal so it's OK
UNCOV
1916
                                conditionalMapToKey(bnd, candidate);
×
UNCOV
1917
                                return true;
×
1918
                        }
UNCOV
1919
                        else if ( (bnd == null) && (owner == null) ) {
×
1920
                                return true;
×
1921
                        }
1922
                }
1923

1924
                // check owners without bnd
1925
                if (bnd == null) {
2✔
1926
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1927
                }
1928

1929
                // check owners with bnd
1930
                // type is an annotation
1931
                if (bnd.isAnnotation() && (candidate instanceof AnnotationType)) {
6!
1932
                        if (matchAndMapPackage(bnd.getPackage(), owner.getName(), (Package) Util.getOwner(owner), Util.getOwner(candidate))) {
13!
1933
                                conditionalMapToKey(bnd, candidate);
4✔
1934
                                return true;
2✔
1935
                        } else {
UNCOV
1936
                                return false;
×
1937
                        }
1938
                }
1939

1940
                // check owners with bnd
1941
                // type is a Parameterized type
1942
                if ((bnd.isParameterizedType() || bnd.isRawType()) && (candidate instanceof ParametricClass)) {
6!
UNCOV
1943
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1944
                }
1945

1946
                // check owners with bnd
1947
                // type is an Enum
1948
                if (bnd.isEnum() && (candidate instanceof Enum)) {
3!
UNCOV
1949
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1950
                }
1951

1952
                // check owners with bnd
1953
                // type is something elae (a class or interface)
1954
                // Annotation are interfaces too, so we should check this one after isAnnotation
1955
                if ( bnd.isClass()) {
3!
UNCOV
1956
                        return matchAndMapClass(bnd, name, owner, (Type) candidate);
×
1957
                }
1958

1959
                if(bnd.isInterface()) {
3!
1960
                        return matchAndMapInterface(bnd, name, owner, (Type) candidate);
×
1961
                }
1962

1963
                return false;
2✔
1964
        }
1965

1966
        /**
1967
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1968
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1969
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1970
         * @param name of the class
1971
         * @param owner of the class
1972
         * @param candidate -- a Famix Entity
1973
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1974
         */
1975
        private boolean matchAndMapClass(ITypeBinding bnd, String name, TNamedEntity owner, TType candidate) {
1976
                if (!(candidate instanceof Class)) {
3!
UNCOV
1977
                        return false;
×
1978
                }
1979

1980
                // check whether bnd and candidate are already bound
1981
                CheckResult res = checkKeyMatch(bnd, (NamedEntity) candidate);
6✔
1982
                if (res == CheckResult.MATCH) {
3!
UNCOV
1983
                        return true;
×
1984
                } else if (res == CheckResult.FAIL) {
3✔
1985
                        return false;
2✔
1986
                }
1987

1988
                if (checkNameMatch(bnd, name, (NamedEntity) candidate) == CheckResult.FAIL) {
8!
UNCOV
1989
                        return false;
×
1990
                }
1991

1992
                // checking owner
1993
                return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1994
        }
1995

1996
        /**
1997
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1998
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1999
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2000
         * @param name of the class
2001
         * @param owner of the class
2002
         * @param candidate -- a Famix Entity
2003
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2004
         */
2005
        private boolean matchAndMapInterface(ITypeBinding bnd, String name, TNamedEntity owner, Type candidate) {
2006
                if (!(candidate instanceof Interface)) {
3!
UNCOV
2007
                        return false;
×
2008
                }
2009

2010
                // check whether bnd and candidate are already bound
2011
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
2012
                if (res == CheckResult.MATCH) {
3!
UNCOV
2013
                        return true;
×
2014
                } else if (res == CheckResult.FAIL) {
3✔
2015
                        return false;
2✔
2016
                }
2017

2018
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
UNCOV
2019
                        return false;
×
2020
                }
2021

2022
                // checking owner
2023
                return matchAndMapTypeOwner(bnd, owner, candidate);
6✔
2024
        }
2025

2026
        /**
2027
         * Checks whether the existing unmapped Famix "Method" matches the binding.
2028
         * Checks that the candidate has the same name and same signature as the JDT bound method, and checks recursively that owners also match.
2029
         * Note that AnnotationTypeAttribute are treated as methods by JDT, so they are checked here.
2030
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2031
         * @param sig -- signature of the method
2032
         * @param retTyp -- return type of the method
2033
         * @param owner of the method
2034
         * @param candidate -- a Famix Entity (regular Method or AnnotationTypeAttribute)
2035
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2036
         */
2037
        private  boolean matchAndMapMethod(IMethodBinding bnd, String sig, TType retTyp, TNamedEntity owner, NamedEntity candidate) {
2038
                if (! (candidate instanceof Method) ) {
3✔
2039
                        return false;
2✔
2040
                }
2041

2042
                // check whether bnd and candidate are already bound
2043
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
2044
                if (res == CheckResult.MATCH) {
3!
UNCOV
2045
                        return true;
×
2046
                }
2047
                else if (res == CheckResult.FAIL) {
3✔
2048
                        return false;
2✔
2049
                }
2050

2051
                // checking names
2052
                String name = (sig != null) ? sig.substring(0, sig.indexOf('(')) : null;
10!
2053
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
UNCOV
2054
                        return false;
×
2055
                }
2056

2057
                // for methods, the name is not enough, we must test the signature also
2058
                // but not for AnnotationTypeAttribute
2059

2060
                        if (bnd != null) {
2✔
2061
                                sig = bnd.getName() + "(" + signatureParamsFromBinding(bnd) + ")";
7✔
2062
                        }
2063
                        if (! ((Method) candidate).getSignature().equals(sig)) {
6✔
2064
                                return false;
2✔
2065
                        }
2066

2067
                        // and still for method, must also check the return type
2068
                        if (bnd != null) {
2✔
2069
                                if (bnd.isConstructor()) {
3!
UNCOV
2070
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
×
UNCOV
2071
                                                return false;
×
2072
                                        }
2073
                                        // else OK for now
2074
                                }
2075
                                else { // not a constructor
2076
                                        if ( ((Method) candidate).getDeclaredType() == null ) {
4!
UNCOV
2077
                                                return false;
×
2078
                                        }
2079
                                        else if (! matchAndMapType(bnd.getReturnType(), null, null, ((Method) candidate).getDeclaredType()) ) {
10!
UNCOV
2080
                                                return false;
×
2081
                                        }
2082
                                        // else OK for now
2083
                                }
2084
                        }
2085
                        else {  // bnd == null
2086
                                if (retTyp == null) { // similar to (bnd.isConstructor())
2!
2087
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
4!
UNCOV
2088
                                                return false;
×
2089
                                        }
2090
                                        // else OK for now
2091
                                } else { // (ret != null)  i.e. not a constructor
2092
                                        if (((Method) candidate).getDeclaredType() == null) {
×
UNCOV
2093
                                                return false;
×
UNCOV
2094
                                        } else if (!matchAndMapType(null, retTyp.getName(), Util.getOwner(retTyp), (NamedEntity) ((Method) candidate).getDeclaredType())) {
×
UNCOV
2095
                                                return false;
×
2096
                                        }
2097
                                        // else OK for now
2098
                                }
2099
                        }
2100

2101

2102
                // check owner
2103
                if (matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, Util.getOwner(candidate)) == CheckResult.MATCH) {
13✔
2104
                        conditionalMapToKey(bnd, candidate);
4✔
2105
                        return true;
2✔
2106
                } else {
2107
                        return false;
2✔
2108
                }
2109
        }
2110

2111
        /**
2112
         * Checks whether the candidate (an existing unmapped Famix "Variable" like Attribute, Parameter, ...) matches the binding.
2113
         * Checks that the candidate has the same name as the JDT bound variable, and checks recursively that owners also match.
2114
         * The Famix candidate is a NamedEntity and not a StructuralEntity to allow dealing with Famix EnumValue that JDT treats as variables
2115
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2116
         * @param name of the variable
2117
         * @param owner of the variable
2118
         * @param candidate -- a Famix Entity (a StructuralEntity or an EnumValue)
2119
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2120
         */
2121
        private boolean matchAndMapVariable(IVariableBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
2122
                if (!(candidate instanceof TStructuralEntity)) {
3!
UNCOV
2123
                        return false;
×
2124
                }
2125

2126
                // check whether bnd and candidate are already bound
2127
                CheckResult keyMatch = checkKeyMatch(bnd, candidate);
5✔
2128
                if (keyMatch == CheckResult.MATCH) {
3!
UNCOV
2129
                        return true;
×
2130
                } else if (keyMatch == CheckResult.FAIL) {
3✔
2131
                        return false;
2✔
2132
                }
2133

2134
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
UNCOV
2135
                        return false;
×
2136
                }
2137

2138
                // check owner
2139
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3✔
2140

2141
                // local variable or parameter ?
2142
                // owner is a Method? (for example in case of an anonymous class)
2143
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidateOwner);
11✔
2144
                if (res == CheckResult.FAIL) {
3✔
2145
                        return false;
2✔
2146
                } else if (res == CheckResult.MATCH) {
3!
UNCOV
2147
                        conditionalMapToKey(bnd, candidate);
×
UNCOV
2148
                        return true;
×
2149
                }
2150

2151
                // check owner
2152
                // <anArray>.length field?
2153
                if (name.equals("length")) {
4!
UNCOV
2154
                        boolean isArrayLengthField = ((bnd != null) && (bnd.getDeclaringClass() == null)) ||
×
UNCOV
2155
                                                                                 ((bnd == null) && (owner.getName().equals(EntityDictionary.ARRAYS_NAME)));
×
UNCOV
2156
                        if (isArrayLengthField) {
×
UNCOV
2157
                                if (candidateOwner.getName().equals(EntityDictionary.ARRAYS_NAME)) {
×
2158
                                        conditionalMapToKey(bnd, candidate);
×
2159
                                        return true;
×
2160
                                }
2161
                                else {
2162
                                        return false;
×
2163
                                }
2164
                        }
2165
                }
2166

2167
                // check owner
2168
                // "normal" field?
2169
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2170
                if (res == CheckResult.MATCH) {
3!
2171
                        conditionalMapToKey(bnd, candidate);
4✔
2172
                        return true;
2✔
2173
                }
UNCOV
2174
                return false;
×
2175
        }
2176

2177
        /**
2178
         * Checks whether the existing unmapped Famix Type's parent (or owner) matches the binding's owner.
2179
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
2180
         * @param bnd -- a JDT binding whose owner we are trying to match to the candidate's owner
2181
         * @param owner -- the owner of the type
2182
         * @param candidate -- a Famix Entity
2183
         * @return whether we found a match (if <b>true</b>, the mapping is recorded)
2184
         */
2185
        private boolean matchAndMapTypeOwner(ITypeBinding bnd, TNamedEntity owner, Type candidate) {
2186
                ContainerEntity candidateOwner = Util.getOwner(candidate);
4✔
2187

2188
                // owner is a Method? (for example in case of an anonymous class)
2189
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11✔
2190
                if (res == CheckResult.MATCH) {
3!
UNCOV
2191
                        conditionalMapToKey(bnd, candidate);
×
UNCOV
2192
                        return true;
×
2193
                } else if (res == CheckResult.FAIL) {
3!
UNCOV
2194
                        return false;
×
2195
                }
2196

2197
                // owner is a class ?
2198
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2199
                if (res == CheckResult.MATCH) {
3✔
2200
                        conditionalMapToKey(bnd, candidate);
4✔
2201
                        return true;
2✔
2202
                }
2203
                else if (res == CheckResult.FAIL) {
3✔
2204
                        return false;
2✔
2205
                }
2206

2207
                // owner must be a package
2208
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12✔
2209
                        conditionalMapToKey(bnd, candidate);
4✔
2210
                        return true;
2✔
2211
                }
2212
                return false;
2✔
2213
        }
2214

2215
        /**
2216
         * Check whether the owner of candidates is a method macthinf either methBnd or owner
2217
         * @param methBnd
2218
         * @param owner
2219
         * @param candidateOwner
2220
         * @return a {@link CheckResult}
2221
         */
2222
        private  <T extends TNamedEntity> CheckResult matchAndMapOwnerAsMethod(IMethodBinding methBnd, T owner, T candidateOwner) {
2223
                if ((methBnd != null) || ((owner != null) && (owner instanceof Method))) {
7!
2224
                        if (!(candidateOwner instanceof Method)) {
3!
UNCOV
2225
                                return CheckResult.FAIL;
×
2226
                        }
2227

2228
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7!
2229
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7!
2230
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8!
2231

2232
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9!
UNCOV
2233
                                return CheckResult.MATCH;
×
2234
                        } else {
2235
                                return CheckResult.FAIL;
2✔
2236
                        }
2237
                }
2238
                return CheckResult.UNDECIDED;
2✔
2239
        }
2240

2241
        /**
2242
         * @param typBnd
2243
         * @param owner
2244
         * @param candidateOwner
2245
         * @return a {@link CheckResult}
2246
         */
2247
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2248
                if ((typBnd != null) || ((owner != null) && (owner instanceof Type))) {
7!
2249
                        if (!(candidateOwner instanceof Type)) {
3✔
2250
                                return CheckResult.FAIL;
2✔
2251
                        }
2252

2253
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6!
2254
                        String ownerName = (owner != null) ? ((Type) owner).getName() : null;
7!
2255

2256
                        if (matchAndMapType(typBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2257
                                return CheckResult.MATCH;
2✔
2258
                        } else {
2259
                                return CheckResult.FAIL;
2✔
2260
                        }
2261
                }
2262
                return CheckResult.UNDECIDED;
2✔
2263
        }
2264

2265
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2266
                if ((pckgBnd != null) || ((owner != null) && (owner instanceof Package))) {
7!
2267
                        if (!(candidateOwner instanceof Package)) {
3!
UNCOV
2268
                                return CheckResult.FAIL;
×
2269
                        }
2270

2271
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7!
2272
                        String ownerName = (owner != null) ? ((Package) owner).getName() : null;
7!
2273

2274
                        if (matchAndMapPackage(pckgBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2275
                                return CheckResult.MATCH;
2✔
2276
                        } else {
2277
                                return CheckResult.FAIL;
2✔
2278
                        }
2279
                }
UNCOV
2280
                return CheckResult.UNDECIDED;
×
2281
        }
2282

2283
        /**
2284
         * Checks whether the name and the candidate matches the name of the entity (given either by 'bnd' or 'name')<br>
2285
         * 'name' and 'bnd' cannot be null together
2286
         * @param bnd -- binding associated with the entity may be null
2287
         * @param name -- name of the entity may be null
2288
         * @param candidate
2289
         * @return true if names match, false if not
2290
         */
2291
        private CheckResult checkNameMatch(IBinding bnd, String name, TNamedEntity candidate) {
2292
                if ( (bnd != null) && (! bnd.getName().equals(candidate.getName())) ) {
8!
UNCOV
2293
                        return CheckResult.FAIL;
×
2294
                }
2295
                else if ( (bnd == null) && (name != null) && (! name.equals(candidate.getName())) ) {
9!
2296
                        return CheckResult.FAIL;
2✔
2297
                }
2298
                else {
2299
                        return CheckResult.MATCH;
2✔
2300
                }
2301
        }
2302

2303
        /**
2304
         * Check whether key and candidate are already bound together, whether either is bound to something else, or whether none is bound
2305
         * @param key
2306
         * @param candidate
2307
         * @return <ul><li><b>-1</b>, if either is bound to something else</li><li><b>0</b>, if none is bound (or key is null)</li><li><b>1</b>, if they are bound to each other</li></ul>
2308
         */
2309
        private CheckResult checkKeyMatch(IBinding key, TNamedEntity candidate) {
2310
                if (key == null) {
2✔
2311
                        return CheckResult.UNDECIDED;
2✔
2312
                }
2313

2314
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5✔
2315
                if (bound == candidate) {
3✔
2316
                        return CheckResult.MATCH;
2✔
2317
                }
2318
                else if (bound != null) {
2✔
2319
                        return CheckResult.FAIL;
2✔
2320
                }
2321
                else if (getEntityKey(candidate) != null) {
4✔
2322
                        // candidate already bound, and not to this binding
2323
                        return CheckResult.FAIL;
2✔
2324
                }
2325
                else {
2326
                        return CheckResult.UNDECIDED;
2✔
2327
                }
2328
        }
2329

2330
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2331
                if (bnd != null) {
2✔
2332
                        mapEntityToKey(bnd, ent);
4✔
2333
                }
2334
        }
1✔
2335

2336
        public Method ensureFamixMethod(IMethodBinding bnd) {
2337
                return ensureFamixMethod(
9✔
2338
                                bnd,
2339
                                /*name*/null,
2340
                                /*paramsType*/(Collection<String>)null,
2341
                                /*returnType*/null,
2342
                                /*owner*/null,
2343
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6✔
2344
        }
2345

2346
        /**
2347
         * Returns a Famix Method associated with the IMethodBinding. The Entity is created if it does not exist.
2348
         * The Entity is created if it does not exist.
2349
         * @param name -- the name of the FAMIX Method (MUST NOT be null, but this is not checked)
2350
         * @param ret -- Famix Type returned by the method (ideally should only be null in case of a constructor, but will accept it in any case)
2351
         * @param owner -- type defining the method (should not be null, but it will work if it is)
2352
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2353
         */
2354
        public Method ensureFamixMethod(IMethodBinding bnd, String name, Collection<String> paramTypes, TType ret, TWithMethods owner, int modifiers) {
2355
                Method fmx = null;
2✔
2356
                String sig;
2357
                boolean delayedRetTyp;
2358

2359
                // --------------- to avoid useless computations if we can
2360
                fmx = (Method)getEntityByKey(bnd);
5✔
2361
                if (fmx != null) {
2✔
2362
                        return fmx;
2✔
2363
                }
2364

2365
                // --------------- name
2366
                if (name == null) {
2✔
2367
                        if (bnd == null) {
2✔
2368
                                return null;
2✔
2369
                        }
2370
                        else {
2371
                                name = bnd.getName();
3✔
2372
                        }
2373
                }
2374

2375
                // --------------- signature
2376
                sig = name + "(";
3✔
2377
                 if (bnd != null) {
2✔
2378
                    sig += signatureParamsFromBinding(bnd);
7✔
2379
                }
2380
        else if (paramTypes != null) {
2!
2381
                        sig += signatureParamsFromStringCollection(paramTypes);
7✔
2382
                }
2383
                else {
UNCOV
2384
                        sig += "???";
×
2385
                }
2386
                sig += ")";
3✔
2387

2388
                // --------------- return type
2389
                delayedRetTyp = false;
2✔
2390
                ITypeBinding retTypBnd = null;
2✔
2391
                if (ret == null) {
2!
2392
                        if (bnd == null) {
2✔
2393
                                ret = null;  // what else ?
3✔
2394
                        }
2395
                        else {
2396
                                if (bnd.isConstructor()) {
3✔
2397
                                        ret = null;
3✔
2398
                                }
2399
                                else {
2400

2401
                                        // must create the return type
2402
                                        // but for method like "<T> T mtd()" where T belongs to mtd and mtd returns T,
2403
                                        // we need T to create the method and the method to create T ...
2404
                                        // so we need to test the situation and deal with it
2405
                                        retTypBnd = bnd.getReturnType();
3✔
2406
                                        if (retTypBnd == null) {
2✔
2407
                                                ret = null;
3✔
2408
                                        }
2409
                                        else if (retTypBnd.isArray()) {
3✔
2410
                                                retTypBnd = retTypBnd.getElementType();
3✔
2411
                                        }
2412

2413
                                        if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9✔
2414
                                                ret = null;
2✔
2415
                                                delayedRetTyp = true;
3✔
2416
                                        }
2417
                                        else {
2418
                                                ret = this.ensureFamixType(retTypBnd,(TWithTypes) /*ctxt*/owner);
6✔
2419
                                        }
2420
                                }
2421
                        }
2422
                }
2423

2424
                // --------------- owner
2425
                if (owner == null) {
2✔
2426
                        if (bnd == null) {
2✔
2427
                                owner = ensureFamixClassStubOwner();
4✔
2428
                        }
2429
                        else {
2430
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4✔
2431
                                if (classBnd != null) {
2!
2432
                                        TType tmpOwn = ensureFamixType(classBnd);
4✔
2433

2434
                                        owner = (TWithMethods) tmpOwn;
3✔
2435
                                        
2436
                                }
1✔
2437
                                else {
UNCOV
2438
                                        owner = ensureFamixClassStubOwner();
×
2439
                                }
2440
                        }
2441
                }
2442

2443
                // --------------- recover from name ?
2444
                for (Method candidate : this.getEntityByName(Method.class, name)) {
13✔
2445
                        if (matchAndMapMethod(bnd, sig, ret, (TNamedEntity) owner, candidate)) {
9✔
2446
                                fmx = candidate;
2✔
2447
                                break;
1✔
2448
                        }
2449
                }
1✔
2450

2451
                if (fmx == null) {
2✔
2452
                        if(bnd != null && bnd.isGenericMethod()) {
5✔
2453
                                fmx = ensureFamixEntity(ParametricMethod.class, bnd, name);
7✔
2454
                                for(ITypeBinding param: bnd.getTypeParameters()) {
18✔
2455
                                        TypeParameter fmxParam = this.ensureFamixTypeParameter(param, null, (TWithTypes)fmx);
6✔
2456
                                        fmxParam.setGenericEntity((ParametricMethod)fmx);
4✔
2457
                                }
2458
                        // parameterized method binding = when the method is the target of an invocation.
2459
                        } else if (bnd != null && bnd.isParameterizedMethod()) {
5!
UNCOV
2460
                                fmx = (ParametricMethod)this.ensureFamixMethod(bnd.getMethodDeclaration());
×
2461
                        }else{
2462
                                fmx = ensureFamixEntity(Method.class, bnd, name);
7✔
2463
                        }
2464
                        
2465
                        fmx.setSignature(sig);
3✔
2466
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
7✔
2467
                        ensureFamixEntityTyping(returnTypeBnd, fmx, ret);
6✔
2468
                        fmx.setParentType(owner);
3✔
2469
                }
2470

2471
                if (fmx != null) {
2!
2472
                        setMethodModifiers(fmx, modifiers);
4✔
2473
                        // if it's a constructor
2474
                        if (fmx.getName().equals(Util.getOwner(fmx).getName())) {
7✔
2475
                                fmx.setKind(CONSTRUCTOR_KIND_MARKER);
3✔
2476
                        }
2477
                }
2478

2479
                if ((fmx != null) && delayedRetTyp) {
4!
2480
                        int retTypModifiers = (retTypBnd != null) ? retTypBnd.getModifiers() : UNKNOWN_MODIFIERS;
6!
2481
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
5!
2482
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13✔
2483
                }
2484

2485
                return fmx;
2✔
2486
        }
2487

2488
        /**
2489
         * Creates or recovers a stub Famix Method
2490
         * @param name of the method
2491
         * @return the Famix Method
2492
         */
2493
        public Method ensureFamixStubMethod(String name) {
UNCOV
2494
                return ensureFamixMethod(null, name, /*paramType*/(Collection<String>)null, /*returnType*/null, ensureFamixClassStubOwner(), /*modifiers*/0);  // cast needed to desambiguate the call
×
2495
        }
2496

2497
        public void setAttributeModifiers(Attribute fmx, int mod) {
2498
                setCommonModifiers(fmx, mod);
4✔
2499
                fmx.setIsTransient(Modifier.isTransient(mod));
5✔
2500
                fmx.setIsVolatile(Modifier.isVolatile(mod));
5✔
2501
        }
1✔
2502

2503
        public void setMethodModifiers(Method fmx, int mod) {
2504
                setCommonModifiers(fmx, mod);
4✔
2505
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2506
                fmx.setIsSynchronized(Modifier.isSynchronized(mod));
5✔
2507
        }
1✔
2508

2509
        public void setClassModifiers(Class fmx, int mod) {
2510
                setCommonModifiers(fmx, mod);
4✔
2511
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2512
        }
1✔
2513

2514
        public void setInterfaceModifiers(Interface fmx, int mod) {
2515
                setCommonModifiers(fmx, mod);
4✔
2516
        }
1✔
2517

2518
        private void setCommonModifiers(Entity fmx, int mod) {
2519
                setVisibility((THasVisibility)fmx, mod);
5✔
2520
                ((TCanBeClassSide)fmx).setIsClassSide(Modifier.isStatic(mod));
6✔
2521
                ((TCanBeFinal)fmx).setIsFinal(Modifier.isFinal(mod));
6✔
2522
        }
1✔
2523

2524
        /**
2525
         * Sets the visibility of a FamixNamedEntity
2526
         *
2527
         * @param fmx -- the FamixNamedEntity
2528
         * @param mod -- a description of the modifiers as understood by org.eclipse.jdt.core.dom.Modifier
2529
         */
2530
        public void setVisibility(THasVisibility fmx, int mod) {
2531
                if (Modifier.isPublic(mod)) {
3✔
2532
                        fmx.setVisibility(MODIFIER_PUBLIC);
4✔
2533
                } else if (Modifier.isPrivate(mod)) {
3✔
2534
                        fmx.setVisibility(MODIFIER_PRIVATE);
4✔
2535
                } else if (Modifier.isProtected(mod)) {
3✔
2536
                        fmx.setVisibility(MODIFIER_PROTECTED);
4✔
2537
                } else {
2538
                        fmx.setVisibility(MODIFIER_PACKAGE);
3✔
2539
                }
2540
        }
1✔
2541

2542
        /**
2543
         * Returns a Famix Attribute associated with the IVariableBinding.
2544
         * The Entity is created if it does not exist.<br>
2545
         * @param name -- the name of the FAMIX Attribute (MUST NOT be null, but this is not checked)
2546
         * @param type -- Famix Type of the Attribute (should not be null, but it will work if it is)
2547
         * @param owner -- type defining the Attribute (should not be null, but it will work if it is)
2548
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2549
         */
2550
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, Type type, TWithAttributes owner) {
2551
                Attribute fmx = null;
2✔
2552

2553
                // --------------- to avoid useless computations if we can
2554
                fmx = (Attribute)getEntityByKey(bnd);
5✔
2555
                if (fmx != null) {
2✔
2556
                        return fmx;
2✔
2557
                }
2558

2559
                // --------------- name
2560
                if (name == null) {
2!
UNCOV
2561
                        if (bnd == null) {
×
UNCOV
2562
                                return null;
×
2563
                        }
2564
                        else {
2565
                                name = bnd.getName();
×
2566
                        }
2567
                }
2568

2569
                // --------------- owner
2570
                if (owner == null) {
2✔
2571
                        if (bnd == null) {
2!
UNCOV
2572
                                return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
×
2573
                        }
2574
                        else {
2575
                                if (bnd.getDeclaringClass() != null && bnd.getDeclaringClass().getErasure() != null) {
7!
2576
                                        // Declaring class is the generic one if the class is parametric.
2577
                                        owner = (TWithAttributes)ensureFamixType(bnd.getDeclaringClass().getErasure());
8✔
2578
                                } else {
2579
                                        return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
2✔
2580
                                }
2581
                        }
2582
                }
2583

2584
                // --------------- recover from name ?
2585
                for (Attribute candidate : getEntityByName(Attribute.class, name)) {
13✔
2586
                        if (matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate)) {
8✔
2587
                                fmx = candidate;
2✔
2588
                                break;
1✔
2589
                        }
2590
                }
1✔
2591

2592
                if (fmx == null) {
2✔
2593
                        fmx = ensureFamixEntity(Attribute.class, bnd, name);
7✔
2594
                        fmx.setParentType( owner);
3✔
2595
                }
2596

2597
                if (fmx != null) {
2!
2598
                        fmx.setParentType((TWithAttributes) owner);
3✔
2599
                        ITypeBinding declaredTypeBinding = (bnd == null) ? null : bnd.getType();
7✔
2600
                        ensureFamixEntityTyping(declaredTypeBinding, fmx, type);
6✔
2601
                        if (bnd != null) {
2✔
2602
                                int mod = bnd.getModifiers();
3✔
2603
                                setAttributeModifiers(fmx, mod);
4✔
2604
                        }
2605
                }
2606

2607
                return fmx;
2✔
2608
        }
2609

2610
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2611
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2612
        }
2613

2614
        /**
2615
         * helper method, we know the var exists, ensureFamixAttribute will recover it
2616
         */
2617
        public Attribute getFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2618
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2619
        }
2620

2621
        /**
2622
         * Returns a Famix Parameter associated with the IVariableBinding.
2623
         * The Entity is created if it does not exist.<br>
2624
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2625
         */
2626
        public Parameter ensureFamixParameter(IVariableBinding bnd, String name, Type typ, TMethod tMethod) {
2627
                Parameter fmx = null;
2✔
2628

2629
                // --------------- to avoid useless computations if we can
2630
                try {
2631
                        fmx = (Parameter)getEntityByKey(bnd);
5✔
2632

UNCOV
2633
                }catch(Throwable e) {
×
UNCOV
2634
                        e.printStackTrace();
×
2635
                }
1✔
2636
                if (fmx != null) {
2✔
2637
                        return fmx;
2✔
2638
                }
2639

2640
                // --------------- name
2641
                if (name == null) {
2!
UNCOV
2642
                        if (bnd == null) {
×
UNCOV
2643
                                return null;
×
2644
                        }
2645
                        else {
2646
                                name = bnd.getName();
×
2647
                        }
2648
                }
2649

2650
                // --------------- owner
2651
                if (tMethod == null) {
2!
UNCOV
2652
                        if (bnd == null) {
×
UNCOV
2653
                                tMethod = ensureFamixStubMethod("<"+name+"_owner>");
×
2654
                        }
2655
                        else {
2656
                                tMethod = ensureFamixMethod(bnd.getDeclaringMethod());
×
2657
                        }
2658
                }
2659

2660
                // --------------- recover from name ?
2661
                for (Parameter candidate : getEntityByName(Parameter.class, name) ) {
13✔
2662
                        if ( matchAndMapVariable(bnd, name, tMethod, candidate) ) {
7!
UNCOV
2663
                                fmx = candidate;
×
UNCOV
2664
                                break;
×
2665
                        }
2666
                }
1✔
2667

2668
                if (fmx == null) {
2!
2669
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7✔
2670
                        fmx.setParentBehaviouralEntity(tMethod);
3✔
2671
                }
2672

2673
                if (fmx != null) {
2!
2674
                        fmx.setParentBehaviouralEntity(tMethod);
3✔
2675
                        ITypeBinding declaredTypeBnd = (bnd == null) ? null : bnd.getType();
5!
2676
                        ensureFamixEntityTyping(declaredTypeBnd, fmx, typ);
6✔
2677
                }
2678

2679
                return fmx;
2✔
2680
        }
2681

2682
        /**
2683
         * helper method, we know the var exists, ensureFamixParameter will recover it
2684
         */
2685
        public Parameter getFamixParameter(IVariableBinding bnd, String name, TMethod tMethod) {
UNCOV
2686
                return ensureFamixParameter(bnd, name, /*declared type*/null, tMethod);
×
2687
        }
2688

2689
        /**
2690
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2691
         * The Entity is created if it does not exist.<br>
2692
         * @param name -- the name of the FAMIX LocalVariable
2693
         * @return the Famix Entity found or created. May return null if <b>bnd</b> and <b>name</b> are null, or <b>bnd</b> and <b>owner</b> are null, or in case of a Famix error
2694
         */
2695
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2696
                LocalVariable fmx = null;
2✔
2697

2698
                // --------------- to avoid useless computations if we can
2699
                fmx = (LocalVariable)getEntityByKey(bnd);
5✔
2700
                if (fmx != null) {
2!
UNCOV
2701
                        return fmx;
×
2702
                }
2703

2704
                // --------------- name
2705
                if (name == null) {
2!
UNCOV
2706
                        if (bnd == null) {
×
UNCOV
2707
                                return null;
×
2708
                        }
2709
                        else {
2710
                                name = bnd.getName();
×
2711
                        }
2712
                }
2713

2714
                // --------------- owner
2715
                if (owner == null) {
2!
UNCOV
2716
                        if (bnd == null) {
×
UNCOV
2717
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2718
                        }
2719
                        else {
2720
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2721
                        }
2722
                }
2723

2724
                // --------------- recover from name ?
2725
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13✔
2726
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8!
UNCOV
2727
                                fmx = candidate;
×
UNCOV
2728
                                break;
×
2729
                        }
2730
                }
1✔
2731

2732
                if (fmx == null) {
2!
2733
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7✔
2734
                        fmx.setParentBehaviouralEntity(owner);
3✔
2735
                }
2736

2737
                if (fmx != null) {
2!
2738
                        // we just created it or it was not bound, so we make sure it has the right information in it
2739
                        fmx.setParentBehaviouralEntity(owner);
3✔
2740
                }
2741

2742
                return fmx;
2✔
2743
        }
2744

2745
        /**
2746
         * helper method, we know the var exists, ensureFamixLocalVariable will recover it
2747
         */
2748
        public LocalVariable getFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
UNCOV
2749
                return ensureFamixLocalVariable(bnd, name, owner);
×
2750
        }
2751

2752
        /**
2753
         * Returns a FAMIX ImplicitVariable with the given <b>name</b> ("self" or "super") and corresponding to the <b>type</b>.
2754
         * If this ImplicitVariable does not exist yet, it is created
2755
         * @param name -- the name of the FAMIX ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
2756
         * @param type -- the Famix Type for this ImplicitVariable (should not be null)
2757
         * @param tMethod -- the ContainerEntity where the implicit variable appears (should be a method inside <b>type</b>)
2758
         * @return the FAMIX ImplicitVariable or null in case of a FAMIX error
2759
         */
2760
        public ImplicitVariable ensureFamixImplicitVariable(IBinding key, String name, TType type, TMethod tMethod) {
2761
                ImplicitVariable fmx;
2762
                fmx = ensureFamixEntity(ImplicitVariable.class, key, name);
7✔
2763
                fmx.setParentBehaviouralEntity(tMethod);
3✔
2764
                return fmx;
2✔
2765
        }
2766

2767
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2768
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4✔
2769
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7✔
2770
        }
2771

2772
        /**
2773
         * Creates and returns a Famix Comment and associates it with an Entity (ex: for Javadocs)
2774
         * @param jCmt -- the content (String) of the comment 
2775
         * @param owner -- the entity that is commented
2776
         * @return the Famix Comment
2777
         */
2778
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner) {
2779
                Comment cmt = null;
2✔
2780

2781
                if ( (jCmt != null) && (owner != null) ) {
4!
2782
                        
2783
                        cmt = new Comment();
4✔
2784
                        addSourceAnchor(cmt, jCmt);
5✔
2785
                        famixRepoAdd(cmt);
3✔
2786
                        cmt.setCommentedEntity(owner);
3✔
2787
                }
2788

2789
                return cmt;
2✔
2790
        }
2791

2792
        /**
2793
         * Creates and returns a Famix Comment and associates it with an Entity
2794
         * @param jCmt -- the content (String) of the comment 
2795
         * @param owner -- the entity that is commented
2796
         * @param content -- the text of the comment
2797
         * @return the Famix Comment
2798
         */
2799
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner, String content) {
2800
                Comment cmt = null;
2✔
2801

2802
                if ( (jCmt != null) && (owner != null) ) {
4!
2803
                        cmt = new Comment();
4✔
2804
                        cmt.setContent(content );
3✔
2805
                        famixRepoAdd(cmt);
3✔
2806
                        cmt.setCommentedEntity(owner);
3✔
2807
                }
2808

2809
                return cmt;
2✔
2810
        }
2811

2812
        /**
2813
         * Adds location information to a Famix Entity.
2814
         * Location informations are: <b>name</b> of the source file and <b>line</b> position in this file. They are found in the JDT ASTNode: ast.
2815
         * This method also creates some basic links between the entity and others (e.g. declaring container, return type, ...)
2816
         * @param fmx -- Famix Entity to add the anchor to
2817
         * @param node -- JDT ASTNode, where the information is extracted
2818
         * @return the Famix SourceAnchor added to fmx. May be null in case of incorrect parameter ('fmx' or 'ast' == null)
2819
         */
2820
        public SourceAnchor addSourceAnchor(TSourceEntity fmx, ASTNode node) {
2821
                IndexedFileAnchor fa = null;
2✔
2822

2823
                fa = createIndexedFileAnchor(node);
4✔
2824
                if ((fmx != null) && (fa != null)) {
4!
2825
                        fmx.setSourceAnchor(fa);
3✔
2826
                        famixRepoAdd(fa);
3✔
2827
                }
2828

2829
                return fa;
2✔
2830
        }
2831

2832
        /**
2833
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2834
         */
2835
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2836
                IndexedFileAnchor fa = null;
2✔
2837

2838
                fa = createIndexedFileAnchor(node);
4✔
2839
                if ((fmx != null) && (fa != null)) {
4!
2840

2841
                        // may change the positions
2842
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4✔
2843
                        methodDeclarationModifiers.addAll(node.modifiers());
5✔
2844
                        if (node.getName() != null) {
3!
2845
                                methodDeclarationModifiers.add(node.getName());
5✔
2846
                        }
2847
                        if (node.getReturnType2() != null) {
3✔
2848
                                methodDeclarationModifiers.add(node.getReturnType2());
5✔
2849
                        }
2850
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12✔
2851
                        int end = node.getStartPosition() + node.getLength();
6✔
2852

2853
                        ((IndexedFileAnchor)fa).setStartPos(beg);
4✔
2854
                        ((IndexedFileAnchor)fa).setEndPos(end);
4✔
2855

2856
                        fmx.setSourceAnchor(fa);
3✔
2857
                        famixRepoAdd(fa);
3✔
2858
                }
2859

2860
                return fa;
2✔
2861
        }
2862

2863
        /**
2864
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2865
         * Information returned in the form of an IndexedFileAnchor
2866
         */
2867
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2868
                IndexedFileAnchor fa;
2869
                
2870
                if (node == null) {
2!
UNCOV
2871
                        return null;
×
2872
                }
2873

2874
                // position in source file
2875
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5✔
2876
                int end = beg + node.getLength() - 1;
7✔
2877

2878
                // find source Compilation Unit
2879
                // there is a special case for the JDT Comment Nodes
2880
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3✔
2881
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5✔
2882
                } else {
2883
                        node = node.getRoot();
3✔
2884
                }
2885

2886
                fa = new IndexedFileAnchor();
4✔
2887
                ((IndexedFileAnchor)fa).setStartPos(beg);
4✔
2888
                ((IndexedFileAnchor)fa).setEndPos(end);
4✔
2889

2890
                fa.setFileName((String) ((CompilationUnit)node).getProperty(SOURCE_FILENAME_PROPERTY));
7✔
2891

2892
                return fa;
2✔
2893
        }
2894

2895
        /**
2896
         * Creates or recovers the Famix Class for "Object".
2897
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2898
         *
2899
         * @param bnd -- a potential binding for the java "Object" class
2900
         * @return a Famix class for "Object"
2901
         */
2902
        public Class ensureFamixClassObject(ITypeBinding bnd) {
2903
                Class fmx = ensureFamixUniqEntity(Class.class, bnd, OBJECT_NAME);
7✔
2904

2905
                if (fmx != null) {
2!
2906
                        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5✔
2907
                }
2908
                // Note: "Object" has no superclass
2909

2910
                return fmx;
2✔
2911
        }
2912

2913
        /**
2914
         * Ensures the Java meta-class: <pre>{@code java.lang.Class<>}</pre>
2915
         */
2916
        public Class ensureFamixMetaClass(ITypeBinding bnd) {
2917
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2918
                ParametricClass fmx = (ParametricClass) this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, Modifier.PUBLIC & Modifier.FINAL);
9✔
2919

2920
                if (fmx != null) {
2!
2921
                        fmx.addTypeParameters(ensureFamixTypeParameter(null, "T", fmx));
7✔
2922
                }
2923

2924
                if ((fmx != null) && (fmx.getSuperInheritances() == null)) {
5!
UNCOV
2925
                        ensureFamixInheritance(ensureFamixClassObject(null), fmx, null, null);
×
2926
                }
2927

2928
                return fmx;
2✔
2929
        }
2930

2931
        public Class getFamixMetaClass(ITypeBinding bnd) {
2932
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2933
                return this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, UNKNOWN_MODIFIERS);
8✔
2934
        }
2935

2936
        /**
2937
         * Creates or recovers the Famix Class for all arrays (<pre>{@code <some-type> []}</pre>)
2938
         * In java arrays or objects of special classes (i.e. "I[" for an array of int).
2939
         * JDT does not create a binding for these classes, so we create a stub one here.
2940
         *
2941
         * @return a Famix class
2942
         */
2943
        public Class ensureFamixClassArray() {
UNCOV
2944
                Class fmx = ensureFamixUniqEntity(Class.class, null, ARRAYS_NAME);
×
UNCOV
2945
                if (fmx != null) {
×
UNCOV
2946
                        ensureFamixInheritance(ensureFamixClassObject(null), fmx, /*prev*/null, null);
×
UNCOV
2947
                        fmx.setTypeContainer(ensureFamixPackageDefault());
×
2948

2949
                        // may be not needed anymore now that we use modifiers
2950
                        /*fmx.setIsAbstract(Boolean.FALSE);
2951
                        fmx.setIsFinal(Boolean.FALSE);
2952
                        fmx.setIsInterface(Boolean.FALSE); 
2953
                        fmx.setIsPrivate(Boolean.FALSE);
2954
                        fmx.setIsProtected(Boolean.FALSE);*/
UNCOV
2955
                        fmx.setVisibility(MODIFIER_PUBLIC);
×
2956
                }
2957

UNCOV
2958
                return fmx;
×
2959
        }
2960

2961
        public String removeLastPartOfPackageName(String qualifiedName) {
2962
                String ret = null;
2✔
2963
                int last = qualifiedName.lastIndexOf('.');
4✔
2964
                if (last > 0) {
2✔
2965
                        // recursively creating the parent
2966
                        ret = qualifiedName.substring(0, last);
6✔
2967
                }
2968
                else {
2969
                        ret = "";
2✔
2970
                }
2971

2972
                return ret;
2✔
2973
        }
2974

2975
        /** Generates the list of parameters for a method signature
2976
         * @return a string
2977
         */
2978
        protected String signatureParamsFromBinding(IMethodBinding bnd) {
2979
                boolean first = true;
2✔
2980
                String sig = new String();
4✔
2981

2982
                for (ITypeBinding parBnd : bnd.getParameterTypes()) {
17✔
2983
                        if (first) {
2✔
2984
                                sig = parBnd.getName();
3✔
2985
                                first = false;
3✔
2986
                        }
2987
                        else {
2988
                                sig += "," + parBnd.getName();
5✔
2989
                        }
2990
                }
2991
                return sig;
2✔
2992
        }
2993

2994
        private String signatureParamsFromStringCollection(Collection<String> paramTypes) {
2995
                boolean first = true;
2✔
2996
                String sig = new String();
4✔
2997

2998
                for (String t : paramTypes) {
10✔
2999
                        if (first) {
2✔
3000
                                sig = t;
2✔
3001
                                first = false;
3✔
3002
                        }
3003
                        else {
3004
                                sig += "," + t;
4✔
3005
                        }
3006
                }
1✔
3007
                return sig;
2✔
3008
        }
3009

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