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

moosetechnology / VerveineJ / 38410216745

13 Oct 2026 02:04PM UTC coverage: 53.18% (+0.2%) from 52.984%
38410216745

push

github

web-flow
Merge pull request #282 from moosetechnology/244-upgrade-famejava-1.0.6

Upgrade FameJava to 1.0.6

2067 of 4060 branches covered (50.91%)

Branch coverage included in aggregate %.

57 of 77 new or added lines in 7 files covered. (74.03%)

3 existing lines in 1 file now uncovered.

4564 of 8409 relevant lines covered (54.28%)

2.24 hits per line

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

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

3
import java.util.*;
4
import java.util.logging.Level;
5
import java.util.logging.Logger;
6

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

54
import ch.akuhn.fame.Repository;
55
import fr.inria.verveine.extractor.java.utils.ImplicitVarBinding;
56
import fr.inria.verveine.extractor.java.utils.Util;
57

58
/**
59
 * A dictionary of FamixJava entities to help create them and find them back
60
 * Entities are mapped to keys which are the "binding" provided by the JDT pars
61
 * 
62
 * @author anquetil
63
 */
64
public class EntityDictionary {
65
        private static final Logger LOGGER = Logger.getLogger(EntityDictionary.class.getName());
5 ✔
66

67
        /**
68
         * A property added to CompilationUnits to record the name of the source file they belong to.
69
         * Used to create FileAnchors
70
         */
71
        public static final String SOURCE_FILENAME_PROPERTY = "verveine-source-filename";
72

73
        public static final String DEFAULT_PCKG_NAME = "<Default Package>";
74
        public static final String MISSING_PCKG_NAME= "<Missing Package>";
75
        public static final String STUB_METHOD_CONTAINER_NAME = "<StubMethodContainer>";
76
        public static final String THIS_NAME = "this";
77
        public static final String SUPER_NAME = "super";
78
        
79
        public static final String OBJECT_NAME = "Object";
80
        public static final String METACLASS_NAME = "Class";
81
        public static final String OBJECT_PACKAGE_NAME = "java.lang";
82
        public static final String ARRAYS_NAME = "default[]";
83
        public static final String INIT_BLOCK_NAME = "<Initializer>";
84
        public static final String ANONYMOUS_NAME_PREFIX = "_Anonymous";
85

86
        public static final int UNKNOWN_MODIFIERS = 0;
87
        public static final String MODIFIER_PUBLIC   = "public";
88
        public static final String MODIFIER_PRIVATE  = "private";
89
        public static final String MODIFIER_PROTECTED= "protected";
90
        public static final String MODIFIER_PACKAGE = "package";
91

92
    /**
93
     * The symbol kind to use to define that a method is a default implementation in an interface
94
     */
95
    public static final String DEFAULT_IMPLEMENTATION_KIND_MARKER = "default";
96

97
        /** name of the entity representing the "unknown" type 'var'
98
         * The entity is intended to be unique, see {@link #ensureFamixUniqEntity(java.lang.Class, IBinding , String )}
99
         */
100
        public static final String IMPLICIT_VAR_TYPE_NAME = "<ImplicitVarType>";
101

102
        /**
103
         * The FAMIX repository where all FAMIX entities are created and stored
104
         */
105
        protected Repository famixRepo;
106

107
        /**
108
         * A dictionary to map a key (provided by the user) to FAMIX Entity
109
         */
110
        protected Map<IBinding,TNamedEntity> keyToEntity;
111
        /**
112
         * A reverse dictionary (see {@link #keyToEntity}) to find the key of an entity.
113
         */
114
        protected Map<TNamedEntity,IBinding> entityToKey;
115

116
        /**
117
         * Another dictionary to map a name to FAMIX Entities with this name
118
         */
119
        protected Map<String,Collection<TNamedEntity>> nameToEntity;
120
        
121
        /**
122
         * Yet another dictionary for implicit variables ('self' and 'super')
123
         * Because they are implicit, they may not have a binding provided by the parser,
124
         * or may have the same binding as their associated type so they can't be kept easily in {@link #keyToEntity}
125
         */
126
        @Deprecated
127
        protected Map<Type,ImplicitVars> typeToImpVar;
128

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

146
        /**
147
         * Option: If true, create stubs without package into a "Missing" package
148
         */
149
        protected boolean useMissingPackage;
150

151
        /** Constructor taking a FAMIX repository
152
         * @param famixRepo
153
         */
154
        public EntityDictionary(Repository famixRepo) {
2 ✔
155
                        this.famixRepo = famixRepo;
3 ✔
156
                        
157
                        this.keyToEntity = new Hashtable<IBinding,TNamedEntity>();
5 ✔
158
                        this.entityToKey = new Hashtable<TNamedEntity,IBinding>();
5 ✔
159
                        this.nameToEntity = new Hashtable<String,Collection<TNamedEntity>>();
5 ✔
160
                        this.typeToImpVar = new Hashtable<Type,ImplicitVars>();
5 ✔
161
                        
162
                        if (! this.famixRepo.isEmpty()) {
4 ✔
163
                                recoverExistingRepository();
2 ✔
164
                        }
165
                }
1 ✔
166
        
167
        /** Constructor taking a FAMIX repository and the useMissingPackage option
168
         * @param famixRepo
169
         * @param useMissingPackage
170
         */
171
        public EntityDictionary(Repository famixRepo, boolean useMissingPackage) {
2 ✔
172
                        this.famixRepo = famixRepo;
3 ✔
173
                        this.useMissingPackage = useMissingPackage;
3 ✔
174
                        
175
                        this.keyToEntity = new Hashtable<IBinding,TNamedEntity>();
5 ✔
176
                        this.entityToKey = new Hashtable<TNamedEntity,IBinding>();
5 ✔
177
                        this.nameToEntity = new Hashtable<String,Collection<TNamedEntity>>();
5 ✔
178
                        this.typeToImpVar = new Hashtable<Type,ImplicitVars>();
5 ✔
179
                        
180
                        if (! this.famixRepo.isEmpty()) {
4 ✔
181
                                recoverExistingRepository();
2 ✔
182
                        }
183
                }
1 ✔
184

185
    /**
186
         * Resets the dictionnary in a proper state after loading entities from an existing MSE file:
187
         * <UL>
188
         * <li>map all named entities to their names in <b>mapName</b></li>
189
         * <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>
190
         * </ul>
191
         */
192
        protected void recoverExistingRepository() {
193
                for (NamedEntity ent : famixRepo.all(NamedEntity.class)) {
13 ✔
194
                        try {
195
                                mapEntityToName(ent.getName(), ent);
5 ✔
196
                        } catch (java.lang.Exception e) {
×
NEW
197
                                LOGGER.log(Level.WARNING, "Error recovering entity " + ent.getName() + " from repository " + famixRepo, e);
×
198
                        };
1 ✔
199
                        // for the Exception to be raised, the return value must be tested
200
                        try { if (((TCanBeStub) ent).getIsStub()) {} }
5 ✔
201
                        catch (NullPointerException e) { ((TCanBeStub)ent).setIsStub(Boolean.FALSE); }
6 ✔
202
                }
1 ✔
203

204
                for (Access acc : famixRepo.all(Access.class)) {
13 ✔
205
                        // for the Exception to be raised, the return value must be tested
206
                        try { if (acc.getIsWrite()) {}        }
4 ✔
207
                        catch (NullPointerException e) { acc.setIsWrite(Boolean.FALSE); }
5 ✔
208
                }
1 ✔
209
        }
1 ✔
210

211
        protected void mapEntityToName(String name, TNamedEntity ent) {
212
                
213
                Collection<TNamedEntity> l_ent = nameToEntity.get(name);
6 ✔
214
                if (l_ent == null) {
2 ✔
215
                        l_ent = new LinkedList<>();
4 ✔
216
                }
217
                l_ent.add(ent);
4 ✔
218
                nameToEntity.put(name, l_ent);
6 ✔
219
        }
1 ✔
220

221
        public void removeEntity( NamedEntity ent) {
222
                IBinding key;
223
                key = entityToKey.get(ent);
6 ✔
224
                if (key != null) {
2 ✔
225
                        entityToKey.remove(ent);
5 ✔
226
                        keyToEntity.remove(key);
5 ✔
227
                }
228

229
                Collection<TNamedEntity> l_ent = nameToEntity.get(ent.getName());
7 ✔
230
                if (l_ent != null) {
2 ✔
231
                        l_ent.remove(ent);
4 ✔
232
                }
233

234
                famixRepo.getElements().remove(ent);
6 ✔
235
        }
1 ✔
236
        
237
        protected void mapEntityToKey(IBinding key, TNamedEntity ent) {
238
                TNamedEntity old = keyToEntity.get(key);
6 ✔
239
                if (old != null) {
2 ✔
240
                        entityToKey.remove(old);
5 ✔
241
                }
242
                keyToEntity.put(key, ent);
6 ✔
243
                entityToKey.put(ent, key);
6 ✔
244
        }
1 ✔
245
        
246
        /**
247
         * Returns all the Famix Entity with the given name and class 
248
         * @param fmxClass -- the subtype of Famix Entity we are looking for
249
         * @param name -- the name of the entity
250
         * @return the Collection of Famix Entities with the given name and class (possibly empty)
251
         */
252
        @SuppressWarnings("unchecked")
253
        public <T extends TNamedEntity> Collection<T> getEntityByName(java.lang.Class<T> fmxClass, String name) {
254
                Collection<T> ret = new LinkedList<T>();
4 ✔
255
                Collection<TNamedEntity> l_name = nameToEntity.get(name);
6 ✔
256
                
257
                if (l_name != null ) {
2 ✔
258
                        for (TNamedEntity obj : l_name) {
10 ✔
259
                                if (fmxClass.isInstance(obj)) {
4 ✔
260
                                        ret.add((T) obj);
4 ✔
261
                                }
262
                        }
1 ✔
263
                }
264

265
                return ret;
2 ✔
266
        }
267

268
        /**
269
         * Returns the Famix Entity associated to the given key.
270
         * <b>Note</b>: Be careful that ImplicitVariables share the same binding as their associated Class and cannot be retrieved with this method.
271
         * In such a case, this method will always retrieve the Class associated to the key.
272
         * To get an ImplicitVariable from the key, use {@link #getImplicitVariableByBinding(IBinding, String)}
273
         * @param key -- the key
274
         * @return the Famix Entity associated to the binding or null if not found
275
         */
276
        public TNamedEntity getEntityByKey(IBinding key) {
277
                if (key == null) {
2 ✔
278
                        return null;
2 ✔
279
                }
280
                else {
281
                        return keyToEntity.get(key);
6 ✔
282
                }
283
        }
284

285
        /**
286
         * Returns the Famix Entity associated to the given key if it is an instance of the given Famix class.
287
         * This avoids recovering a binding as another kind of entity than the one requested.
288
         * @param key -- the key
289
         * @param fmxClass -- the expected Famix class
290
         * @return the Famix Entity associated to the binding or null if not found or not an instance of <b>fmxClass</b>
291
         */
292
        protected <T extends TNamedEntity> T getEntityByKey(IBinding key, java.lang.Class<T> fmxClass) {
293
                TNamedEntity fmx = getEntityByKey(key);
4 ✔
294
                if (fmxClass.isInstance(fmx)) {
4 ✔
295
                        return fmxClass.cast(fmx);
5 ✔
296
                }
297
                return null;
2 ✔
298
        }
299

300
        /**
301
         * Returns the key associated to a Famix Entity.
302
         * @param e -- the Named entity
303
         * @return the key associated to this entity or null if none
304
         */
305
        public IBinding getEntityKey(TNamedEntity e) {
306
                return entityToKey.get(e);
6 ✔
307
        }
308

309
        /**
310
         * Creates and returns a FAMIX Entity of the type <b>fmxjava.lang.Class</b>.
311
         * The Entity is always created.
312
         * @param fmxClass -- the FAMIX class of the instance to create
313
         * @param name -- the name of the new instance must not be null (and this is not tested)
314
         * @return the FAMIX Entity or null in case of a FAMIX error
315
         */
316
        protected <T extends TNamedEntity & TSourceEntity> T createFamixEntity(java.lang.Class<T> fmxClass, String name) {
317
                T fmx = null;
2 ✔
318

319
                if (name == null) {
2 !
320
                        return null;
×
321
                }
322
                
323
                try {
324
                        fmx = fmxClass.getDeclaredConstructor().newInstance();
9 ✔
325
                } catch (java.lang.Exception e) {
×
NEW
326
                        LOGGER.log(Level.WARNING, "Unexpected error, could not create a FAMIX entity", e);
×
327
                }
1 ✔
328
                
329
                if (fmx != null) {
2 !
330
                        fmx.setName(name);
3 ✔
331
                        if (fmx instanceof TCanBeStub) {
3 !
332
                                ((TCanBeStub)fmx).setIsStub(Boolean.TRUE);
4 ✔
333
                        }
334

335
                        mapEntityToName(name, fmx);
4 ✔
336
                        
337
                        // put new entity in Famix repository
338
                        famixRepoAdd((Entity) fmx);
4 ✔
339
                }
340

341
                return fmx;
2 ✔
342
        }
343
        
344
        /**
345
         * Returns a Famix Entity of the type <b>fmxjava.lang.Class</b> and maps it to its binding <b>bnd</b> (if not null).
346
         * The Entity is created if it did not exist.
347
         * @param fmxClass -- the Famix class of the instance to create
348
         * @param bnd -- the binding to map to the new instance
349
         * @param name -- the name of the new instance (used if <pre>{@code bnd == null}</pre>)
350
         * @return the Famix Entity or null if <b>bnd</b> was null or in case of a Famix error
351
         */
352
        @SuppressWarnings("unchecked")
353
        protected <T extends TNamedEntity & TSourceEntity> T ensureFamixEntity(java.lang.Class<T> fmxClass, IBinding bnd, String name) {
354
                T fmx = null;
2 ✔
355
                
356
                /* 
357
                 * Unfortunately different entities with the same name and same type may exist
358
                 * e.g. 2 parameters of 2 different methods but having the same name
359
                 * so we cannot recover just from the name
360
                 */
361

362
                if (bnd != null) {
2 ✔
363
                        fmx = getEntityByKey(bnd, fmxClass);
5 ✔
364
                        if (fmx != null) {
2 ✔
365
                                return fmx;
2 ✔
366
                        }
367
                }
368

369
                // else
370
                fmx = createFamixEntity(fmxClass, name);
5 ✔
371
                if ( (bnd != null) && (fmx != null) ) {
4 !
372
                        mapEntityToKey(bnd, fmx);
4 ✔
373
                }
374
                
375
                return fmx;
2 ✔
376
        }
377

378
        /**
379
         * Adds an already created Entity to the Famix repository
380
         * Used mainly for non-NamedEntity, for example relationships
381
         * @param e -- the Famix entity to add to the repository
382
         */
383
        public void famixRepoAdd(Entity e) {
384
                this.famixRepo.add(e);
4 ✔
385
        }
1 ✔
386

387

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

411
        /**
412
         * Returns a Famix ParametricInterface with the given <b>name</b>, creating it if it does not exist yet
413
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
414
         * @param name -- the name of the Famix Class
415
         * @return the Famix Class or null in case of a Famix error
416
         */
417
        public ParametricInterface ensureFamixParametricInterface(ITypeBinding key, String name, TWithTypes owner) {
418
                ParametricInterface fmx = ensureFamixEntity(ParametricInterface.class, key, name);
7 ✔
419
                if(key != null) {
2 !
420
                        for (ITypeBinding tp : key.getTypeParameters()) {
17 ✔
421
                                // If there is a type parameter, then fmx will be a Famix ParametricInterface
422
                                // note: in Famix, the owner of the TypeParameter is the ParametricInterface
423
                                TypeParameter fmxParam = ensureFamixTypeParameter(tp,
5 ✔
424
                                                tp.getName(), fmx);
2 ✔
425
                                fmxParam.setGenericEntity(fmx);
3 ✔
426
                fmxParam.setIsStub(false);
4 ✔
427
            }
428
                }
429
                fmx.setTypeContainer(owner);
3 ✔
430
                return fmx;
2 ✔
431
        }
432

433
        public AnnotationInstanceAttribute createFamixAnnotationInstanceAttribute(AnnotationTypeAttribute att, String value) {
434
                AnnotationInstanceAttribute fmx = null;
2 ✔
435
                if ( (att != null) && (value != null) ) {
4 !
436
                        fmx = new AnnotationInstanceAttribute();
4 ✔
437
                        fmx.setAnnotationTypeAttribute(att);
3 ✔
438
                        fmx.setValue(value);
3 ✔
439
                        this.famixRepo.add(fmx);
4 ✔
440
                }
441
                return fmx;
2 ✔
442
        }
443

444
        public AnnotationInstance addFamixAnnotationInstance(TWithAnnotationInstances fmx, AnnotationType annType, Collection<AnnotationInstanceAttribute> annAtts) {
445
                AnnotationInstance inst = null;
2 ✔
446
                if ( (fmx != null) && (annType != null) ) {
4 !
447
                        inst = new AnnotationInstance();
4 ✔
448
                        inst.setAnnotatedEntity(fmx);
3 ✔
449
                        inst.setAnnotationType(annType);
3 ✔
450
                        inst.addAttributes(annAtts);
3 ✔
451
                        this.famixRepo.add(inst);
4 ✔
452
                }
453
                return inst;
2 ✔
454
        }
455

456
        ///// ensure Famix Relationships /////
457

458
        /**
459
         * Returns a Famix Inheritance relationship between two Famix Classes creating it if needed
460
         * @param sup -- the super class
461
         * @param sub -- the sub class
462
         * @param prev -- previous inheritance relationship in the same context
463
         * @return the Inheritance relationship
464
         */
465
        public Inheritance ensureFamixInheritance(TWithInheritances sup, TWithInheritances sub, TAssociation prev, ITypeBinding supBnd) {
466
                if ( (sup == null) || (sub == null) ) {
4 !
467
                        return null;
×
468
                }
469

470
                // Does the inheritance already exist?
471
                for (TInheritance i : (sup).getSubInheritances()) {                        
11 ✔
472
                        if (i.getSubclass() == sub) {
4 ✔
473
                                return (Inheritance) i;
3 ✔
474
                        }
475
                }
1 ✔
476

477
                Inheritance inh;
478
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5 ✔
479
                        inh = (ParametricInheritance)buildFamixParametricAssociation(new ParametricInheritance(), supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
13 ✔
480
                } else {
481
                        inh = new Inheritance();
4 ✔
482
                }
483

484
                inh.setSuperclass(sup);
3 ✔
485
                inh.setSubclass(sub);
3 ✔
486
                chainPrevNext(prev, inh);
4 ✔
487
                famixRepoAdd(inh);
3 ✔
488
                return inh;
2 ✔
489
        }
490
        
491
        /**
492
         * Creates the concretization between the type parameters of the generic entity that is target of an association 
493
         * and the concrete types that concretize them in this association.
494
         * @param association -- the association that must be linked to # or several concretizations
495
         * @param typeParameters -- the collection of type parameters declared in the generic entity
496
         * @param typeArguments -- the collection of concrete types linked to this association
497
         * @return the parametric association
498
         */
499
        public  <T extends TParametricEntity> TParametricAssociation buildFamixParametricAssociation(TParametricAssociation association, ITypeBinding[] typeParameters, ITypeBinding[] typeArguments
500
        ) {
501
                
502
                Iterator<ITypeBinding> genericIterator = Arrays.asList(typeParameters).iterator();
4 ✔
503
                Iterator<ITypeBinding> concreteIterator = Arrays.asList(typeArguments).iterator();
4 ✔
504

505
                while (concreteIterator.hasNext() && genericIterator.hasNext()) {
6 ✔
506
                        TTypeArgument typeArgument = (TTypeArgument)ensureFamixType(concreteIterator.next());
7 ✔
507
                        TypeParameter typeParameter = (TypeParameter)ensureFamixType(genericIterator.next());
7 ✔
508

509
                        Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5 ✔
510
                        association.addConcretization(concretization);
3 ✔
511
                }
1 ✔
512

513
                return association;
2 ✔
514
        }
515

516
        /**
517
         * Returns a Famix Concretization relationship between a Concrete Type and a ParameterType
518
         * @param typeArgument -- the concrete type
519
         * @param typeParameter -- the generic type parameter
520
         * @return the Concretization relationship
521
         */
522
        public Concretization ensureFamixConcretization(TTypeArgument typeArgument, TypeParameter typeParameter ) {
523
                if ( (typeArgument == null) || (typeParameter == null) ) {
4 !
524
                        return null;
×
525
                }
526

527
                Concretization concretization = new Concretization();
4 ✔
528
                concretization.setTypeArgument(typeArgument);
3 ✔
529
                concretization.setTypeParameter(typeParameter);
3 ✔
530

531
                famixRepoAdd(concretization);
3 ✔
532
                return concretization;
2 ✔
533
        }
534
        
535
                /**
536
         * Returns a Famix Implementation relationship between two Famix Classes creating it if needed
537
         * @param myInterface -- the implemented interface
538
         * @param implementingClass -- the implementing class
539
         * @param prev -- previous inheritance relationship in the same context
540
         * @return the Inheritance relationship
541
         */
542
        public Implementation ensureFamixImplementation(TImplementable myInterface, TCanImplement implementingClass, TAssociation prev, ITypeBinding supBnd) {
543
                if ( (myInterface == null) || (implementingClass == null) ) {
4 !
544
                        return null;
×
545
                }
546

547
                for (TImplementation imp : myInterface.getImplementations()) {
11 ✔
548
                        if (imp.getImplementingClass() == implementingClass) {
4 ✔
549
                                return (Implementation) imp;
3 ✔
550
                        }
551
                }
1 ✔
552
                
553
                Implementation implementation;
554
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5 !
555
                        implementation = new ParametricImplementation();
5 ✔
556
                } else {
557
                        implementation = new Implementation();
4 ✔
558
                }
559

560
                implementation.setImplementingClass(implementingClass);
3 ✔
561
                implementation.setMyInterface(myInterface);
3 ✔
562
                chainPrevNext(prev, implementation);
4 ✔
563
                famixRepoAdd(implementation);
3 ✔
564
                if (implementation instanceof ParametricImplementation) {
3 ✔
565
                        buildFamixParametricAssociation((ParametricImplementation) implementation,
6 ✔
566
                                        supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
4 ✔
567
                }
568
                return implementation;
2 ✔
569
        }
570

571
        public void ensureImplementedInterfaces(ITypeBinding bnd, TType fmx, TWithTypes owner, TAssociation lastAssociation) {
572
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17 ✔
573
                        Type superTyp;
574
                        if(intbnd.isClass()){
3 ✔
575
                                superTyp = this.ensureFamixInterface(intbnd, intbnd.getName(), null, intbnd.isGenericType() || intbnd.isParameterizedType() || intbnd.isRawType(), intbnd.getModifiers());
22 !
576
                        }else {
577
                                superTyp = this.ensureFamixType(intbnd);
4 ✔
578
                        }
579
                        
580
                        if (bnd.isInterface()) {
3 ✔
581
                                // in Java "subtyping" link between 2 interfaces is call inheritance 
582
                                lastAssociation = ensureFamixInheritance((TWithInheritances)superTyp, (TWithInheritances)fmx, lastAssociation, intbnd);
10 ✔
583
                        }
584
                        else {
585
                                lastAssociation = ensureFamixImplementation((TImplementable)superTyp, (TCanImplement)fmx, lastAssociation, intbnd);
9 ✔
586
                        }
587
                }
588
        }
1 ✔
589

590
        /**
591
         * Returns a Famix Reference between two Famix Entities creating it if needed.<br>
592
         * 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
593
         * @param src -- source of the reference
594
         * @param tgt -- target of the reference
595
         * @param prev -- previous reference relationship in the same context
596
         * @return the FamixReference
597
         */
598
        public Reference addFamixReference(Method src, TType tgt, TAssociation prev, ITypeBinding referredTypeBnd) {
599
                Reference ref = null;
2 ✔
600
                
601
                if ( (src == null) || (tgt == null) ) {
4 !
602
                        return null;
×
603
                }
604

605
                if (prev == null) {
2 ✔
606
                        for (TReference existingRef : src.getOutgoingReferences()) {
7 !
607
                                if (existingRef.getReferredEntity() == tgt) {
×
608
                                        return (Reference) existingRef;
×
609
                                }
610
                        }
×
611
                }
612

613
                if (referredTypeBnd != null) {
2 ✔
614
                        if (referredTypeBnd.isParameterizedType()) {
3 ✔
615
                                ref = (ParametricReference)buildFamixParametricAssociation(new ParametricReference(), referredTypeBnd.getErasure().getTypeParameters(), referredTypeBnd.getTypeArguments());
13 ✔
616
                        } else if (referredTypeBnd.isArray()) {
3 ✔
617
                                ref = new ParametricReference();
4 ✔
618
                        
619
                                TTypeArgument typeArgument  = (TTypeArgument)ensureFamixType(referredTypeBnd.getElementType());
6 ✔
620
                                TypeParameter typeParameter = (TypeParameter) ((TParametricEntity)tgt).getTypeParameters().iterator().next();
7 ✔
621

622
                                Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5 ✔
623
                                ((ParametricReference)ref).addConcretization(concretization);
4 ✔
624
                        }
625
                }
626

627
                if (ref == null){
2 ✔
628
                        ref = new Reference();
4 ✔
629
                }
630

631
                ref.setReferredEntity(tgt);
3 ✔
632
                ref.setReferencer(src);
3 ✔
633
                chainPrevNext(prev,ref);
4 ✔
634
                famixRepoAdd(ref);
3 ✔
635

636
                return ref;
2 ✔
637
        }
638

639
        /**
640
         * Returns a Famix Invocation between two Famix Entities creating it if needed
641
         * @param tMethod of the invocation
642
         * @param invoked -- method invoked
643
         * @param receiver of the invocation
644
         * @param signature -- i.e. actual invocation code
645
         * @param prev -- previous invocation relationship in the same context
646
         * @return the FamixInvocation
647
         */
648
        public Invocation addFamixInvocation(TMethod tMethod, TMethod invoked, TInvocationsReceiver receiver, String signature, TAssociation prev, IMethodBinding invokedBnd) {
649
                if ( (tMethod == null) || (invoked == null) ) {
4 !
650
                        return null;
×
651
                }
652
                Invocation invocation;
653
                if (invokedBnd != null && invokedBnd.isParameterizedMethod()) {
5 ✔
654
                        invocation = (ParametricInvocation)buildFamixParametricAssociation(new ParametricInvocation(), invokedBnd.getMethodDeclaration().getTypeParameters(), invokedBnd.getTypeArguments());
13 ✔
655
                } else if ( invokedBnd != null && isConstructorBinding(invokedBnd) && invokedBnd.getMethodDeclaration().getDeclaringClass().isGenericType()) {
11 ✔
656
                        invocation = (ParametricInvocation)buildFamixParametricAssociation(new ParametricInvocation(), invokedBnd.getMethodDeclaration().getDeclaringClass().getTypeParameters(), invokedBnd.getDeclaringClass().getTypeArguments());
15 ✔
657
                } else {
658
                        invocation = new Invocation();
4 ✔
659
                }
660

661
                invocation.setReceiver(receiver);
3 ✔
662
                invocation.setSender(tMethod);
3 ✔
663
                invocation.setSignature((signature == null) ? invoked.getSignature() : signature);
5 !
664
                invocation.addCandidates(invoked);
3 ✔
665
                chainPrevNext(prev,invocation);
4 ✔
666
                famixRepoAdd(invocation);
3 ✔
667
                
668
                return invocation;
2 ✔
669
        }
670

671
        /**
672
         * Returns a Famix Access between two Famix Entities creating it if needed
673
         * @param accessor -- the entity (presumably a method) accessing the attribute
674
         * @param var -- the variable accessed
675
         * @param isWrite -- whether this is an access for reading or writing in the variable
676
         * @param prev -- previous access relationship in the same context
677
         * @return the FamixAccess
678
         */
679
        public Access addFamixAccess(TWithAccesses accessor, TStructuralEntity var, boolean isWrite, TAssociation prev) {
680
                if ( (accessor == null) || (var == null) ) {
4 !
681
                        return null;
×
682
                }
683
                Access acc = new Access();
4 ✔
684
                acc.setAccessor(accessor);
3 ✔
685
                acc.addCandidates((TAccessible) var);
3 ✔
686
                acc.setIsWrite(isWrite);
4 ✔
687
                chainPrevNext(prev, acc);
4 ✔
688
                famixRepoAdd(acc);
3 ✔
689
                
690
                return acc;
2 ✔
691
        }
692

693
        protected void chainPrevNext(TAssociation prev, TAssociation next) {
694
                if (prev != null) {
2 ✔
695
                        next.setPrevious(prev);  // not yet implemented in importer
3 ✔
696
                }
697
        }
1 ✔
698
        
699
        /**
700
         * Returns a Famix DeclaredException between a method and an Exception that it declares to throw
701
         * @param meth -- the method throwing the exception
702
         * @param excep -- the exception declared to be thrown
703
         * @return the DeclaredException
704
         */
705
        public TThrowable createFamixDeclaredException(Method meth, TThrowable excep) {
706
                if ( (meth == null) || (excep == null) ) {
4 !
707
                        return null;
×
708
                }
709
                meth.getDeclaredExceptions().add(excep);
5 ✔
710
                return excep;
2 ✔
711
        }
712

713
        /**
714
         * Returns a Famix CaughtException between a method and an Exception that is caught
715
         * @param meth -- the method catching the exception
716
         * @param excep -- the exception caught
717
         * @return the CaughtException
718
         */
719
        public TThrowable createFamixCaughtException(Method meth, TThrowable excep) {
720
                if ( (meth == null) || (excep == null) ) {
4 !
721
                        return null;
×
722
                }
723
                meth.getCaughtExceptions().add(excep);
5 ✔
724
                return excep;
2 ✔
725
        }
726

727
        /**
728
         * Returns a Famix ThrownException between a method and an Exception that it (actually) throws.
729
         * Note: DeclaredException indicates that the method declares it can throw the exception,
730
         * here we state that the exception is actually thrown
731
         * @param meth -- the method throwing the exception
732
         * @param excep -- the exception thrown
733
         * @return the ThrownException
734
         */
735
        public TThrowable createFamixThrownException(Method meth, TThrowable excep) {
736
                if ( (meth == null) || (excep == null) ) {
4 !
737
                        return null;
×
738
                }
739
                meth.getThrownExceptions().add(excep);
5 ✔
740
                return excep;
2 ✔
741
        }
742

743

744
        /**
745
         * Returns a Famix EntityTyping between a typed entity and a type.
746
         * @param typedEntity -- the typed entity
747
         * @param declaredType -- the declared type
748
         * @return the FamixEntityTyping
749
         */
750
        public EntityTyping ensureFamixEntityTyping(ITypeBinding declaredTypeBnd, TTypedEntity typedEntity, TType declaredType) {
751
                if ( (typedEntity == null) || (declaredType == null) ) {
4 !
752
                        return null;
2 ✔
753
                }
754
                EntityTyping typing = null;
2 ✔
755
                
756
                if (declaredTypeBnd != null) {
2 ✔
757
                        if (declaredTypeBnd.isParameterizedType()) {
3 ✔
758
                                typing = (ParametricEntityTyping)buildFamixParametricAssociation(new ParametricEntityTyping(), declaredTypeBnd.getErasure().getTypeParameters(), declaredTypeBnd.getTypeArguments());
13 ✔
759
                        }else if (declaredTypeBnd.isArray()) {
3 ✔
760
                                typing = new ParametricEntityTyping();
4 ✔
761
                                
762
                                TTypeArgument typeArgument  = (TTypeArgument)ensureFamixType(declaredTypeBnd.getElementType());
6 ✔
763
                                TypeParameter typeParameter = (TypeParameter) ((ParametricClass)declaredType).getTypeParameters().iterator().next();
7 ✔
764

765
                                Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5 ✔
766
                                ((ParametricEntityTyping)typing).addConcretization(concretization);
4 ✔
767
                        }
768
                }
769

770
                // If we did not set a typing because not parameterized nor array, set a default one
771
                if (typing == null) {
2 ✔
772
                        typing = new EntityTyping();
4 ✔
773
                }
774
                
775
                typing.setTypedEntity(typedEntity);
3 ✔
776
                typing.setDeclaredType(declaredType);
3 ✔
777
                famixRepoAdd(typing);
3 ✔
778
                
779
                return typing;
2 ✔
780
        }
781

782

783
        ///// Special Case: ImplicitVariables /////
784

785
        /**
786
         * Returns the Famix ImplicitVariable associated to the given binding and name (self or super).
787
         * See also {@link #getEntityByKey(IBinding)}
788
         * @param bnd -- the binding
789
         * @return the Famix Entity associated to the binding or null if not found
790
         */
791
        @Deprecated
792
        public ImplicitVariable getImplicitVariableByBinding(IBinding bnd, String iv_name) {
793
                return getImplicitVariableByType((Class)getEntityByKey(bnd), iv_name);
×
794
        }
795
        
796
        /**
797
         * Returns the Famix ImplicitVariable associated to the given FamixType.
798
         * @param type -- the FamixType
799
         * @param name -- name of the ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
800
         * @return the Famix ImplicitVariable associated to the Type or null if not found
801
         */
802
        @Deprecated
803
        public ImplicitVariable getImplicitVariableByType(Type type, String name) {
804
                ImplicitVars iv = typeToImpVar.get(type);
×
805
                ImplicitVariable ret = null;
×
806
                
807
                if (iv == null) {
×
808
                        iv = new ImplicitVars();
×
809
                }
810
                
811
                if (name.equals(THIS_NAME)) {
×
812
                        ret = iv.self_iv;
×
813
                }
814
                else if (name.equals(SUPER_NAME)) {
×
815
                        ret = iv.super_iv;
×
816
                }
817

818
                return ret;
×
819
        }
820

821
        ///// Special Case: "Uniq" Entities /////
822

823
        /**
824
         * Creates or recovers a Famix Named Entity uniq for the given name.
825
         * For some specific entities we don't allow two of them with the same name.
826
         * This is the case e.g. for the default package, or the Java class "Object" and its package "java.lang".
827
         * @param fmxClass -- the Famix class of the instance to create
828
         * @param key -- a potential binding for the entity
829
         * @param name -- the name of the new instance (used if <pre>{@code bnd == null}</pre>)
830
         * @return the uniq Famix Entity for this binding and/or name
831
         */
832
        @SuppressWarnings("unchecked")
833
        public <T extends NamedEntity> T ensureFamixUniqEntity(java.lang.Class<T> fmxClass, IBinding key, String name) {
834
                T fmx = null;
2 ✔
835
                
836
                if (name == null) {
2 !
837
                        return null;
×
838
                }
839
                
840
                if (key != null) {
2 ✔
841
                        fmx = (T) getEntityByKey(key);
5 ✔
842
                }
843
                
844
                if (fmx == null) {
2 ✔
845
                        Collection<T> l = getEntityByName( fmxClass, name);
5 ✔
846
                        if (l.size() > 0) {
3 ✔
847
                                fmx = l.iterator().next();
6 ✔
848
                        }
849
                        else {
850
                                fmx = createFamixEntity(fmxClass, name);
6 ✔
851
                        }
852
                        
853
                        if (key != null) {
2 ✔
854
                                // may happen for example if the entity was first created without binding
855
                                // and we find a binding for it later
856
                                keyToEntity.put(key, fmx);
6 ✔
857
                        }
858
                }
859

860
                return fmx;
2 ✔
861
        }
862

863
        /**
864
         * Creates or recovers the Famix Class that will own all stub methods (for which the real owner is unknown)
865
         *
866
         * @return a Famix class
867
         */
868
        public Class ensureFamixClassStubOwner() {
869
                Class fmx =  ensureFamixUniqEntity(Class.class, null, STUB_METHOD_CONTAINER_NAME);
7 ✔
870
                if (fmx != null) {
2 !
871
                        /*if the option `useMissingPackage` is activated, we put all the stubs with unknown packages in a package `Missing*/
872
                        if(this.useMissingPackage) {
3 ✔
873
                                fmx.setTypeContainer(ensureFamixPackageMissing());
5 ✔
874
                        }
875
                        /*otherwise we put them in the default package*/
876
                        else {
877
                                fmx.setTypeContainer( ensureFamixPackageDefault());
4 ✔
878
                        }
879
                }
880
                ensureFamixInheritance(ensureFamixClassObject(), fmx, /*prev*/null, null);
8 ✔
881

882
                return fmx;
2 ✔
883
        }
884

885
        public Type searchTypeInContext(String name, TWithTypes ctxt) {
886
                if (ctxt == null) {
×
887
                        return null;
×
888
                }
889
                
890
                for (TType candidate : ctxt.getTypes()) {
×
891
                        if (candidate.getName().equals(name) ) {
×
892
                                return (Type) candidate;
×
893
                        }
894
                }
×
895
                
896
                return searchTypeInContext(name, Util.getOwner((TNamedEntity)ctxt));
×
897
        }
898

899
        /**
900
         * Returns a Famix Package associated with its IPackageBinding and/or fully qualified name.
901
         * The Entity is created if it does not exist.
902
         * We assume that Namespaces must be uniq for a given name
903
         * Also creates or recovers recusively it's parent namespaces.<br>
904
         * At least one of <b>bnd</b> and <b>name</b> must be non null.
905
         *
906
         * @param bnd  -- the JDT Binding that may be used as a uniq key to recover this namespace
907
         * @param name -- fully qualified name of the namespace (e.g. 'java.lang')
908
         * @return the Famix Namespace found or created. May return null in case of a Famix error
909
         */
910
        public Package ensureFamixPackage(IPackageBinding bnd, String name) {
911
                Package fmx;
912
                Package parent;
913

914
                if ((name == null) && (bnd != null)) {
4 !
915
                        name = bnd.getName();
3 ✔
916
                }
917

918
                if ((name == null) || name.equals("")) {
6 !
919
                        return ensureFamixPackageDefault();
3 ✔
920
                } else {
921
                        /* Note: Packages are created with their fully-qualified name to simplify recovering when we don't have a binding
922
                         * (for example when creating parent packages of a package we have a binding for).
923
                         * Because the preferred solution in Moose is to give their simple names to packages, they must be post-processed when
924
                         * all is said and done. */
925
                        fmx = ensureFamixUniqEntity(Package.class, bnd, name);
7 ✔
926
                        String parentName = removeLastPartOfPackageName(name);
4 ✔
927
                        if (parentName.length() > 0) {
3 ✔
928
                                parent = ensureFamixPackage(null, parentName);
5 ✔
929
                                // set the parentscope relationship
930
                                if ((parent != null) && (fmx != null) && (fmx.getParentPackage() == null)) {
7 !
931
                                        parent.addChildEntities(fmx);
3 ✔
932
                                }
933
                        }
934
                }
935

936
                return fmx;
2 ✔
937
        }
938

939
        /**
940
         * Creates or recovers a default Famix Package.
941
         * Because this package does not really exist, it has no binding.
942
         *
943
         * @return a Famix Namespace
944
         */
945
        public Package ensureFamixPackageDefault() {
946
        return ensureFamixUniqEntity(Package.class, null, DEFAULT_PCKG_NAME);
7 ✔
947
        }
948
        
949
        /**
950
         * Returns an artificial Package to contain stubs with an unknown package.
951
         * Always returns the same package. Create it lazily if not existing.
952
         * @return a Famix Namespace
953
         */
954
        public Package ensureFamixPackageMissing( ) {
955
                return ensureFamixUniqEntity(Package.class, null, MISSING_PCKG_NAME);
7 ✔
956
        }
957

958
        /**
959
         * Creates or recovers a Famix Package for the package of Java class "Object" (i.e. "java.lang").
960
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
961
         *
962
         * @param bnd -- a potential binding for the "java.lang" package
963
         * @return a Famix Namespace for "java.lang"
964
         */
965
        public Package ensureFamixPackageJavaLang(IPackageBinding bnd) {
966

967
        return this.ensureFamixPackage(bnd, OBJECT_PACKAGE_NAME);
5 ✔
968
        }
969

970
        /**
971
         * Returns the Package with {@link #DEFAULT_PCKG_NAME} or <code>null</code> if not found
972
         */
973
        public Package getFamixPackageDefault() {
974
                Collection<Package> l = getEntityByName(Package.class, DEFAULT_PCKG_NAME);
5 ✔
975
                if (l.size() > 0) {
3 !
976
                        return l.iterator().next();
5 ✔
977
                } else {
978
                        return null;
×
979
                }
980
        }
981

982
        /**
983
         * Returns a Famix Type with the given <b>name</b>, creating it if it does not exist yet.
984
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
985
         * @param bnd -- binding for the type to create
986
         * @param name of the type
987
         * @param owner of the type
988
         * @param ctxt -- context of use of the type
989
         */
990
        public Type ensureFamixType(ITypeBinding bnd, String name, TWithTypes owner, TWithTypes ctxt, int modifiers) {
991
                
992
                Type fmx;
993

994
                if (bnd == null) {
2 !
995
                        if (name == null) {
×
996
                                return null;
×
997
                        }
998
                        fmx = searchTypeInContext(name, ctxt); // WildCard Types don't have binding
×
999
                        if (fmx != null) {
×
1000
                                return fmx;
×
1001
                        }
1002

1003
                        if ((owner instanceof TParametricEntity)) {
×
1004
                                return this.ensureFamixTypeParameter(null, name, owner);
×
1005
                        }
1006
                        else {
1007
                                fmx = ensureFamixEntity(Type.class, bnd, name);
×
1008
                                fmx.setTypeContainer(owner);
×
1009
                                return fmx;
×
1010
                        }
1011
                }
1012

1013
                // bnd != null
1014

1015
                fmx = (Type) getEntityByKey(bnd);
5 ✔
1016
                if (fmx != null) {
2 ✔
1017
                        return fmx;
2 ✔
1018
                }
1019

1020
                if (bnd.isArray()) {
3 !
1021
                        bnd = bnd.getElementType();
×
1022
                }
1023

1024
                if (bnd.isPrimitive()) {
3 ✔
1025
                        return this.ensureFamixPrimitiveType(bnd, name);
5 ✔
1026
                }
1027

1028
                if (bnd.isEnum()) {
3 !
1029
                        return this.ensureFamixEnum(bnd, name, owner);
×
1030
                }
1031
 
1032
                if ((bnd.isRawType() || bnd.isGenericType()) && !bnd.isInterface() ) {
9 ✔
1033
                        return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
10 ✔
1034
                }
1035

1036
                if (bnd.isCapture()) {
3 ✔
1037
                        if (bnd.getErasure().isInterface()) {
4 !
1038
                                return this.ensureFamixInterface(bnd.getErasure(), name, owner, /*isGeneric*/true, modifiers);
9 ✔
1039
                        }
1040
                        else {
1041
                                return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
×
1042
                        }
1043
                }
1044

1045
                if (bnd.isAnnotation()) {
3 ✔
1046
                        return this.ensureFamixAnnotationType(bnd, name, (ContainerEntity) owner);
7 ✔
1047
                }
1048

1049
                if (bnd.isInterface()) {
3 ✔
1050
                        return this.ensureFamixInterface(bnd, name, owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
19 ✔
1051
                }
1052

1053
                if (isThrowable(bnd)) {
4 ✔
1054
                        return this.ensureFamixException(bnd, name, owner, /*isGeneric*/false, modifiers);
8 ✔
1055
                }
1056
                if (bnd.isClass()) {
3 ✔
1057
                        return this.ensureFamixClass(bnd, name, (TNamedEntity) owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
20 !
1058
                }
1059
                if(bnd.isWildcardType()) {
3 ✔
1060
                        return this.ensureFamixWildcardType(bnd, name, (TParametricEntity)owner, ctxt);
8 ✔
1061
                }
1062

1063
                //otherwise (none of the above)
1064

1065
                if (name == null) {
2 ✔
1066
                        name = bnd.getName();
3 ✔
1067
                }
1068

1069
                if (owner == null) {
2 !
1070
                        owner = (TWithTypes) this.ensureOwner(bnd);
5 ✔
1071
                }
1072

1073
                if (bnd.isTypeVariable() ) {
3 !
1074
                        fmx = ensureFamixTypeParameter(bnd, name, owner);
6 ✔
1075
                        return fmx;
2 ✔
1076
                }
1077

1078
                fmx = ensureFamixEntity(Type.class, bnd, name);
×
1079
                fmx.setTypeContainer(owner);
×
1080
                return fmx;
×
1081
        }
1082

1083
        public Type ensureFamixType(ITypeBinding bnd, TWithTypes context) {
1084
        int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
6 !
1085
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8 ✔
1086
        }
1087
        
1088
        public Type ensureFamixType(ITypeBinding bnd) {
1089
                return ensureFamixType(bnd, /*ctxt*/null);
5 ✔
1090
        }
1091

1092
        public boolean isThrowable(ITypeBinding bnd) {
1093
                if (bnd == null) {
2 !
1094
                        return false;
×
1095
                }
1096
                if (bnd.getQualifiedName().equals("java.lang.Throwable")) {
5 ✔
1097
                        return true;
2 ✔
1098
                } else if (bnd.getQualifiedName().equals("java.lang.Object")) {
5 ✔
1099
                        return false;
2 ✔
1100
                }
1101
                else {
1102
                        return isThrowable(bnd.getSuperclass());
5 ✔
1103
                }
1104
        }
1105

1106
        /**
1107
         * Returns a Famix Class associated with the ITypeBinding.
1108
         * The Entity is created if it does not exist.
1109
         * @param name -- the name of the Famix Class (MUST NOT be null, but this is not checked)
1110
         * @param owner -- package defining the class (should not be null, but it will work if it is)
1111
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1112
         */
1113
        @SuppressWarnings("deprecation")
1114
        public Class ensureFamixClass(ITypeBinding bnd, String name, TNamedEntity owner, boolean isGeneric, int modifiers) {
1115
                Class fmx;
1116

1117
                // --------------- some special cases
1118
                if (bnd != null) {
2 ✔
1119
                        if (bnd.isArray()) {
3 !
1120
                                bnd = bnd.getElementType();
×
1121
                        }
1122

1123
                        // for inner classes defined in generics !!! For others should not change anything
1124
                        bnd = bnd.getErasure();
3 ✔
1125
                }
1126

1127
                // ---------------- to avoid useless computations if we can
1128
                fmx = getEntityByKey(bnd, Class.class);
6 ✔
1129
                if (fmx != null) {
2 ✔
1130
                        return fmx;
2 ✔
1131
                }
1132

1133
                // --------------- name
1134
                if (name == null) {
2 ✔
1135
                        if (bnd == null) {
2 !
1136
                                return null;  // not much we can do
×
1137
                        } else if (!bnd.isAnonymous()) {
3 !
1138
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5 ✔
1139
                        } else { // anonymous class
1140
                                if (bnd.getSuperclass() != null) {
×
1141
                                        name = bnd.getSuperclass().getName();
×
1142
                                }
1143
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1144
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1145
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1146
                                                name = bnd.getInterfaces()[0].getName();
×
1147
                                        }
1148
                                        else {
1149
                                                name = "???";
×
1150
                                        }
1151
                                }
1152
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1153
                        }
1154
                }
1155

1156
        // If we have java.lang.Object we should ensure we create this class
1157
        if (bnd != null && bnd.getQualifiedName().equals("java.lang.Object")) {
7 ✔
1158
                        return ensureFamixClassObject();
3 ✔
1159
                }
1160

1161
                // --------------- owner
1162
                if (owner == null) {
2 ✔
1163
                        if (bnd != null) {
2 ✔
1164
                                owner = ensureOwner(bnd);
4 ✔
1165
                        }
1166
                        /*                                owner = ensureFamixPackageDefault();
1167
                        } else {*/
1168
                }
1169

1170
                // --------------- recover from name ?
1171
                if (owner != null) {
2 ✔
1172
                        for (Class candidate : this.getEntityByName(Class.class, name)) {
13 ✔
1173
                                if (matchAndMapClass(bnd, name, owner, candidate)) {
7 ✔
1174
                                        fmx = candidate;
2 ✔
1175
                                        break;
1 ✔
1176
                                }
1177
                        }
1 ✔
1178
                }
1179

1180
                // ---------------- create
1181
                if (fmx == null) {
2 ✔
1182
                        if (isGeneric) {
2 ✔
1183
                                fmx = ensureFamixParametricClass(bnd, name, (TWithTypes) owner);
8 ✔
1184
                        }
1185
                        else {
1186
                                fmx = ensureFamixEntity(Class.class, bnd, name);
7 ✔
1187
                                fmx.setTypeContainer((TWithTypes)owner);
4 ✔
1188
                        }
1189
                }
1190

1191
                // ---------------- modifiers and super-classes
1192
                if (fmx!=null) {
2 !
1193
                        // we just created it, or it was not bound so we make sure it has the right information in it
1194
                        if (bnd != null) {
2 ✔
1195
                                setClassModifiers(fmx, bnd.getDeclaredModifiers(), (TWithTypes) owner);
7 ✔
1196
                        }
1197

1198
                        TAssociation lastAssoc = null;
2 ✔
1199

1200
                        if (bnd != null) {
2 ✔
1201
                                ITypeBinding supbnd = bnd.getSuperclass();
3 ✔
1202
                                if (supbnd != null) {
2 ✔
1203
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11 ✔
1204
                                }
1205
                                else {
1206
                                        lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
8 ✔
1207
                                }
1208
                                ensureImplementedInterfaces(bnd, fmx, (TWithTypes) owner, lastAssoc);
7 ✔
1209
                        }
1210
                }
1211

1212
                return fmx;
2 ✔
1213
        }
1214

1215
        /**
1216
         * Returns a Famix Exception associated with the ITypeBinding.
1217
         * The Entity is created if it does not exist.
1218
         * @param name -- the name of the Famix Exception
1219
         * @param owner -- type defining the Exception (should not be null, but it will work if it is) 
1220
         *
1221
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1222
         */
1223
        public <T extends TWithTypes & TNamedEntity> Exception ensureFamixException(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1224
                Exception fmx;
1225

1226
                // --------------- some special cases
1227
                if (bnd != null) {
2 ✔
1228
                        if (bnd.isArray()) {
3 !
1229
                                bnd = bnd.getElementType();
×
1230
                        }
1231

1232
                        // for inner classes defined in generics !!! For others should not change anything
1233
                        bnd = bnd.getErasure();
3 ✔
1234
                }
1235

1236
                // ---------------- to avoid useless computations if we can
1237
                fmx = (Exception) getEntityByKey(bnd);
5 ✔
1238
                if (fmx != null) {
2 ✔
1239
                        return fmx;
2 ✔
1240
                }
1241

1242
                // --------------- name
1243
                if (name == null) {
2 ✔
1244
                        if (bnd == null) {
2 !
1245
                                return null;  // not much we can do
×
1246
                        } else if (!bnd.isAnonymous()) {
3 !
1247
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5 ✔
1248
                        } else { // anonymous class
1249
                                if (bnd.getSuperclass() != null) {
×
1250
                                        name = bnd.getSuperclass().getName();
×
1251
                                }
1252
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1253
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1254
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1255
                                                name = bnd.getInterfaces()[0].getName();
×
1256
                                        }
1257
                                        else {
1258
                                                name = "???";
×
1259
                                        }
1260
                                }
1261
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1262
                        }
1263
                }
1264

1265
                // --------------- owner
1266
                if (owner == null) {
2 ✔
1267
                        if (bnd == null) {
2 ✔
1268
                                owner = ensureFamixPackageDefault();
4 ✔
1269
                        } else {
1270
                                owner = (TWithTypes) ensureOwner(bnd);
5 ✔
1271
                        }
1272
                }
1273

1274
                // --------------- recover from name ?
1275
                for (Exception candidate : this.getEntityByName(Exception.class, name)) {
13 ✔
1276
                        if (matchAndMapClass(bnd, name, (T) owner, candidate)) {
8 !
1277
                                fmx = candidate;
×
1278
                                break;
×
1279
                        }
1280
                }
1 ✔
1281

1282
                // ---------------- create
1283
                if (fmx == null) {
2 !
1284
                        fmx = ensureFamixEntity(Exception.class, bnd, name);
7 ✔
1285
                        fmx.setTypeContainer(owner);
3 ✔
1286
                }
1287

1288
        // we just created it or it was not bound, so we make sure it has the right information in it
1289
        TAssociation lastAssoc = null;
2 ✔
1290
        if (bnd != null) {
2 ✔
1291
            ITypeBinding supbnd = bnd.getSuperclass();
3 ✔
1292
            if (supbnd != null) {
2 !
1293
                lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11 ✔
1294
            }
1295
            else {
1296
                lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
×
1297
            }
1298
            ensureImplementedInterfaces(bnd, fmx, owner, lastAssoc);
6 ✔
1299
        }
1300

1301
        return fmx;
2 ✔
1302
        }
1303

1304
        /**
1305
         * Returns a FAMIX Interface with the given <b>name</b>, creating it if it does not exist yet.
1306
         * @param name -- the name of the FAMIX Method
1307
         * @param owner -- type defining the method (should not be null, but it will work if it is) 
1308
         * @return the FAMIX Class or null in case of a FAMIX error
1309
         */
1310
        public <T extends TWithTypes & TNamedEntity> Interface ensureFamixInterface(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1311
                Interface fmx;
1312

1313
                // --------------- some special cases
1314
                if (bnd != null) {
2 !
1315
                        if (bnd.isArray()) {
3 !
1316
                                bnd = bnd.getElementType();
×
1317
                        }
1318

1319
                        // for inner classes defined in generics !!! For others should not change anything
1320
                        bnd = bnd.getErasure();
3 ✔
1321
                }
1322

1323
                // ---------------- to avoid useless computations if we can
1324
                fmx = getEntityByKey(bnd, Interface.class);
6 ✔
1325
                if (fmx != null) {
2 ✔
1326
                        return fmx;
2 ✔
1327
                }
1328

1329
                // --------------- name
1330
                if (name == null) {
2 ✔
1331
                        if (bnd == null) {
2 !
1332
                                return null;  // not much we can do
×
1333
                        } else if (!bnd.isAnonymous()) {
3 !
1334
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5 ✔
1335
                        } else { // anonymous class
1336
                                if (bnd.getSuperclass() != null) {
×
1337
                                        name = bnd.getSuperclass().getName();
×
1338
                                }
1339
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1340
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1341
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1342
                                                name = bnd.getInterfaces()[0].getName();
×
1343
                                        }
1344
                                        else {
1345
                                                name = "???";
×
1346
                                        }
1347
                                }
1348
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1349
                        }
1350
                }
1351

1352
                // --------------- owner
1353
                if (owner == null) {
2 ✔
1354
                        if (bnd == null) {
2 !
1355
                                owner = ensureFamixPackageDefault();
×
1356
                        } else {
1357
                                owner = (TWithTypes) ensureOwner(bnd);
5 ✔
1358
                        }
1359
                }
1360

1361
                // --------------- recover from name ?
1362
                for (Interface candidate : this.getEntityByName(Interface.class, name)) {
13 ✔
1363
                        if (matchAndMapInterface(bnd, name, (T) owner, candidate)) {
8 ✔
1364
                                fmx = candidate;
2 ✔
1365
                                break;
1 ✔
1366
                        }
1367
                }
1 ✔
1368

1369
                // ---------------- create
1370
                if (fmx == null) {
2 ✔
1371
                        if (isGeneric) {
2 ✔
1372
                                fmx = ensureFamixParametricInterface(bnd, name, owner);
7 ✔
1373
                        }
1374
                        else {
1375
                                fmx = ensureFamixEntity(Interface.class, bnd, name);
7 ✔
1376
                                fmx.setTypeContainer(owner);
3 ✔
1377
                        }
1378
                }
1379

1380
                // ---------------- modifiers and "super interfaces"
1381
                if (fmx!=null) {
2 !
1382
                        // we just created it or it was not bound, so we make sure it has the right information in it
1383
                        if (bnd != null) {
2 !
1384
                                setInterfaceModifiers(fmx, bnd.getModifiers());
5 ✔
1385
                        }
1386
                        TAssociation lastAssociation = null;
2 ✔
1387
                        if (bnd != null) {
2 !
1388
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssociation);
6 ✔
1389
                        }
1390
                }
1391
                return fmx;
2 ✔
1392
        }
1393

1394
        /**
1395
         * "Converts" (if needed) a TTYpe entity to be a TThrowable. Might involve removing the existing entity, recreating a new one and migrating
1396
         * all the relationship of the former to the later
1397
         */
1398
        public TThrowable asException(TType fmxType) {
1399
                if (fmxType instanceof Exception) {
3 ✔
1400
                        return (Exception) fmxType;
3 ✔
1401
                }
1402
                if(fmxType instanceof TypeParameter) {
3 ✔
1403
                        return (TypeParameter) fmxType;
3 ✔
1404
                }
1405

1406
                Exception fmxException = null;
2 ✔
1407
                IBinding key;
1408

1409
                try {
1410
                        key = entityToKey.get(fmxType);
6 ✔
1411

1412
                        /* Remove entity immediately so that its key and name are not "reassigned" in the various cache dictionaries
1413
                         * the object still exists and its properties are still accessible */
1414
                        removeEntity((NamedEntity) fmxType);
4 ✔
1415

1416
                        TWithTypes owner = fmxType.getTypeContainer();
3 ✔
1417
                        fmxType.setTypeContainer(null);
3 ✔
1418
                        fmxException = ensureFamixException((ITypeBinding) key, fmxType.getName(), owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
10 ✔
1419

1420
                        fmxException.addMethods( new ArrayList<>( ((TWithMethods)fmxType).getMethods() ) );
8 ✔
1421
                        if (fmxType instanceof TWithAttributes) {
3 !
1422
                                fmxException.addAttributes( new ArrayList<>( ((TWithAttributes)fmxType).getAttributes() ) );
8 ✔
1423
                        }
1424

1425
                        if (fmxType instanceof TWithInheritances) {
3 !
1426
                                fmxException.addSuperInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSuperInheritances() ) );
8 ✔
1427
                                fmxException.addSubInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSubInheritances() ) );
8 ✔
1428
                        }
1429
                        fmxException.setComments(new ArrayList<>( ((TWithComments) fmxType).getComments() ));
8 ✔
1430
                        fmxException.setSourceAnchor(fmxType.getSourceAnchor());
4 ✔
1431
                        fmxException.addIncomingTypings( new ArrayList<>( fmxType.getIncomingTypings() ) );
7 ✔
1432
                        fmxException.addAnnotationInstances( new ArrayList<>( ((NamedEntity)fmxType).getAnnotationInstances() ) );
8 ✔
1433
                        fmxException.addIncomingReferences( new ArrayList<>( fmxType.getIncomingReferences() ) );
7 ✔
1434
                        fmxException.setIsStub(fmxType.getIsStub());
4 ✔
1435
                        fmxException.addTypes( new ArrayList<>( ((ContainerEntity) fmxType).getTypes() ) );
8 ✔
1436
                }
1437
                catch( ConcurrentModificationException e) {
×
1438
                        e.printStackTrace();
×
1439
                }
1 ✔
1440

1441
                return fmxException;
2 ✔
1442
        }
1443

1444
        /**
1445
         * helper method, we know the type exists, ensureFamixClass will recover it
1446
         */
1447
        public Class getFamixClass(ITypeBinding bnd, String name, TNamedEntity owner) {
1448
                return ensureFamixClass(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8 ✔
1449
        }
1450

1451
        /**
1452
         * helper method, we know the type exists, ensureFamixInterface will recover it
1453
         */
1454
        public Interface getFamixInterface(ITypeBinding bnd, String name, ContainerEntity owner) {
1455
                return ensureFamixInterface(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8 ✔
1456
        }
1457

1458
        /**
1459
         * helper method, we know the type exists, ensureFamixInterface will recover it
1460
         */
1461
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1462
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8 ✔
1463
        }
1464

1465
        /**
1466
         * Ensures a famix entity for the owner of a binding.<br>
1467
         * This owner can be a method, a class or a namespace
1468
         * @param bnd -- binding for the owned entity
1469
         * @return a famix entity for the owner
1470
         */
1471
        private TNamedEntity ensureOwner(ITypeBinding bnd) {
1472
                TNamedEntity owner;
1473
                IMethodBinding parentMtd = bnd.getDeclaringMethod();
3 ✔
1474
                if (parentMtd != null) {
2 ✔
1475
                        owner = this.ensureFamixMethod(parentMtd);  // cast needed to desambiguate the call
5 ✔
1476
                }
1477
                else {
1478
                        ITypeBinding parentClass = bnd.getDeclaringClass();
3 ✔
1479
                        if (parentClass != null) {
2 ✔
1480
                owner = this.ensureFamixType(parentClass);
5 ✔
1481
            }
1482
                        else {
1483
                                IPackageBinding parentPckg = bnd.getPackage();
3 ✔
1484
                                if (parentPckg != null) {
2 !
1485
                                        owner = this.ensureFamixPackage(parentPckg, null);
6 ✔
1486
                                } else {
1487
                                        owner = this.ensureFamixPackageDefault();
×
1488
                                }
1489
                        }
1490
                }
1491
                return owner;
2 ✔
1492
        }
1493

1494

1495
        /**
1496
         * Returns a FAMIX PrimitiveType with the given <b>name</b>, creating it if it does not exist yet
1497
         * We assume that PrimitiveType must be uniq for a given name
1498
         * @param name -- the name of the FAMIX PrimitiveType
1499
         * @return the FAMIX PrimitiveType or null in case of a FAMIX error
1500
         */
1501
        public PrimitiveType ensureFamixPrimitiveType(ITypeBinding bnd, String name) {
1502
                if (name == null) {
2 ✔
1503
                        if (bnd == null) {
2 !
1504
                                return null;
×
1505
                        } else {
1506
                                name = bnd.getName();
3 ✔
1507
                        }
1508
                }
1509
                return ensureFamixUniqEntity(PrimitiveType.class, bnd, name);
7 ✔
1510
        }
1511

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

1515
                // --------------- to avoid useless computations if we can
1516
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5 ✔
1517
                if (fmx != null) {
2 ✔
1518
                        return fmx;
2 ✔
1519
                }
1520

1521
                // --------------- name
1522
                if (name == null) {
2 ✔
1523
                        if (bnd == null) {
2 !
1524
                                return null;
×
1525
                        }
1526
                        else {
1527
                                name = bnd.getName();
3 ✔
1528
                        }
1529
                }
1530

1531
                // --------------- owner
1532
                if (owner == null) {
2 ✔
1533
                        if (bnd == null) {
2 !
1534
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1535
                        } else {
1536
                                owner = (TWithTypes) ensureOwner(bnd);
5 ✔
1537
                        }
1538
                }
1539

1540
                // --------------- recover from name ?
1541
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9 !
1542
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
1543
                                fmx = candidate;
×
1544
                                break;
×
1545
                        }
1546
                }
×
1547

1548
                if (fmx == null) {
2 !
1549
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7 ✔
1550
                        fmx.setTypeContainer(owner);
3 ✔
1551
                }
1552

1553
                if (bnd != null) {
2 !
1554
                        setVisibility(fmx, bnd.getModifiers(), owner);
6 ✔
1555
                }
1556

1557
                return fmx;
2 ✔
1558
        }
1559

1560
        /**
1561
         * helper method, we know the type exists, ensureFamixEnum will recover it
1562
         */
1563
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1564
                return ensureFamixEnum(bnd, name, owner);
6 ✔
1565
        }
1566

1567
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1568
                EnumValue fmx;
1569

1570
                // --------------- to avoid useless computations if we can
1571
                fmx = (EnumValue)getEntityByKey(bnd);
5 ✔
1572
                if (fmx != null) {
2 ✔
1573
                        return fmx;
2 ✔
1574
                }
1575

1576
                // --------------- name
1577
                if (name == null) {
2 !
1578
                        if (bnd == null) {
×
1579
                                return null;
×
1580
                        }
1581
                        else {
1582
                                name = bnd.getName();
×
1583
                        }
1584
                }
1585

1586
                // --------------- owner
1587
                if (owner == null) {
2 ✔
1588
                        if (bnd == null) {
2 !
1589
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1590
                        }
1591
                        else {
1592
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7 ✔
1593
                        }
1594
                }
1595

1596
                // --------------- recover from name ?
1597
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9 !
1598
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
1599
                                fmx = candidate;
×
1600
                                break;
×
1601
                        }
1602
                }
×
1603
                if (fmx == null) {
2 !
1604
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7 ✔
1605
                        fmx.setParentEnum(owner);
3 ✔
1606
                }
1607

1608
        fmx.setParentEnum(owner);
3 ✔
1609

1610
        return fmx;
2 ✔
1611
        }
1612

1613
    /**
1614
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1615
         */
1616
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1617
                AnnotationType fmx;
1618

1619
                // --------------- to avoid useless computations if we can
1620
                fmx = (AnnotationType)getEntityByKey(bnd);
5 ✔
1621
                if (fmx != null) {
2 ✔
1622
                        return fmx;
2 ✔
1623
                }
1624

1625
                // --------------- name
1626
                if (name == null) {
2 ✔
1627
                        if (bnd == null) {
2 !
1628
                                return null;
×
1629
                        }
1630
                        else {
1631
                                name = bnd.getName();
3 ✔
1632
                        }
1633
                }
1634

1635
                // --------------- owner
1636
                if (owner == null) {
2 ✔
1637
                        if (bnd == null) {
2 !
1638
                                owner = ensureFamixPackageDefault();
×
1639
                        }
1640
                        else {
1641
                                IPackageBinding parentPckg = bnd.getPackage();
3 ✔
1642
                                if (parentPckg != null) {
2 !
1643
                                        owner = this.ensureFamixPackage(parentPckg, null);
6 ✔
1644
                                } else {
1645
                                        owner = this.ensureFamixPackageDefault();
×
1646
                                }
1647
                        }
1648
                }
1649

1650
                // --------------- recover from name ?
1651
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13 ✔
1652
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7 !
1653
                                fmx = candidate;
2 ✔
1654
                                break;
1 ✔
1655
                        }
1656
                }
×
1657

1658
                // --------------- create
1659
                if (fmx == null) {
2 ✔
1660
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7 ✔
1661
                        fmx.setAnnotationTypesContainer(owner);
3 ✔
1662
                }
1663

1664
                if (bnd != null) {
2 !
1665
                        // Not supported in Famix
1666

1667
                        // setVisibility(fmx, bnd.getModifiers());
1668
                }
1669

1670
                return fmx;
2 ✔
1671
        }
1672

1673
        /**
1674
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1675
         */
1676
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1677
                return ensureFamixAnnotationType(bnd, name, owner);
6 ✔
1678
        }
1679

1680
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1681
                AnnotationTypeAttribute fmx = null;
2 ✔
1682

1683
                // --------------- to avoid useless computations if we can
1684
                fmx = (AnnotationTypeAttribute)getEntityByKey(bnd);
5 ✔
1685
                if (fmx != null) {
2 ✔
1686
                        return fmx;
2 ✔
1687
                }
1688

1689
                // --------------- name
1690
                if (name == null) {
2 !
1691
                        if (bnd == null) {
×
1692
                                return null;
×
1693
                        }
1694
                        else {
1695
                                name = bnd.getName();
×
1696
                        }
1697
                }
1698

1699
                // --------------- owner
1700
                if (owner == null) {
2 !
1701
                        if (bnd == null) {
×
1702
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1703
                        }
1704
                        else {
1705
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
1706
                                if (parentType != null) {
×
1707
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1708
                                }
1709
                                else  {
1710
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1711
                                }
1712
                        }
1713
                }
1714

1715
                // --------------- recover from name ?
1716
                for (AnnotationTypeAttribute candidate : getEntityByName(AnnotationTypeAttribute.class, name) ) {
13 ✔
1717
                        // JDT treats annotation type attributes as methods ...
1718
                        // checkAndMapMethod wants a signature as 2nd argument so we add empty param list
1719
                        if ( (bnd != null) && matchAndMapMethod(bnd, name+"()", null, owner, candidate) ) {
11 !
1720
                                fmx = candidate;
×
1721
                                break;
×
1722
                        }
1723
                        // if the binding is null, the annotationTypeAttribute migth have been created
1724
                        else if ( (bnd == null) && matchAndMapVariable(null, name, owner, candidate)) {
2 !
1725
                                fmx = candidate;
×
1726
                                break;
×
1727
                        }
1728
                }
1 ✔
1729

1730
                if (fmx == null) {
2 !
1731
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7 ✔
1732
                        fmx.setParentType(owner);
3 ✔
1733
                }
1734

1735
                if (bnd != null) {
2 !
1736
                        // Not suopp
1737

1738
                        // setVisibility(fmx, bnd.getModifiers());
1739
                }
1740

1741
                return fmx;
2 ✔
1742
        }
1743

1744
        /**
1745
         * helper method, we know the attribute exists, ensureFamixAnnotationTypeAttribute will recover it
1746
         */
1747
        public AnnotationTypeAttribute getFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1748
                return ensureFamixAnnotationTypeAttribute( bnd, name, owner);
6 ✔
1749
        }
1750
        
1751
        
1752
        /**
1753
         * Returns a FAMIX Wildcard with its bounds
1754
         * @param bnd
1755
         * @param name
1756
         * @param owner
1757
         * @return
1758
         */
1759
        public Wildcard ensureFamixWildcardType(ITypeBinding bnd, String name, TParametricEntity owner, TWithTypes ctxt) {
1760
                Wildcard fmx = this.ensureFamixEntity(Wildcard.class, bnd, bnd.getName());
8 ✔
1761
                if(bnd.getBound() != null) {
3 ✔
1762
                        Type bound = this.ensureFamixType(bnd.getBound());
5 ✔
1763
                        if(bnd.isUpperbound()) {
3 ✔
1764
                                fmx.setUpperBound(bound);
3 ✔
1765
                                bound.addUpperBoundedWildcards(fmx);
4 ✔
1766
                        }else{
1767
                                fmx.setLowerBound(bound);
3 ✔
1768
                                bound.addLowerBoundedWildcards(fmx);
3 ✔
1769
                        }
1770
                }
1771
                return fmx;
2 ✔
1772
        }
1773

1774
        /**
1775
         * Returns a Famix TypeParameter (created by a Famix ParametricEntity) with the given <b>name</b>, creating it if it does not exist yet
1776
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public
1777
         * @param name -- the name of the Famix TypeParameter
1778
         * @return the Famix TypeParameter or null in case of a Famix error
1779
         */
1780
        public TypeParameter ensureFamixTypeParameter(ITypeBinding bnd,        String name, TWithTypes owner) {
1781
                TypeParameter fmx;
1782

1783
                // --------------- to avoid useless computations if we can
1784
                fmx = (TypeParameter)getEntityByKey(bnd);
5 ✔
1785
                if (fmx != null) {
2 ✔
1786
                        return fmx;
2 ✔
1787
                }
1788

1789
                // --------------- name
1790
                if (name == null) {
2 ✔
1791
                        if (bnd == null) {
2 !
1792
                                return null;
×
1793
                        }
1794
                        else {
1795
                                name = bnd.getName();
3 ✔
1796
                        }
1797
                }
1798

1799
                // --------------- owner
1800
                if (owner == null && bnd != null) {
2 !
1801
            if (bnd.getDeclaringClass() != null) {
×
1802
                owner = this.ensureFamixType(bnd.getDeclaringClass());
×
1803
            } else if(bnd.getDeclaringMethod() != null) {
×
1804
                owner = this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1805
            }
1806
                }
1807

1808
                // --------------- recover from name ?
1809
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13 ✔
1810
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8 ✔
1811
                                fmx = (TypeParameter) candidate;
3 ✔
1812
                                break;
1 ✔
1813
                        }
1814
                }
1 ✔
1815

1816
                // --------------- create
1817
                if (fmx == null) {
2 ✔
1818
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7 ✔
1819
                        if(bnd != null && bnd.getSuperclass() != null) {
5 !
1820
                                Type upperBound = ensureFamixType(bnd.getSuperclass());
5 ✔
1821
                                fmx.setUpperBound(upperBound);
3 ✔
1822
                        }
1823
                        if(bnd != null) {
2 ✔
1824
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17 ✔
1825
                    Type upperBound = ensureFamixType(intbnd);
4 ✔
1826
                    fmx.setUpperBound(upperBound);
3 ✔
1827
                }
1828
            }
1829
                        fmx.setTypeContainer(owner);
3 ✔
1830
                }
1831

1832
                return fmx;
2 ✔
1833
        }
1834

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

1850
                // check whether bnd and candidate are already bound
1851
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
1852
                if (res == CheckResult.MATCH) {
3 ✔
1853
                        return true;
2 ✔
1854
                } else if (res == CheckResult.FAIL) {
3 ✔
1855
                        return false;
2 ✔
1856
                }
1857

1858
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 ✔
1859
                        return false;
2 ✔
1860
                }
1861

1862
                // names match, not need to look at owner because names of Namespaces are their fully qualified name
1863
                conditionalMapToKey(bnd, candidate);
4 ✔
1864
                return true;
2 ✔
1865
        }
1866

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

1882
                // check whether bnd and candidate are already bound
1883
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
1884
                if (res == CheckResult.MATCH) {
3 ✔
1885
                        return true;
2 ✔
1886
                }
1887
                else if (res == CheckResult.FAIL) {
3 ✔
1888
                        return false;
2 ✔
1889
                }
1890

1891
                if ( (bnd != null) && (bnd.isArray()) ) {
5 ✔
1892
                                bnd = bnd.getElementType();
3 ✔
1893
                }
1894

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

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

1919
                // check owners without bnd
1920
                if (bnd == null) {
2 ✔
1921
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7 ✔
1922
                }
1923

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

1935
                // check owners with bnd
1936
                // type is a Parameterized type
1937
                if ((bnd.isParameterizedType() || bnd.isRawType()) && (candidate instanceof ParametricClass)) {
6 !
1938
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1939
                }
1940

1941
                // check owners with bnd
1942
                // type is an Enum
1943
                if (bnd.isEnum() && (candidate instanceof Enum)) {
3 !
1944
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1945
                }
1946

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

1954
                if(bnd.isInterface()) {
3 !
UNCOV
1955
                        return matchAndMapInterface(bnd, name, owner, (Type) candidate);
×
1956
                }
1957

1958
                return false;
2 ✔
1959
        }
1960

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

1975
                // check whether bnd and candidate are already bound
1976
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
1977
                if (res == CheckResult.MATCH) {
3 ✔
1978
                        return true;
2 ✔
1979
                } else if (res == CheckResult.FAIL) {
3 ✔
1980
                        return false;
2 ✔
1981
                }
1982

1983
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 !
1984
                        return false;
×
1985
                }
1986

1987
                // checking owner
1988
                return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7 ✔
1989
        }
1990

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

2005
                // check whether bnd and candidate are already bound
2006
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
2007
                if (res == CheckResult.MATCH) {
3 ✔
2008
                        return true;
2 ✔
2009
                } else if (res == CheckResult.FAIL) {
3 ✔
2010
                        return false;
2 ✔
2011
                }
2012

2013
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 !
UNCOV
2014
                        return false;
×
2015
                }
2016

2017
                // checking owner
2018
                return matchAndMapTypeOwner(bnd, owner, candidate);
6 ✔
2019
        }
2020

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

2037
                // check whether bnd and candidate are already bound
2038
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
2039
                if (res == CheckResult.MATCH) {
3 ✔
2040
                        return true;
2 ✔
2041
                }
2042
                else if (res == CheckResult.FAIL) {
3 ✔
2043
                        return false;
2 ✔
2044
                }
2045

2046
                // checking names
2047
                String name = (sig != null) ? sig.substring(0, sig.indexOf('(')) : null;
10 !
2048
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 ✔
2049
                        return false;
2 ✔
2050
                }
2051

2052
                // for methods, the name is not enough, we must test the signature also
2053
                // but not for AnnotationTypeAttribute
2054

2055
                        if (bnd != null) {
2 ✔
2056
                                sig = bnd.getName() + "(" + signatureParamsFromBinding(bnd) + ")";
7 ✔
2057
                        }
2058
                        if (! ((Method) candidate).getSignature().equals(sig)) {
6 ✔
2059
                                return false;
2 ✔
2060
                        }
2061

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

2096

2097
                // check owner
2098
                if (matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, Util.getOwner(candidate)) == CheckResult.MATCH) {
13 ✔
2099
                        conditionalMapToKey(bnd, candidate);
4 ✔
2100
                        return true;
2 ✔
2101
                } else {
2102
                        return false;
2 ✔
2103
                }
2104
        }
2105

2106
        /** testing that a method binding is for a constructor
2107
         * There is a special case for "diamond constructors" (eg: <code>new HashSet<>()</code>)
2108
         */
2109
        protected boolean isConstructorBinding(IMethodBinding bnd) {
2110
                if (bnd.isConstructor()) {
3 ✔
2111
                        return true;
2 ✔
2112
                }
2113
                if ( bnd.getName().equals("<factory>") ) {
5 ✔
2114
                        return true;
2 ✔
2115
                }
2116
                return false;
2 ✔
2117
        }
2118

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

2134
                // check whether bnd and candidate are already bound
2135
                CheckResult keyMatch = checkKeyMatch(bnd, candidate);
5 ✔
2136
                if (keyMatch == CheckResult.MATCH) {
3 !
2137
                        return true;
×
2138
                } else if (keyMatch == CheckResult.FAIL) {
3 ✔
2139
                        return false;
2 ✔
2140
                }
2141

2142
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 !
2143
                        return false;
×
2144
                }
2145

2146
                // check owner
2147
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3 ✔
2148

2149
                // local variable or parameter ?
2150
                // owner is a Method? (for example in case of an anonymous class)
2151
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidateOwner);
11 ✔
2152
                if (res == CheckResult.FAIL) {
3 ✔
2153
                        return false;
2 ✔
2154
                } else if (res == CheckResult.MATCH) {
3 !
2155
                        conditionalMapToKey(bnd, candidate);
×
2156
                        return true;
×
2157
                }
2158

2159
                // check owner
2160
                // <anArray>.length field?
2161
                if (name.equals("length")) {
4 !
2162
                        boolean isArrayLengthField = ((bnd != null) && (bnd.getDeclaringClass() == null)) ||
×
2163
                                                                                 ((bnd == null) && (owner.getName().equals(EntityDictionary.ARRAYS_NAME)));
×
2164
                        if (isArrayLengthField) {
×
2165
                                if (candidateOwner.getName().equals(EntityDictionary.ARRAYS_NAME)) {
×
2166
                                        conditionalMapToKey(bnd, candidate);
×
2167
                                        return true;
×
2168
                                }
2169
                                else {
2170
                                        return false;
×
2171
                                }
2172
                        }
2173
                }
2174

2175
                // check owner
2176
                // "normal" field?
2177
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11 ✔
2178
                if (res == CheckResult.MATCH) {
3 !
2179
                        conditionalMapToKey(bnd, candidate);
4 ✔
2180
                        return true;
2 ✔
2181
                }
2182
                return false;
×
2183
        }
2184

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

2196
                // owner is a Method? (for example in case of an anonymous class)
2197
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11 ✔
2198
                if (res == CheckResult.MATCH) {
3 !
2199
                        conditionalMapToKey(bnd, candidate);
×
2200
                        return true;
×
2201
                } else if (res == CheckResult.FAIL) {
3 !
2202
                        return false;
×
2203
                }
2204

2205
                // owner is a class ?
2206
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11 ✔
2207
                if (res == CheckResult.MATCH) {
3 ✔
2208
                        conditionalMapToKey(bnd, candidate);
4 ✔
2209
                        return true;
2 ✔
2210
                }
2211
                else if (res == CheckResult.FAIL) {
3 ✔
2212
                        return false;
2 ✔
2213
                }
2214

2215
                // owner must be a package
2216
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12 ✔
2217
                        conditionalMapToKey(bnd, candidate);
4 ✔
2218
                        return true;
2 ✔
2219
                }
2220
                return false;
2 ✔
2221
        }
2222

2223
        /**
2224
         * Check whether the owner of candidates is a method macthinf either methBnd or owner
2225
         * @param methBnd
2226
         * @param owner
2227
         * @param candidateOwner
2228
         * @return a {@link CheckResult}
2229
         */
2230
        private  <T extends TNamedEntity> CheckResult matchAndMapOwnerAsMethod(IMethodBinding methBnd, T owner, T candidateOwner) {
2231
                if ((methBnd != null) || (owner instanceof Method)) {
5 !
2232
                        if (!(candidateOwner instanceof Method)) {
3 !
2233
                                return CheckResult.FAIL;
×
2234
                        }
2235

2236
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7 !
2237
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7 !
2238
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8 !
2239

2240
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9 !
2241
                                return CheckResult.MATCH;
×
2242
                        } else {
2243
                                return CheckResult.FAIL;
2 ✔
2244
                        }
2245
                }
2246
                return CheckResult.UNDECIDED;
2 ✔
2247
        }
2248

2249
        /**
2250
         * @param typBnd
2251
         * @param owner
2252
         * @param candidateOwner
2253
         * @return a {@link CheckResult}
2254
         */
2255
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2256
                if ((typBnd != null) || (owner instanceof Type)) {
5 ✔
2257
                        if (!(candidateOwner instanceof Type)) {
3 ✔
2258
                                return CheckResult.FAIL;
2 ✔
2259
                        }
2260

2261
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6 !
2262
                        String ownerName = (owner != null) ? owner.getName() : null;
6 !
2263

2264
                        if (matchAndMapType(typBnd, ownerName, ownerOwner, candidateOwner)) {
7 ✔
2265
                                return CheckResult.MATCH;
2 ✔
2266
                        } else {
2267
                                return CheckResult.FAIL;
2 ✔
2268
                        }
2269
                }
2270
                return CheckResult.UNDECIDED;
2 ✔
2271
        }
2272

2273
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2274
                if ((pckgBnd != null) || (owner instanceof Package)) {
5 !
2275
                        if (!(candidateOwner instanceof Package)) {
3 !
2276
                                return CheckResult.FAIL;
×
2277
                        }
2278

2279
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7 !
2280
                        String ownerName = (owner != null) ? owner.getName() : null;
6 !
2281

2282
                        if (matchAndMapPackage(pckgBnd, ownerName, ownerOwner, candidateOwner)) {
7 ✔
2283
                                return CheckResult.MATCH;
2 ✔
2284
                        } else {
2285
                                return CheckResult.FAIL;
2 ✔
2286
                        }
2287
                }
2288
                return CheckResult.UNDECIDED;
×
2289
        }
2290

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

2311
        /**
2312
         * Check whether key and candidate are already bound together, whether either is bound to something else, or whether none is bound
2313
         * @param key
2314
         * @param candidate
2315
         * @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>
2316
         */
2317
        private CheckResult checkKeyMatch(IBinding key, TNamedEntity candidate) {
2318
                if (key == null) {
2 ✔
2319
                        return CheckResult.UNDECIDED;
2 ✔
2320
                }
2321

2322
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5 ✔
2323
                if (bound == candidate) {
3 ✔
2324
                        return CheckResult.MATCH;
2 ✔
2325
                }
2326
                else if (bound != null) {
2 ✔
2327
                        return CheckResult.FAIL;
2 ✔
2328
                }
2329
                else if (getEntityKey(candidate) != null) {
4 ✔
2330
                        //we check if the both bindings are linked to the same entity
2331
                        IBinding candidateBinding = getEntityKey(candidate);
4 ✔
2332
                        if(candidateBinding.getKey().equals(key.getKey())) {
6 ✔
2333
                                return CheckResult.MATCH;
2 ✔
2334
                        }
2335
                        
2336
                        //if candidate is a stub, we accept multiple recovery binding
2337
                        //this code will be upgraded with the possibility to add manually code to entities
2338
                        if (candidate instanceof TCanBeStub && ((TCanBeStub) candidate).getIsStub()) {
8 !
2339
                                return CheckResult.UNDECIDED;
2 ✔
2340
                        }
2341
      
2342
                        return CheckResult.FAIL;
2 ✔
2343
                }
2344
                else {
2345
                        return CheckResult.UNDECIDED;
2 ✔
2346
                }
2347
        }
2348

2349
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2350
                if (bnd != null) {
2 ✔
2351
                        mapEntityToKey(bnd, ent);
4 ✔
2352
                }
2353
        }
1 ✔
2354

2355
        public Method ensureFamixMethod(IMethodBinding bnd) {
2356
                return ensureFamixMethod(
8 ✔
2357
                                bnd,
2358
                                /*name*/null,
2359
                                /*paramsType*/null,
2360
                                /*returnType*/null,
2361
                                /*owner*/null,
2362
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6 ✔
2363
        }
2364

2365
        /**
2366
         * Returns a Famix Method associated with the IMethodBinding.
2367
         * The Entity is created if it does not exist.
2368
         * @param name -- the name of the Famix Method (MUST NOT be null, but this is not checked)
2369
         * @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)
2370
         * @param owner -- type defining the method (should not be null, but it will work if it is)
2371
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2372
         */
2373
        public Method ensureFamixMethod(IMethodBinding bnd, String name, Collection<String> paramTypes, TType ret, TWithMethods owner, int modifiers) {
2374
                Method fmx;
2375
                String signature;
2376
                boolean delayedRetTyp;
2377

2378
                // --------------- to avoid useless computations if we can
2379
                fmx = (Method)getEntityByKey(bnd);
5 ✔
2380
                if (fmx != null) {
2 ✔
2381
                        return fmx;
2 ✔
2382
                }
2383

2384
                // --------------- name
2385
                if (name == null) {
2 ✔
2386
                        if (bnd == null) {
2 ✔
2387
                                return null;
2 ✔
2388
                        }
2389
                        else {
2390
                                name = bnd.getName();
3 ✔
2391
                        }
2392
                }
2393

2394
                // --------------- signature
2395
                signature = name + "(";
3 ✔
2396
                 if (bnd != null) {
2 ✔
2397
                    signature += signatureParamsFromBinding(bnd);
7 ✔
2398
                }
2399
        else if (paramTypes != null) {
2 !
2400
                        signature += signatureParamsFromStringCollection(paramTypes);
7 ✔
2401
                }
2402
                else {
2403
                        signature += "???";
×
2404
                }
2405
                signature += ")";
3 ✔
2406

2407
                // --------------- return type
2408
                delayedRetTyp = false;
2 ✔
2409
                ITypeBinding retTypBnd = null;
2 ✔
2410
                if (ret == null) {
2 !
2411
                        if (bnd != null) {
2 ✔
2412
                // must create the return type
2413
                // but for method like "<T> T mtd()" where T belongs to mtd and mtd returns T,
2414
                // we need T to create the method and the method to create T ...
2415
                // so we need to test the situation and deal with it
2416
                retTypBnd = bnd.getReturnType();
3 ✔
2417
                if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9 ✔
2418
                    delayedRetTyp = true;
3 ✔
2419
                }
2420
                else {
2421
                        ret = this.referredType(retTypBnd, fmx);
5 ✔
2422
                }
2423
                        }
2424
                }
2425

2426
                // --------------- owner
2427
                if (owner == null) {
2 ✔
2428
                        if (bnd == null) {
2 ✔
2429
                                owner = ensureFamixClassStubOwner();
4 ✔
2430
                        }
2431
                        else {
2432
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4 ✔
2433
                                if (classBnd != null) {
2 !
2434
                                        owner = ensureFamixType(classBnd);
5 ✔
2435
                                }
2436
                                else {
2437
                                        owner = ensureFamixClassStubOwner();
×
2438
                                }
2439
                        }
2440
                }
2441

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

2450
                if (fmx == null) {
2 ✔
2451
                        if(bnd != null && bnd.isGenericMethod() && !isConstructorBinding(bnd)) {
9 ✔
2452
                                fmx = ensureFamixEntity(ParametricMethod.class, bnd, name);
7 ✔
2453
                                for(ITypeBinding param: bnd.getTypeParameters()) {
18 ✔
2454
                                        TypeParameter fmxParam = this.ensureFamixTypeParameter(param, null, fmx);
6 ✔
2455
                                        fmxParam.setGenericEntity((ParametricMethod)fmx);
4 ✔
2456
                                }
2457
                        // Parameterized method binding = when the method is the target of an invocation.
2458
                        } else if (bnd != null && bnd.isParameterizedMethod()) {
5 ✔
2459
                                fmx = this.ensureFamixMethod(bnd.getMethodDeclaration());
6 ✔
2460
                        } else {
2461
                if (bnd != null && isConstructorBinding(bnd)) {
6 ✔
2462
                    fmx = ensureFamixEntity(Initializer.class, bnd, name);
8 ✔
2463
                } else {
2464
                    fmx = ensureFamixEntity(Method.class, bnd, name);
7 ✔
2465
                }
2466
            }
2467

2468
                        fmx.setSignature(signature);
3 ✔
2469
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
7 ✔
2470
                        ensureFamixEntityTyping(returnTypeBnd, fmx, ret);
6 ✔
2471
                        fmx.setParentType(owner);
3 ✔
2472
                }
2473

2474
                if (fmx != null) {
2 !
2475
                        setMethodModifiers(fmx, modifiers);
4 ✔
2476
                }
2477

2478
        //If it has the #default keywork, we mark it as default implementation
2479
        if (Modifier.isDefault(modifiers)) {
3 ✔
2480
            fmx.setKind(DEFAULT_IMPLEMENTATION_KIND_MARKER);
3 ✔
2481
        }
2482

2483
        if (delayedRetTyp) {
2 ✔
2484
                        int retTypModifiers = retTypBnd.getModifiers();
3 ✔
2485
                        ITypeBinding returnTypeBnd = bnd.getReturnType();
3 ✔
2486
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13 ✔
2487
                }
2488

2489
                return fmx;
2 ✔
2490
        }
2491

2492

2493
        /**
2494
         * Creates or recovers the initializer method containing the attribute initializations of a type.
2495
         * @param owner Type containing the initializer
2496
         * @param isStatic Modifier of the initializer. A type can have 2 initializers for attribute initialization: 1 static and 1 not.
2497
         * @param isInitializationBlock True if the entity is an initialization block. False for the artificial method containing all field initializations.
2498
         * @return the FamixInitializer
2499
         */
2500
        public Initializer ensureFamixInitializer(TWithMethods owner, Boolean isStatic, Boolean isInitializationBlock) {
2501
                Initializer fmx = null;
2 ✔
2502

2503
                if (owner != null) {
2 !
2504
                        Optional<TMethod> existingInitializer = owner.getMethods().stream()
6 ✔
2505
                                        .filter(meth ->
1 ✔
2506
                                                        ((Method) meth).getIsInitializer() &&
8 ✔
2507
                                                        ((Method) meth).getIsConstructor().equals(false) &&
7 ✔
2508
                                                        ((Method) meth).getIsClassSide().equals(isStatic) &&
6 ✔
2509
                                                        ((Initializer) meth).getIsInitializationBlock().equals(isInitializationBlock))
7 ✔
2510
                                        .findFirst();
2 ✔
2511
                        if (existingInitializer.isPresent()) {
3 ✔
2512
                                fmx = (Initializer) existingInitializer.get();
4 ✔
2513
                        }
2514
                }
2515

2516
                if (fmx == null) {
2 ✔
2517
                        fmx = createFamixEntity(Initializer.class, INIT_BLOCK_NAME);
6 ✔
2518
                        fmx.setSignature(INIT_BLOCK_NAME + "()" );
3 ✔
2519
                        fmx.setVisibility(MODIFIER_PRIVATE);
3 ✔
2520
                        fmx.setParentType(owner);
3 ✔
2521
                        fmx.setIsClassSide(isStatic);
3 ✔
2522
                        fmx.setIsInitializationBlock(isInitializationBlock);
3 ✔
2523
                }
2524

2525
                return fmx;
2 ✔
2526
        }
2527

2528

2529
        public Initializer ensureImplicitConstructor(IMethodBinding binding, TWithMethods owner, String name, Collection<String> parameterTypesNames) {
2530
                Initializer fmx = null;
2 ✔
2531

2532
                if (fmx == null) {
2 !
2533
                        int modifiers = (binding != null) ? binding.getModifiers() : EntityDictionary.UNKNOWN_MODIFIERS;
7 ✔
2534
                        if (binding == null) {
2 ✔
2535
                                // OK! Binding is null, this is the default constructor!!
2536
                                // It has no source code :)
2537
                                fmx = ensureFamixEntity(Initializer.class, null, name);
7 ✔
2538
                                fmx.setParentType(owner);
3 ✔
2539
                                fmx.setSignature(name + "()");                                
5 ✔
2540
                        } else {
2541
                                // But, if we have the binding, that means the constructor exists. Let's just go the normal way
2542
                                fmx = (Initializer) this.ensureFamixMethod(binding, name, parameterTypesNames, /*ret type*/null, owner, modifiers);
10 ✔
2543
                        }
2544
                }
2545

2546
                return fmx;
2 ✔
2547
        }
2548

2549
        /**
2550
         * Creates or recovers a stub Famix Method
2551
         * @param name of the method
2552
         * @return the Famix Method
2553
         */
2554
        public Method ensureFamixStubMethod(String name) {
2555
                return ensureFamixMethod(null, name, /*paramType*/null, /*returnType*/null, ensureFamixClassStubOwner(), /*modifiers*/0);
×
2556
        }
2557

2558
        public void setAttributeModifiers(Attribute fmx, int mod) {
2559
                setCommonModifiers(fmx, mod, null);
5 ✔
2560
                fmx.setIsTransient(Modifier.isTransient(mod));
5 ✔
2561
                fmx.setIsVolatile(Modifier.isVolatile(mod));
5 ✔
2562
        }
1 ✔
2563

2564
        public void setMethodModifiers(Method fmx, int mod) {
2565
                setCommonModifiers(fmx, mod, (TWithTypes) fmx.getParentType());
7 ✔
2566
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5 ✔
2567
                fmx.setIsSynchronized(Modifier.isSynchronized(mod));
5 ✔
2568
        }
1 ✔
2569

2570
        public void setClassModifiers(Class fmx, int mod, TWithTypes owner) {
2571
                setCommonModifiers(fmx, mod, null);
5 ✔
2572
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5 ✔
2573
        }
1 ✔
2574

2575
        public void setInterfaceModifiers(Interface fmx, int mod) {
2576
                setCommonModifiers(fmx, mod, null);
5 ✔
2577
        }
1 ✔
2578

2579
        private void setCommonModifiers(Entity fmx, int mod, TWithTypes owner) {
2580
                setVisibility((THasVisibility)fmx, mod, owner);
6 ✔
2581
                ((TCanBeClassSide)fmx).setIsClassSide(Modifier.isStatic(mod));
6 ✔
2582
                ((TCanBeFinal)fmx).setIsFinal(Modifier.isFinal(mod));
6 ✔
2583
        }
1 ✔
2584

2585
        /**
2586
         * Sets the visibility of a FamixNamedEntity
2587
         *
2588
         * @param fmx -- the FamixNamedEntity
2589
         * @param mod -- a description of the modifiers as understood by org.eclipse.jdt.core.dom.Modifier
2590
         */
2591
        public void setVisibility(THasVisibility fmx, int mod, TWithTypes owner) {
2592
                if (Modifier.isPublic(mod)) {
3 ✔
2593
                        fmx.setVisibility(MODIFIER_PUBLIC);
4 ✔
2594
                } else if (Modifier.isPrivate(mod)) {
3 ✔
2595
                        fmx.setVisibility(MODIFIER_PRIVATE);
4 ✔
2596
                } else if (Modifier.isProtected(mod)) {
3 ✔
2597
                        fmx.setVisibility(MODIFIER_PROTECTED);
4 ✔
2598
                } else {
2599
                        //Default visibility!
2600
                        //If we are in an interface, default visibility is public, otherwise package.
2601
                        if (owner instanceof Interface) {
3 ✔
2602
                                fmx.setVisibility(MODIFIER_PUBLIC);
4 ✔
2603
                        } else {
2604
                                fmx.setVisibility(MODIFIER_PACKAGE);
3 ✔
2605
                        }
2606
                }
2607
        }
1 ✔
2608

2609
        /**
2610
         * Returns a Famix Attribute associated with the IVariableBinding.
2611
         * The Entity is created if it does not exist.<br>
2612
         * @param name -- the name of the FAMIX Attribute (MUST NOT be null, but this is not checked)
2613
         * @param type -- Famix Type of the Attribute (should not be null, but it will work if it is)
2614
         * @param owner -- type defining the Attribute (should not be null, but it will work if it is)
2615
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2616
         */
2617
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, Type type, TWithAttributes owner) {
2618
                Attribute fmx;
2619

2620
                // --------------- to avoid useless computations if we can
2621
                fmx = (Attribute)getEntityByKey(bnd);
5 ✔
2622
                if (fmx != null) {
2 ✔
2623
                        return fmx;
2 ✔
2624
                }
2625

2626
                // --------------- name
2627
                if (name == null) {
2 !
2628
                        if (bnd == null) {
×
2629
                                return null;
×
2630
                        }
2631
                        else {
2632
                                name = bnd.getName();
×
2633
                        }
2634
                }
2635

2636
                // --------------- owner
2637
                if (owner == null) {
2 ✔
2638
                        if (bnd == null) {
2 !
2639
                                return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
×
2640
                        }
2641
                        else {
2642
                                if (bnd.getDeclaringClass() != null && bnd.getDeclaringClass().getErasure() != null) {
7 !
2643
                                        // Declaring class is the generic one if the class is parametric.
2644
                                        owner = (TWithAttributes)ensureFamixType(bnd.getDeclaringClass().getErasure());
8 ✔
2645
                                } else {
2646
                                        return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
2 ✔
2647
                                }
2648
                        }
2649
                }
2650

2651
                // --------------- recover from name ?
2652
                for (Attribute candidate : getEntityByName(Attribute.class, name)) {
13 ✔
2653
                        if (matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate)) {
8 ✔
2654
                                fmx = candidate;
2 ✔
2655
                                break;
1 ✔
2656
                        }
2657
                }
1 ✔
2658

2659
                if (fmx == null) {
2 ✔
2660
                        fmx = ensureFamixEntity(Attribute.class, bnd, name);
7 ✔
2661
                        fmx.setParentType( owner);
3 ✔
2662
                }
2663

2664
        fmx.setParentType(owner);
3 ✔
2665
        ITypeBinding declaredTypeBinding = (bnd == null) ? null : bnd.getType();
7 ✔
2666
        ensureFamixEntityTyping(declaredTypeBinding, fmx, type);
6 ✔
2667
        if (bnd != null) {
2 ✔
2668
            int mod = bnd.getModifiers();
3 ✔
2669
            setAttributeModifiers(fmx, mod);
4 ✔
2670
        }
2671

2672
        return fmx;
2 ✔
2673
        }
2674

2675
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2676
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7 ✔
2677
        }
2678

2679
        /**
2680
         * helper method, we know the var exists, ensureFamixAttribute will recover it
2681
         */
2682
        public Attribute getFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2683
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7 ✔
2684
        }
2685

2686
        /**
2687
         * Returns a Famix Parameter associated with the IVariableBinding.
2688
         * The Entity is created if it does not exist.<br>
2689
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2690
         */
2691
        public Parameter ensureFamixParameter(IVariableBinding bnd, String name, Type typ, TMethod tMethod) {
2692
                Parameter fmx = null;
2 ✔
2693

2694
                // --------------- to avoid useless computations if we can
2695
                try {
2696
                        fmx = (Parameter)getEntityByKey(bnd);
5 ✔
2697
                }catch(Throwable e) {
×
2698
                        e.printStackTrace();
×
2699
                }
1 ✔
2700
                if (fmx != null) {
2 ✔
2701
                        return fmx;
2 ✔
2702
                }
2703

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

2714
                // --------------- owner
2715
                if (tMethod == null) {
2 !
2716
                        if (bnd == null) {
×
2717
                                tMethod = ensureFamixStubMethod("<"+name+"_owner>");
×
2718
                        }
2719
                        else {
2720
                                tMethod = ensureFamixMethod(bnd.getDeclaringMethod());
×
2721
                        }
2722
                }
2723

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

2732
                if (fmx == null) {
2 !
2733
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7 ✔
2734
                }
2735

2736
                if (fmx != null) {
2 !
2737
                        fmx.setParentBehaviouralEntity(tMethod);
3 ✔
2738
                        ITypeBinding declaredTypeBnd = (bnd == null) ? null : bnd.getType();
5 !
2739
                        ensureFamixEntityTyping(declaredTypeBnd, fmx, typ);
6 ✔
2740
                }
2741

2742
                return fmx;
2 ✔
2743
        }
2744

2745
    /**
2746
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2747
         * The Entity is created if it does not exist.<br>
2748
         * @param name -- the name of the FAMIX LocalVariable
2749
         * @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
2750
         */
2751
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2752
                LocalVariable fmx;
2753

2754
                // --------------- to avoid useless computations if we can
2755
                fmx = (LocalVariable)getEntityByKey(bnd);
5 ✔
2756
                if (fmx != null) {
2 !
2757
                        return fmx;
×
2758
                }
2759

2760
                // --------------- name
2761
                if (name == null) {
2 !
2762
                        if (bnd == null) {
×
2763
                                return null;
×
2764
                        }
2765
                        else {
2766
                                name = bnd.getName();
×
2767
                        }
2768
                }
2769

2770
                // --------------- owner
2771
                if (owner == null) {
2 !
2772
                        if (bnd == null) {
×
2773
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2774
                        }
2775
                        else {
2776
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2777
                        }
2778
                }
2779

2780
                // --------------- recover from name ?
2781
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13 ✔
2782
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8 !
2783
                                fmx = candidate;
×
2784
                                break;
×
2785
                        }
2786
                }
1 ✔
2787

2788
                if (fmx == null) {
2 !
2789
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7 ✔
2790
                        fmx.setParentBehaviouralEntity(owner);
3 ✔
2791
                }
2792

2793
        // we just created it or it was not bound, so we make sure it has the right information in it
2794
        fmx.setParentBehaviouralEntity(owner);
3 ✔
2795

2796
        return fmx;
2 ✔
2797
        }
2798

2799
    /**
2800
         * Returns a FAMIX ImplicitVariable with the given <b>name</b> ("self" or "super") and corresponding to the <b>type</b>.
2801
         * If this ImplicitVariable does not exist yet, it is created
2802
         * @param name -- the name of the FAMIX ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
2803
         * @param type -- the Famix Type for this ImplicitVariable (should not be null)
2804
         * @param tMethod -- the ContainerEntity where the implicit variable appears (should be a method inside <b>type</b>)
2805
         * @return the FAMIX ImplicitVariable or null in case of a FAMIX error
2806
         */
2807
        public ImplicitVariable ensureFamixImplicitVariable(IBinding key, String name, TType type, TMethod tMethod) {
2808
                ImplicitVariable fmx;
2809
                fmx = ensureFamixEntity(ImplicitVariable.class, key, name);
7 ✔
2810
                fmx.setParentBehaviouralEntity(tMethod);
3 ✔
2811
                return fmx;
2 ✔
2812
        }
2813

2814
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2815
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4 ✔
2816
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7 ✔
2817
        }
2818

2819
        /**
2820
         * Creates and returns a Famix Comment and associates it with an Entity (ex: for Javadocs)
2821
         * @param jCmt -- the content (String) of the comment 
2822
         * @param owner -- the entity that is commented
2823
         * @return the Famix Comment
2824
         */
2825
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner) {
2826
                Comment cmt = null;
2 ✔
2827

2828
                if ( (jCmt != null) && (owner != null) ) {
4 !
2829
                        
2830
                        cmt = new Comment();
4 ✔
2831
                        addSourceAnchor(cmt, jCmt);
5 ✔
2832
                        famixRepoAdd(cmt);
3 ✔
2833
                        cmt.setCommentedEntity(owner);
3 ✔
2834
                }
2835

2836
                return cmt;
2 ✔
2837
        }
2838

2839
        /**
2840
         * Creates and returns a Famix Comment and associates it with an Entity
2841
         * @param jCmt -- the content (String) of the comment 
2842
         * @param owner -- the entity that is commented
2843
         * @param content -- the text of the comment
2844
         * @return the Famix Comment
2845
         */
2846
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner, String content) {
2847
                Comment cmt = null;
2 ✔
2848

2849
                if ( (jCmt != null) && (owner != null) ) {
4 !
2850
                        cmt = new Comment();
4 ✔
2851
                        cmt.setContent(content );
3 ✔
2852
                        famixRepoAdd(cmt);
3 ✔
2853
                        cmt.setCommentedEntity(owner);
3 ✔
2854
                }
2855

2856
                return cmt;
2 ✔
2857
        }
2858

2859
        /**
2860
         * Adds location information to a Famix Entity.
2861
         * 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.
2862
         * This method also creates some basic links between the entity and others (e.g. declaring container, return type, ...)
2863
         * @param fmx -- Famix Entity to add the anchor to
2864
         * @param node -- JDT ASTNode, where the information is extracted
2865
         * @return the Famix SourceAnchor added to fmx. May be null in case of incorrect parameter ('fmx' or 'ast' == null)
2866
         */
2867
        public SourceAnchor addSourceAnchor(TSourceEntity fmx, ASTNode node) {
2868
                IndexedFileAnchor fa;
2869

2870
                fa = createIndexedFileAnchor(node);
4 ✔
2871
                if ((fmx != null) && (fa != null)) {
4 !
2872
                        fmx.setSourceAnchor(fa);
3 ✔
2873
                        famixRepoAdd(fa);
3 ✔
2874
                }
2875

2876
                return fa;
2 ✔
2877
        }
2878

2879
        /**
2880
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2881
         */
2882
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2883
                IndexedFileAnchor fa;
2884

2885
                fa = createIndexedFileAnchor(node);
4 ✔
2886
                if ((fmx != null) && (fa != null)) {
4 !
2887

2888
                        // may change the positions
2889
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4 ✔
2890
                        methodDeclarationModifiers.addAll(node.modifiers());
5 ✔
2891
                        if (node.getName() != null) {
3 !
2892
                                methodDeclarationModifiers.add(node.getName());
5 ✔
2893
                        }
2894
                        if (node.getReturnType2() != null) {
3 ✔
2895
                                methodDeclarationModifiers.add(node.getReturnType2());
5 ✔
2896
                        }
2897
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12 ✔
2898
                        int end = node.getStartPosition() + node.getLength();
6 ✔
2899

2900
                        fa.setStartPos(beg);
4 ✔
2901
                        fa.setEndPos(end);
4 ✔
2902

2903
                        fmx.setSourceAnchor(fa);
3 ✔
2904
                        famixRepoAdd(fa);
3 ✔
2905
                }
2906

2907
                return fa;
2 ✔
2908
        }
2909

2910
        /**
2911
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2912
         * Information returned in the form of an IndexedFileAnchor
2913
         */
2914
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2915
                IndexedFileAnchor fa;
2916
                
2917
                if (node == null) {
2 !
2918
                        return null;
×
2919
                }
2920

2921
                // position in source file
2922
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5 ✔
2923
                int end = beg + node.getLength() - 1;
7 ✔
2924

2925
                // find source Compilation Unit
2926
                // there is a special case for the JDT Comment Nodes
2927
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3 ✔
2928
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5 ✔
2929
                } else {
2930
                        node = node.getRoot();
3 ✔
2931
                }
2932

2933
                fa = new IndexedFileAnchor();
4 ✔
2934
                fa.setStartPos(beg);
4 ✔
2935
                fa.setEndPos(end);
4 ✔
2936

2937
                fa.setFileName((String) node.getProperty(SOURCE_FILENAME_PROPERTY));
6 ✔
2938

2939
                return fa;
2 ✔
2940
        }
2941

2942
        /**
2943
         * Creates or recovers the Famix Class for "Object".
2944
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2945
         *
2946
         * @return a Famix class for "Object"
2947
         */
2948
        public Class ensureFamixClassObject() {
2949
        // In the past we used #ensureFamixUniqEntity but that does not check that the parent package is right and we got some Object from other packages than java.lang...
2950
        Collection<Class> objects = getEntityByName(Class.class, "Object");
5 ✔
2951

2952
        for (Class entity : objects) {
10 ✔
2953
                //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2954
                if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7 ✔
2955
                    return entity;
2 ✔
2956
                }
2957
        }
1 ✔
2958

2959
        Class fmx = createFamixEntity(Class.class, "Object");
6 ✔
2960
        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5 ✔
2961
                return fmx;
2 ✔
2962
        }
2963

2964
        /***
2965
         * We treat array types as parametrized types Array<T>.
2966
         * This keeps the meta-model simple: a single way to model different concepts.
2967
         * @return
2968
         */
2969
        public ParametricClass ensureParametricArrayClass() {
2970
                
2971
                Collection<ParametricClass> arrayClasses = getEntityByName(ParametricClass.class, "Array");
5 ✔
2972
                
2973
                for (ParametricClass entity : arrayClasses) {
10 ✔
2974
            //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2975
            if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7 !
2976
                return entity;
2 ✔
2977
            }
2978
                }
×
2979
                
2980
                //Create the parametric class
2981
                ParametricClass arrayClass = createFamixEntity(ParametricClass.class, "Array"); 
6 ✔
2982

2983
                //And now add the type parameter
2984
                TypeParameter fmxParam = this.ensureFamixTypeParameter(null, "T", arrayClass);
6 ✔
2985
                fmxParam.setGenericEntity(arrayClass);
3 ✔
2986
                fmxParam.setIsStub(true);
4 ✔
2987
                
2988
                //And the class is in java.lang
2989
                arrayClass.setTypeContainer(ensureFamixPackageJavaLang(null));
5 ✔
2990
                
2991
                return arrayClass;
2 ✔
2992
        }
2993

2994
        /**
2995
         * Ensures the Java meta-class: <pre>{@code java.lang.Class<>}</pre>
2996
         */
2997
        public Class ensureFamixMetaClass(ITypeBinding bnd) {
2998
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7 !
2999
                ParametricClass fmx = (ParametricClass) this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, Modifier.PUBLIC & Modifier.FINAL);
9 ✔
3000

3001
                if (fmx != null) {
2 !
3002
                        fmx.addTypeParameters(ensureFamixTypeParameter(null, "T", fmx));
7 ✔
3003
                }
3004

3005
                if ((fmx != null) && (fmx.getSuperInheritances() == null)) {
5 !
3006
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, null, null);
×
3007
                }
3008

3009
                return fmx;
2 ✔
3010
        }
3011

3012
        public Class getFamixMetaClass(ITypeBinding bnd) {
3013
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7 !
3014
                return this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, UNKNOWN_MODIFIERS);
8 ✔
3015
        }
3016

3017
        /**
3018
         * Creates or recovers the Famix Class for all arrays (<pre>{@code <some-type> []}</pre>)
3019
         * In java arrays or objects of special classes (i.e. "I[" for an array of int).
3020
         * JDT does not create a binding for these classes, so we create a stub one here.
3021
         *
3022
         * @return a Famix class
3023
         */
3024
        public Class ensureFamixClassArray() {
3025
                Class fmx = ensureFamixUniqEntity(Class.class, null, ARRAYS_NAME);
×
3026
                if (fmx != null) {
×
3027
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, /*prev*/null, null);
×
3028
                        fmx.setTypeContainer(ensureFamixPackageDefault());
×
3029

3030
                        // may be not needed anymore now that we use modifiers
3031
                        /*fmx.setIsAbstract(Boolean.FALSE);
3032
                        fmx.setIsFinal(Boolean.FALSE);
3033
                        fmx.setIsInterface(Boolean.FALSE); 
3034
                        fmx.setIsPrivate(Boolean.FALSE);
3035
                        fmx.setIsProtected(Boolean.FALSE);*/
3036
                        fmx.setVisibility(MODIFIER_PUBLIC);
×
3037
                }
3038

3039
                return fmx;
×
3040
        }
3041

3042
        public String removeLastPartOfPackageName(String qualifiedName) {
3043
                String ret;
3044
                int last = qualifiedName.lastIndexOf('.');
4 ✔
3045
                if (last > 0) {
2 ✔
3046
                        // recursively creating the parent
3047
                        ret = qualifiedName.substring(0, last);
6 ✔
3048
                }
3049
                else {
3050
                        ret = "";
2 ✔
3051
                }
3052

3053
                return ret;
2 ✔
3054
        }
3055

3056
        /** Generates the list of parameters for a method signature
3057
         * @return a string
3058
         */
3059
        protected String signatureParamsFromBinding(IMethodBinding bnd) {
3060
                boolean first = true;
2 ✔
3061
                String sig = "";
2 ✔
3062

3063
                for (ITypeBinding parBnd : bnd.getParameterTypes()) {
17 ✔
3064
                        if (first) {
2 ✔
3065
                                sig = parBnd.getName();
3 ✔
3066
                                first = false;
3 ✔
3067
                        }
3068
                        else {
3069
                                sig += "," + parBnd.getName();
5 ✔
3070
                        }
3071
                }
3072
                return sig;
2 ✔
3073
        }
3074

3075
        private String signatureParamsFromStringCollection(Collection<String> paramTypes) {
3076
                boolean first = true;
2 ✔
3077
                String sig = "";
2 ✔
3078

3079
                for (String t : paramTypes) {
10 ✔
3080
                        if (first) {
2 ✔
3081
                                sig = t;
2 ✔
3082
                                first = false;
3 ✔
3083
                        }
3084
                        else {
3085
                                sig += "," + t;
4 ✔
3086
                        }
3087
                }
1 ✔
3088
                return sig;
2 ✔
3089
        }
3090

3091
        public String findTypeName(org.eclipse.jdt.core.dom.Type t) {
3092
                if (t == null) {
×
3093
                        return null;
×
3094
                }
3095

3096
                if (t.isPrimitiveType()) {
×
3097
                        return t.toString();
×
3098
                } else if (t.isSimpleType()) {
×
3099
                        String fullName = ((SimpleType) t).getName().getFullyQualifiedName();
×
3100
                        int i = fullName.lastIndexOf('.');
×
3101
                        if (i > 0) {
×
3102
                                return fullName.substring(i+1);
×
3103
                        }
3104
                        else {
3105
                                return fullName;
×
3106
                        }
3107
                } else if (t.isQualifiedType()) {
×
3108
                        return ((QualifiedType) t).getName().getIdentifier();
×
3109
                } else if (t.isArrayType()) {
×
3110
                        return findTypeName(((ArrayType) t).getElementType());
×
3111
                } else if (t.isParameterizedType()) {
×
3112
                        return findTypeName(((org.eclipse.jdt.core.dom.ParameterizedType) t).getType());
×
3113
                } else { // it is a WildCardType
3114
                        if (((org.eclipse.jdt.core.dom.WildcardType) t).isUpperBound()) {
×
3115
                                return findTypeName(((org.eclipse.jdt.core.dom.WildcardType) t).getBound());
×
3116
                        } else {
3117
                                return EntityDictionary.OBJECT_NAME;
×
3118
                        }
3119
                }
3120
        }
3121

3122
        /**
3123
         * Ensures the proper creation of a FamixType for JDT typ in the given context.
3124
         * Useful for parameterizedTypes, or classInstance.
3125
         *
3126
         * @param isClass we are sure that the type is actually a class
3127
         * @return a famix type or null
3128
         */
3129
        public <T extends TWithTypes & TNamedEntity> TType referredType(org.eclipse.jdt.core.dom.Type typ, T ctxt, boolean isClass) {
3130
                return this.referredType(typ, ctxt, isClass, /*isExcep*/false);
7 ✔
3131
        }
3132
        
3133
        /**
3134
         * Ensures the proper creation of a FamixType for JDT type in the given context.
3135
         * Useful for parameterizedTypes, or classInstance.
3136
         *
3137
         * @param isClass we are sure that the type is actually a class
3138
         * @return a famix type or null
3139
         */
3140
        public <T extends TWithTypes & TNamedEntity> TType referredType(org.eclipse.jdt.core.dom.Type typ, T ctxt, boolean isClass, boolean isException) {
3141
                if (typ == null) {
2 !
3142
                        return null;
×
3143
                } else if (typ.resolveBinding() != null) {
3 !
3144
                        return this.referredType(typ.resolveBinding(), ctxt);
7 ✔
3145
                }
3146
                // from here, we assume the owner is the context
3147
                else if (isClass && !isException) {
×
3148
                        return this.ensureFamixClass(null, findTypeName(typ), /*owner*/ctxt, /*isGeneric*/false,
×
3149
                                        EntityDictionary.UNKNOWN_MODIFIERS);
3150
                } else if (isException) {
×
3151
                        // return ensure FamixException
3152
                        return this.ensureFamixException(null, findTypeName(typ), (ContainerEntity) /*owner*/ctxt, /*isGeneric*/false,
×
3153
                                        EntityDictionary.UNKNOWN_MODIFIERS);
3154
                } else {
3155
                        while (typ.isArrayType()) {
×
3156
                                typ = ((ArrayType) typ).getElementType();
×
3157
                        }
3158

3159
                        if (typ.isPrimitiveType()) {
×
3160
                                return this.ensureFamixPrimitiveType(null, findTypeName(typ));
×
3161
                        } else {
3162
                                return this.ensureFamixType(null, findTypeName(typ), /*owner*/ctxt, /*container*/ctxt,
×
3163
                                                EntityDictionary.UNKNOWN_MODIFIERS);
3164
                        }
3165
                }
3166
        }
3167
        
3168
        public TType referredType(ITypeBinding bnd, TNamedEntity ctxt) {
3169
                return this.referredType(bnd, ctxt, 0);
6 ✔
3170
        }
3171
        
3172
        public TType referredType(ITypeBinding bnd, TNamedEntity ctxt, int extraDimensions) {
3173
                TType fmxTyp = null;
2 ✔
3174

3175
                if (bnd == null) {
2 ✔
3176
                        return null;
2 ✔
3177
                }
3178

3179
                String name;
3180
                //Three cases here:
3181
                // - the type binding knows it's an array
3182
                // - the binding is not declared as array, but it has dimensions > 0
3183
                // - the dimension is not in the type but in the variable declaration (thus extra)
3184
                if (bnd.isArray() || bnd.getDimensions() + extraDimensions > 0) {
8 ✔
3185
                        // We treat array types as parametrized types Array<T>.
3186
                        // This keeps the meta-model simple: a single way to model different concepts.
3187
                        return this.ensureParametricArrayClass();
3 ✔
3188
                }
3189
                name = bnd.getName();
3 ✔
3190

3191
                if ( bnd.isParameterizedType() ) {
3 ✔
3192
                        
3193
                        // remove type parameters from the name even for parameterized interfaces
3194
                        int i = name.indexOf('<');
4 ✔
3195
                        if (i > 0) {
2 ✔
3196
                                name = name.substring(0, i);
5 ✔
3197
                        }
3198

3199
                        ITypeBinding parameterizableBnd = bnd.getErasure();
3 ✔
3200
                        int modifiers = (parameterizableBnd != null) ? parameterizableBnd.getModifiers() : EntityDictionary.UNKNOWN_MODIFIERS;
6 !
3201
                        
3202
                        if(parameterizableBnd != null && parameterizableBnd.isInterface()) {
5 !
3203
                                fmxTyp = (ParametricInterface) this.ensureFamixInterface(parameterizableBnd, name, /*owner*/null, /*isGeneric*/true, modifiers);
10 ✔
3204
                        } else {
3205
                                fmxTyp = (ParametricClass) this.ensureFamixClass(parameterizableBnd, name, /*owner*/null, /*isGeneric*/true, modifiers);
9 ✔
3206
                        }
3207
                } else if ( (name != null) && name.equals("var") ) {
7 !
3208
                        fmxTyp = this.ensureFamixUniqEntity(org.moosetechnology.model.famix.famixjavaentities.Type.class, /*binding*/null, EntityDictionary.IMPLICIT_VAR_TYPE_NAME);        
×
3209
                } else {
3210
                        fmxTyp = this.ensureFamixType(bnd, name, /*owner*/null, (TWithTypes) ctxt, bnd.getModifiers());
10 ✔
3211
                }
3212

3213
                return fmxTyp;
2 ✔
3214
        }
3215

3216
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc