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

moosetechnology / VerveineJ / 24243549624

10 Apr 2026 12:44PM UTC coverage: 52.119% (+0.08%) from 52.035%
24243549624

push

github

web-flow
Merge pull request #206 from guillep/array

Array support

1980 of 3988 branches covered (49.65%)

Branch coverage included in aggregate %.

77 of 108 new or added lines in 5 files covered. (71.3%)

2 existing lines in 1 file now uncovered.

4403 of 8259 relevant lines covered (53.31%)

2.16 hits per line

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

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

3
import java.util.*;
4

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

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

56
/**
57
 * A dictionary of FamixJava entities to help create them and find them back
58
 * Entities are mapped to keys which are the "binding" provided by the JDT pars
59
 * 
60
 * @author anquetil
61
 */
62
public class EntityDictionary {
63

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

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

82
        public static final int UNKNOWN_MODIFIERS = 0;
83
        public static final String MODIFIER_PUBLIC   = "public";
84
        public static final String MODIFIER_PRIVATE  = "private";
85
        public static final String MODIFIER_PROTECTED= "protected";
86
        public static final String MODIFIER_PACKAGE = "package";
87

88
    /**
89
     * The symbol kind to use to define that a method is a default implementation in an interface
90
     */
91
    public static final String DEFAULT_IMPLEMENTATION_KIND_MARKER = "default";
92

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

98
        /**
99
         * The FAMIX repository where all FAMIX entities are created and stored
100
         */
101
        protected Repository famixRepo;
102

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

112
        /**
113
         * Another dictionary to map a name to FAMIX Entities with this name
114
         */
115
        protected Map<String,Collection<TNamedEntity>> nameToEntity;
116

117
        /**
118
         * Yet another dictionary for implicit variables ('self' and 'super')
119
         * Because they are implicit, they may not have a binding provided by the parser,
120
         * or may have the same binding as their associated type so they can't be kept easily in {@link #keyToEntity}
121
         */
122
        @Deprecated
123
        protected Map<Type,ImplicitVars> typeToImpVar;
124

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

142

143
        /** Constructor taking a FAMIX repository
144
         * @param famixRepo
145
         */
146
        public EntityDictionary(Repository famixRepo) {
2✔
147
                        this.famixRepo = famixRepo;
3✔
148
                        
149
                        this.keyToEntity = new Hashtable<IBinding,TNamedEntity>();
5✔
150
                        this.entityToKey = new Hashtable<TNamedEntity,IBinding>();
5✔
151
                        this.nameToEntity = new Hashtable<String,Collection<TNamedEntity>>();
5✔
152
                        this.typeToImpVar = new Hashtable<Type,ImplicitVars>();
5✔
153
                        
154
                        if (! this.famixRepo.isEmpty()) {
4✔
155
                                recoverExistingRepository();
2✔
156
                        }
157
                }
1✔
158

159
    /**
160
         * Resets the dictionnary in a proper state after loading entities from an existing MSE file:
161
         * <UL>
162
         * <li>map all named entities to their names in <b>mapName</b></li>
163
         * <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>
164
         * </ul>
165
         */
166
        protected void recoverExistingRepository() {
167
                for (NamedEntity ent : famixRepo.all(NamedEntity.class)) {
13✔
168
                        try {
169
                                mapEntityToName(ent.getName(), ent);
5✔
170
                        } catch (java.lang.Exception e) {
×
171
                                System.err.println("Error recovering entity " + ent.getName() + " from repository " + famixRepo);
×
172
                        };
1✔
173
                        // for the Exception to be raised, the return value must be tested
174
                        try { if (((TCanBeStub) ent).getIsStub()) {} }
5✔
175
                        catch (NullPointerException e) { ((TCanBeStub)ent).setIsStub(Boolean.FALSE); }
6✔
176
                }
1✔
177

178
                for (Access acc : famixRepo.all(Access.class)) {
13✔
179
                        // for the Exception to be raised, the return value must be tested
180
                        try { if (acc.getIsWrite()) {}        }
4✔
181
                        catch (NullPointerException e) { acc.setIsWrite(Boolean.FALSE); }
5✔
182
                }
1✔
183
        }
1✔
184

185
        protected void mapEntityToName(String name, TNamedEntity ent) {
186
                
187
                Collection<TNamedEntity> l_ent = nameToEntity.get(name);
6✔
188
                if (l_ent == null) {
2✔
189
                        l_ent = new LinkedList<>();
4✔
190
                }
191
                l_ent.add(ent);
4✔
192
                nameToEntity.put(name, l_ent);
6✔
193
        }
1✔
194

195
        public void removeEntity( NamedEntity ent) {
196
                IBinding key;
197
                key = entityToKey.get(ent);
6✔
198
                if (key != null) {
2✔
199
                        entityToKey.remove(ent);
5✔
200
                        keyToEntity.remove(key);
5✔
201
                }
202

203
                Collection<TNamedEntity> l_ent = nameToEntity.get(ent.getName());
7✔
204
                if (l_ent != null) {
2✔
205
                        l_ent.remove(ent);
4✔
206
                }
207

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

239
                return ret;
2✔
240
        }
241

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

259
        /**
260
         * Returns the key associated to a Famix Entity.
261
         * @param e -- the Named entity
262
         * @return the key associated to this entity or null if none
263
         */
264
        public IBinding getEntityKey(TNamedEntity e) {
265
                return entityToKey.get(e);
6✔
266
        }
267

268
        /**
269
         * Creates and returns a FAMIX Entity of the type <b>fmxjava.lang.Class</b>.
270
         * The Entity is always created.
271
         * @param fmxClass -- the FAMIX class of the instance to create
272
         * @param name -- the name of the new instance must not be null (and this is not tested)
273
         * @return the FAMIX Entity or null in case of a FAMIX error
274
         */
275
        protected <T extends TNamedEntity & TSourceEntity> T createFamixEntity(java.lang.Class<T> fmxClass, String name) {
276
                T fmx = null;
2✔
277

278
                if (name == null) {
2!
279
                        return null;
×
280
                }
281
                
282
                try {
283
                        fmx = fmxClass.getDeclaredConstructor().newInstance();
9✔
284
                } catch (java.lang.Exception e) {
×
285
                        System.err.println("Unexpected error, could not create a FAMIX entity: "+e.getMessage());
×
286
                        e.printStackTrace();
×
287
                }
1✔
288
                
289
                if (fmx != null) {
2!
290
                        fmx.setName(name);
3✔
291
                        if (fmx instanceof TCanBeStub) {
3!
292
                                ((TCanBeStub)fmx).setIsStub(Boolean.TRUE);
4✔
293
                        }
294

295
                        mapEntityToName(name, fmx);
4✔
296
                        
297
                        // put new entity in Famix repository
298
                        famixRepoAdd((Entity) fmx);
4✔
299
                }
300

301
                return fmx;
2✔
302
        }
303
        
304
        /**
305
         * Returns a Famix Entity of the type <b>fmxjava.lang.Class</b> and maps it to its binding <b>bnd</b> (if not null).
306
         * The Entity is created if it did not exist.
307
         * @param fmxClass -- the Famix class of the instance to create
308
         * @param bnd -- the binding to map to the new instance
309
         * @param name -- the name of the new instance (used if <pre>{@code bnd == null}</pre>)
310
         * @return the Famix Entity or null if <b>bnd</b> was null or in case of a Famix error
311
         */
312
        @SuppressWarnings("unchecked")
313
        protected <T extends TNamedEntity & TSourceEntity> T ensureFamixEntity(java.lang.Class<T> fmxClass, IBinding bnd, String name) {
314
                T fmx = null;
2✔
315
                
316
                /* 
317
                 * Unfortunately different entities with the same name and same type may exist
318
                 * e.g. 2 parameters of 2 different methods but having the same name
319
                 * so we cannot recover just from the name
320
                 */
321

322
                if (bnd != null) {
2✔
323
                        fmx = (T) getEntityByKey(bnd);
4✔
324
                        if (fmx != null) {
2✔
325
                                return fmx;
2✔
326
                        }
327
                }
328

329
                // else
330
                fmx = createFamixEntity(fmxClass, name);
5✔
331
                if ( (bnd != null) && (fmx != null) ) {
4!
332
                        keyToEntity.put(bnd, fmx);
6✔
333
                        entityToKey.put(fmx, bnd);
6✔
334
                }
335
                
336
                return fmx;
2✔
337
        }
338

339
        /**
340
         * Adds an already created Entity to the Famix repository
341
         * Used mainly for non-NamedEntity, for example relationships
342
         * @param e -- the Famix entity to add to the repository
343
         */
344
        public void famixRepoAdd(Entity e) {
345
                this.famixRepo.add(e);
4✔
346
        }
1✔
347

348

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

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

394
        public AnnotationInstanceAttribute createFamixAnnotationInstanceAttribute(AnnotationTypeAttribute att, String value) {
395
                AnnotationInstanceAttribute fmx = null;
2✔
396
                if ( (att != null) && (value != null) ) {
4!
397
                        fmx = new AnnotationInstanceAttribute();
4✔
398
                        fmx.setAnnotationTypeAttribute(att);
3✔
399
                        fmx.setValue(value);
3✔
400
                        this.famixRepo.add(fmx);
4✔
401
                }
402
                return fmx;
2✔
403
        }
404

405
        public AnnotationInstance addFamixAnnotationInstance(TWithAnnotationInstances fmx, AnnotationType annType, Collection<AnnotationInstanceAttribute> annAtts) {
406
                AnnotationInstance inst = null;
2✔
407
                if ( (fmx != null) && (annType != null) ) {
4!
408
                        inst = new AnnotationInstance();
4✔
409
                        inst.setAnnotatedEntity(fmx);
3✔
410
                        inst.setAnnotationType(annType);
3✔
411
                        inst.addAttributes(annAtts);
3✔
412
                        this.famixRepo.add(inst);
4✔
413
                }
414
                return inst;
2✔
415
        }
416

417
        ///// ensure Famix Relationships /////
418

419
        /**
420
         * Returns a Famix Inheritance relationship between two Famix Classes creating it if needed
421
         * @param sup -- the super class
422
         * @param sub -- the sub class
423
         * @param prev -- previous inheritance relationship in the same context
424
         * @return the Inheritance relationship
425
         */
426
        public Inheritance ensureFamixInheritance(TWithInheritances sup, TWithInheritances sub, TAssociation prev, ITypeBinding supBnd) {
427
                if ( (sup == null) || (sub == null) ) {
4!
428
                        return null;
×
429
                }
430

431
                // Does the inheritance already exist?
432
                for (TInheritance i : (sup).getSubInheritances()) {                        
11✔
433
                        if (i.getSubclass() == sub) {
4✔
434
                                return (Inheritance) i;
3✔
435
                        }
436
                }
1✔
437

438
                Inheritance inh;
439
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5✔
440
                        inh = (ParametricInheritance)buildFamixParametricAssociation(new ParametricInheritance(), supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
13✔
441
                } else {
442
                        inh = new Inheritance();
4✔
443
                }
444

445
                inh.setSuperclass(sup);
3✔
446
                inh.setSubclass(sub);
3✔
447
                chainPrevNext(prev, inh);
4✔
448
                famixRepoAdd(inh);
3✔
449
                return inh;
2✔
450
        }
451
        
452
        /**
453
         * Creates the concretization between the type parameters of the generic entity that is target of an association 
454
         * and the concrete types that concretize them in this association.
455
         * @param association -- the association that must be linked to # or several concretizations
456
         * @param typeParameters -- the collection of type parameters declared in the generic entity
457
         * @param typeArguments -- the collection of concrete types linked to this association
458
         * @return the parametric association
459
         */
460
        public  <T extends TParametricEntity> TParametricAssociation buildFamixParametricAssociation(TParametricAssociation association, ITypeBinding[] typeParameters, ITypeBinding[] typeArguments
461
        ) {
462
                
463
                Iterator<ITypeBinding> genericIterator = Arrays.asList(typeParameters).iterator();
4✔
464
                Iterator<ITypeBinding> concreteIterator = Arrays.asList(typeArguments).iterator();
4✔
465

466
                while (concreteIterator.hasNext() && genericIterator.hasNext()) {
6!
467
                        TTypeArgument typeArgument = (TTypeArgument)ensureFamixType(concreteIterator.next());
7✔
468
                        TypeParameter typeParameter = (TypeParameter)ensureFamixType(genericIterator.next());
7✔
469

470
                        Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5✔
471
                        association.addConcretization(concretization);
3✔
472
                }
1✔
473

474
                return association;
2✔
475
        }
476

477
        /**
478
         * Returns a Famix Concretization relationship between a Concrete Type and a ParameterType
479
         * @param typeArgument -- the concrete type
480
         * @param typeParameter -- the generic type parameter
481
         * @return the Concretization relationship
482
         */
483
        public Concretization ensureFamixConcretization(TTypeArgument typeArgument, TypeParameter typeParameter ) {
484
                if ( (typeArgument == null) || (typeParameter == null) ) {
4!
485
                        return null;
×
486
                }
487

488
                Concretization concretization = new Concretization();
4✔
489
                concretization.setTypeArgument(typeArgument);
3✔
490
                concretization.setTypeParameter(typeParameter);
3✔
491

492
                famixRepoAdd(concretization);
3✔
493
                return concretization;
2✔
494
        }
495
        
496
                /**
497
         * Returns a Famix Implementation relationship between two Famix Classes creating it if needed
498
         * @param myInterface -- the implemented interface
499
         * @param implementingClass -- the implementing class
500
         * @param prev -- previous inheritance relationship in the same context
501
         * @return the Inheritance relationship
502
         */
503
        public Implementation ensureFamixImplementation(TImplementable myInterface, TCanImplement implementingClass, TAssociation prev, ITypeBinding supBnd) {
504
                if ( (myInterface == null) || (implementingClass == null) ) {
4!
505
                        return null;
×
506
                }
507

508
                for (TImplementation imp : myInterface.getImplementations()) {
11✔
509
                        if (imp.getImplementingClass() == implementingClass) {
4✔
510
                                return (Implementation) imp;
3✔
511
                        }
512
                }
1✔
513
                
514
                Implementation implementation;
515
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5!
516
                        implementation = (ParametricImplementation)buildFamixParametricAssociation(new ParametricImplementation(), supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
13✔
517
                } else {
518
                        implementation = new Implementation();
4✔
519
                }
520

521
                implementation.setImplementingClass(implementingClass);
3✔
522
                implementation.setMyInterface(myInterface);
3✔
523
                chainPrevNext(prev, implementation);
4✔
524
                famixRepoAdd(implementation);
3✔
525
                return implementation;
2✔
526
        }
527

528
        public void ensureImplementedInterfaces(ITypeBinding bnd, TType fmx, TWithTypes owner, TAssociation lastAssociation) {
529
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17✔
530
                        Type superTyp;
531
                        if(intbnd.isClass()){
3✔
532
                                superTyp = this.ensureFamixInterface(intbnd, intbnd.getName(), null, intbnd.isGenericType() || intbnd.isParameterizedType() || intbnd.isRawType(), intbnd.getModifiers());
20!
533
                        }else {
534
                                superTyp = this.ensureFamixType(intbnd);
4✔
535
                        }
536
                        
537
                        if (bnd.isInterface()) {
3✔
538
                                // in Java "subtyping" link between 2 interfaces is call inheritance 
539
                                lastAssociation = ensureFamixInheritance((TWithInheritances)superTyp, (TWithInheritances)fmx, lastAssociation, intbnd);
10✔
540
                        }
541
                        else {
542
                                lastAssociation = ensureFamixImplementation((TImplementable)superTyp, (TCanImplement)fmx, lastAssociation, intbnd);
9✔
543
                        }
544
                }
545
        }
1✔
546

547
        /**
548
         * Returns a Famix Reference between two Famix Entities creating it if needed.<br>
549
         * 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
550
         * @param src -- source of the reference
551
         * @param tgt -- target of the reference
552
         * @param prev -- previous reference relationship in the same context
553
         * @return the FamixReference
554
         */
555
        public Reference addFamixReference(Method src, TType tgt, TAssociation prev, ITypeBinding referredTypeBnd) {
556
                Reference ref = null;
2✔
557
                
558
                if ( (src == null) || (tgt == null) ) {
4!
559
                        return null;
×
560
                }
561

562
                if (prev == null) {
2✔
563
                        for (TReference existingRef : src.getOutgoingReferences()) {
7!
564
                                if (existingRef.getReferredEntity() == tgt) {
×
565
                                        return (Reference) existingRef;
×
566
                                }
567
                        }
×
568
                }
569

570
                if (referredTypeBnd != null) {
2✔
571
                        if (referredTypeBnd.isParameterizedType()) {
3✔
572
                                ref = (ParametricReference)buildFamixParametricAssociation(new ParametricReference(), referredTypeBnd.getErasure().getTypeParameters(), referredTypeBnd.getTypeArguments());
13✔
573
                        } else if (referredTypeBnd.isArray()) {
3✔
574
                                ref = new ParametricReference();
4✔
575
                        
576
                                TTypeArgument typeArgument  = (TTypeArgument)ensureFamixType(referredTypeBnd.getElementType());
6✔
577
                                TypeParameter typeParameter = (TypeParameter) ((TParametricEntity)tgt).getTypeParameters().iterator().next();
7✔
578

579
                                Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5✔
580
                                ((ParametricReference)ref).addConcretization(concretization);
4✔
581
                        }
582
                }
583

584
                if (ref == null){
2✔
585
                        ref = new Reference();
4✔
586
                }
587

588
                ref.setReferredEntity(tgt);
3✔
589
                ref.setReferencer(src);
3✔
590
                chainPrevNext(prev,ref);
4✔
591
                famixRepoAdd(ref);
3✔
592

593
                return ref;
2✔
594
        }
595

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

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

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

650
        protected void chainPrevNext(TAssociation prev, TAssociation next) {
651
                if (prev != null) {
2✔
652
                        next.setPrevious(prev);  // not yet implemented in importer
3✔
653
                }
654
        }
1✔
655
        
656
        /**
657
         * Returns a Famix DeclaredException between a method and an Exception that it declares to throw
658
         * @param meth -- the method throwing the exception
659
         * @param excep -- the exception declared to be thrown
660
         * @return the DeclaredException
661
         */
662
        public TThrowable createFamixDeclaredException(Method meth, TThrowable excep) {
663
                if ( (meth == null) || (excep == null) ) {
4!
664
                        return null;
×
665
                }
666
                meth.getDeclaredExceptions().add(excep);
5✔
667
                return excep;
2✔
668
        }
669

670
        /**
671
         * Returns a Famix CaughtException between a method and an Exception that is caught
672
         * @param meth -- the method catching the exception
673
         * @param excep -- the exception caught
674
         * @return the CaughtException
675
         */
676
        public TThrowable createFamixCaughtException(Method meth, TThrowable excep) {
677
                if ( (meth == null) || (excep == null) ) {
4!
678
                        return null;
×
679
                }
680
                meth.getCaughtExceptions().add(excep);
5✔
681
                return excep;
2✔
682
        }
683

684
        /**
685
         * Returns a Famix ThrownException between a method and an Exception that it (actually) throws.
686
         * Note: DeclaredException indicates that the method declares it can throw the exception,
687
         * here we state that the exception is actually thrown
688
         * @param meth -- the method throwing the exception
689
         * @param excep -- the exception thrown
690
         * @return the ThrownException
691
         */
692
        public TThrowable createFamixThrownException(Method meth, TThrowable excep) {
693
                if ( (meth == null) || (excep == null) ) {
4!
694
                        return null;
×
695
                }
696
                meth.getThrownExceptions().add(excep);
5✔
697
                return excep;
2✔
698
        }
699

700

701
        /**
702
         * Returns a Famix EntityTyping between a typed entity and a type.
703
         * @param typedEntity -- the typed entity
704
         * @param declaredType -- the declared type
705
         * @return the FamixEntityTyping
706
         */
707
        public EntityTyping ensureFamixEntityTyping(ITypeBinding declaredTypeBnd, TTypedEntity typedEntity, TType declaredType) {
708
                if ( (typedEntity == null) || (declaredType == null) ) {
4!
709
                        return null;
2✔
710
                }
711
                EntityTyping typing = null;
2✔
712
                
713
                if (declaredTypeBnd != null) {
2✔
714
                        if (declaredTypeBnd.isParameterizedType()) {
3✔
715
                                typing = (ParametricEntityTyping)buildFamixParametricAssociation(new ParametricEntityTyping(), declaredTypeBnd.getErasure().getTypeParameters(), declaredTypeBnd.getTypeArguments());
13✔
716
                        }else if (declaredTypeBnd.isArray()) {
3✔
717
                                typing = new ParametricEntityTyping();
4✔
718
                                
719
                                TTypeArgument typeArgument  = (TTypeArgument)ensureFamixType(declaredTypeBnd.getElementType());
6✔
720
                                TypeParameter typeParameter = (TypeParameter) ((ParametricClass)declaredType).getTypeParameters().iterator().next();
7✔
721

722
                                Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5✔
723
                                ((ParametricEntityTyping)typing).addConcretization(concretization);
4✔
724
                        }
725
                }
726

727
                // If we did not set a typing because not parameterized nor array, set a default one
728
                if (typing == null) {
2✔
729
                        typing = new EntityTyping();
4✔
730
                }
731
                
732
                typing.setTypedEntity(typedEntity);
3✔
733
                typing.setDeclaredType(declaredType);
3✔
734
                famixRepoAdd(typing);
3✔
735
                
736
                return typing;
2✔
737
        }
738

739

740
        ///// Special Case: ImplicitVariables /////
741

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

775
                return ret;
×
776
        }
777

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

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

817
                return fmx;
2✔
818
        }
819

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

832
                return fmx;
2✔
833
        }
834

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

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

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

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

886
                return fmx;
2✔
887
        }
888

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

899
        /**
900
         * Creates or recovers a Famix Package for the package of Java class "Object" (i.e. "java.lang").
901
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
902
         *
903
         * @param bnd -- a potential binding for the "java.lang" package
904
         * @return a Famix Namespace for "java.lang"
905
         */
906
        public Package ensureFamixPackageJavaLang(IPackageBinding bnd) {
907

908
        return this.ensureFamixPackage(bnd, OBJECT_PACKAGE_NAME);
5✔
909
        }
910

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

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

935
                if (bnd == null) {
2!
UNCOV
936
                        if (name == null) {
×
UNCOV
937
                                return null;
×
938
                        }
939
                        fmx = searchTypeInContext(name, ctxt); // WildCard Types don't have binding
×
940
                        if (fmx != null) {
×
941
                                return fmx;
×
942
                        }
943

944
                        if ((owner instanceof TParametricEntity)) {
×
945
                                return this.ensureFamixTypeParameter(null, name, owner);
×
946
                        }
947
                        else {
948
                                fmx = ensureFamixEntity(Type.class, bnd, name);
×
949
                                fmx.setTypeContainer(owner);
×
950
                                return fmx;
×
951
                        }
952
                }
953

954
                // bnd != null
955

956
                fmx = (Type) getEntityByKey(bnd);
5✔
957
                if (fmx != null) {
2✔
958
                        return fmx;
2✔
959
                }
960

961
                if (bnd.isArray()) {
3!
962
                        bnd = bnd.getElementType();
×
963
                }
964

965
                if (bnd.isPrimitive()) {
3✔
966
                        return this.ensureFamixPrimitiveType(bnd, name);
5✔
967
                }
968

969
                if (bnd.isEnum()) {
3!
970
                        return this.ensureFamixEnum(bnd, name, owner);
×
971
                }
972
 
973
                if ((bnd.isRawType() || bnd.isGenericType()) && !bnd.isInterface() ) {
9✔
974
                        return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
10✔
975
                }
976

977
                if (bnd.isCapture()) {
3✔
978
                        if (bnd.getErasure().isInterface()) {
4!
979
                                return this.ensureFamixInterface(bnd.getErasure(), name, owner, /*isGeneric*/true, modifiers);
9✔
980
                        }
981
                        else {
982
                                return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
×
983
                        }
984
                }
985

986
                if (bnd.isAnnotation()) {
3!
987
                        return this.ensureFamixAnnotationType(bnd, name, (ContainerEntity) owner);
×
988
                }
989

990
                if (bnd.isInterface()) {
3✔
991
                        return this.ensureFamixInterface(bnd, name, owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
19✔
992
                }
993

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

1004
                //otherwise (none of the above)
1005

1006
                if (name == null) {
2✔
1007
                        name = bnd.getName();
3✔
1008
                }
1009

1010
                if (owner == null) {
2!
1011
                        owner = (TWithTypes) this.ensureOwner(bnd);
5✔
1012
                }
1013

1014
                if (bnd.isTypeVariable() ) {
3!
1015
                        fmx = ensureFamixTypeParameter(bnd, name, owner);
6✔
1016
                        return fmx;
2✔
1017
                }
1018

1019
                fmx = ensureFamixEntity(Type.class, bnd, name);
×
1020
                fmx.setTypeContainer(owner);
×
1021
                return fmx;
×
1022
        }
1023

1024
        public Type ensureFamixType(ITypeBinding bnd, TWithTypes context) {
1025
        int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
6!
1026
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8✔
1027
        }
1028
        
1029
        public Type ensureFamixType(ITypeBinding bnd) {
1030
                return ensureFamixType(bnd, /*ctxt*/null);
5✔
1031
        }
1032

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

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

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

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

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

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

1097
        // If we have java.lang.Object we should ensure we create this class
1098
        if (bnd != null && bnd.getQualifiedName().equals("java.lang.Object")) {
7✔
1099
                        return ensureFamixClassObject();
3✔
1100
                }
1101

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

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

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

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

1139
                        TAssociation lastAssoc = null;
2✔
1140

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

1153
                return fmx;
2✔
1154
        }
1155

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

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

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

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

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

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

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

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

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

1242
        return fmx;
2✔
1243
        }
1244

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

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

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

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

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

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

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

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

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

1335
        /**
1336
         * "Converts" (if needed) a TTYpe entity to be a TThrowable. Might involve removing the existing entity, recreating a new one and migrating
1337
         * all the relationship of the former to the later
1338
         */
1339
        public TThrowable asException(TType fmxType) {
1340
                if (fmxType instanceof Exception) {
3✔
1341
                        return (Exception) fmxType;
3✔
1342
                }
1343
                if(fmxType instanceof TypeParameter) {
3✔
1344
                        return (TypeParameter) fmxType;
3✔
1345
                }
1346

1347
                Exception fmxException = null;
2✔
1348
                IBinding key;
1349

1350
                try {
1351
                        key = entityToKey.get(fmxType);
6✔
1352

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

1357
                        TWithTypes owner = fmxType.getTypeContainer();
3✔
1358
                        fmxType.setTypeContainer(null);
3✔
1359
                        fmxException = ensureFamixException((ITypeBinding) key, fmxType.getName(), owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
10✔
1360

1361
                        fmxException.addMethods( new ArrayList<>( ((TWithMethods)fmxType).getMethods() ) );
8✔
1362
                        if (fmxType instanceof TWithAttributes) {
3!
1363
                                fmxException.addAttributes( new ArrayList<>( ((TWithAttributes)fmxType).getAttributes() ) );
8✔
1364
                        }
1365

1366
                        if (fmxType instanceof TWithInheritances) {
3!
1367
                                fmxException.addSuperInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSuperInheritances() ) );
8✔
1368
                                fmxException.addSubInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSubInheritances() ) );
8✔
1369
                        }
1370
                        fmxException.setComments(new ArrayList<>( ((TWithComments) fmxType).getComments() ));
8✔
1371
                        fmxException.setSourceAnchor(fmxType.getSourceAnchor());
4✔
1372
                        fmxException.addIncomingTypings( new ArrayList<>( fmxType.getIncomingTypings() ) );
7✔
1373
                        fmxException.addAnnotationInstances( new ArrayList<>( ((NamedEntity)fmxType).getAnnotationInstances() ) );
8✔
1374
                        fmxException.addIncomingReferences( new ArrayList<>( fmxType.getIncomingReferences() ) );
7✔
1375
                        fmxException.setIsStub(fmxType.getIsStub());
4✔
1376
                        fmxException.addTypes( new ArrayList<>( ((ContainerEntity) fmxType).getTypes() ) );
8✔
1377
                }
1378
                catch( ConcurrentModificationException e) {
×
1379
                        e.printStackTrace();
×
1380
                }
1✔
1381

1382
                return fmxException;
2✔
1383
        }
1384

1385
        /**
1386
         * helper method, we know the type exists, ensureFamixClass will recover it
1387
         */
1388
        public Class getFamixClass(ITypeBinding bnd, String name, TNamedEntity owner) {
1389
                return ensureFamixClass(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1390
        }
1391

1392
        /**
1393
         * helper method, we know the type exists, ensureFamixInterface will recover it
1394
         */
1395
        public Interface getFamixInterface(ITypeBinding bnd, String name, ContainerEntity owner) {
1396
                return ensureFamixInterface(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1397
        }
1398

1399
        /**
1400
         * helper method, we know the type exists, ensureFamixInterface will recover it
1401
         */
1402
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1403
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1404
        }
1405

1406
        /**
1407
         * Ensures a famix entity for the owner of a binding.<br>
1408
         * This owner can be a method, a class or a namespace
1409
         * @param bnd -- binding for the owned entity
1410
         * @return a famix entity for the owner
1411
         */
1412
        private TNamedEntity ensureOwner(ITypeBinding bnd) {
1413
                TNamedEntity owner;
1414
                IMethodBinding parentMtd = bnd.getDeclaringMethod();
3✔
1415
                if (parentMtd != null) {
2✔
1416
                        owner = this.ensureFamixMethod(parentMtd);  // cast needed to desambiguate the call
5✔
1417
                }
1418
                else {
1419
                        ITypeBinding parentClass = bnd.getDeclaringClass();
3✔
1420
                        if (parentClass != null) {
2✔
1421
                owner = this.ensureFamixType(parentClass);
5✔
1422
            }
1423
                        else {
1424
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1425
                                if (parentPckg != null) {
2!
1426
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1427
                                } else {
1428
                                        owner = this.ensureFamixPackageDefault();
×
1429
                                }
1430
                        }
1431
                }
1432
                return owner;
2✔
1433
        }
1434

1435

1436
        /**
1437
         * Returns a FAMIX PrimitiveType with the given <b>name</b>, creating it if it does not exist yet
1438
         * We assume that PrimitiveType must be uniq for a given name
1439
         * @param name -- the name of the FAMIX PrimitiveType
1440
         * @return the FAMIX PrimitiveType or null in case of a FAMIX error
1441
         */
1442
        public PrimitiveType ensureFamixPrimitiveType(ITypeBinding bnd, String name) {
1443
                if (name == null) {
2✔
1444
                        if (bnd == null) {
2!
1445
                                return null;
×
1446
                        } else {
1447
                                name = bnd.getName();
3✔
1448
                        }
1449
                }
1450
                return ensureFamixUniqEntity(PrimitiveType.class, bnd, name);
7✔
1451
        }
1452

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

1456
                // --------------- to avoid useless computations if we can
1457
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5✔
1458
                if (fmx != null) {
2✔
1459
                        return fmx;
2✔
1460
                }
1461

1462
                // --------------- name
1463
                if (name == null) {
2✔
1464
                        if (bnd == null) {
2!
1465
                                return null;
×
1466
                        }
1467
                        else {
1468
                                name = bnd.getName();
3✔
1469
                        }
1470
                }
1471

1472
                // --------------- owner
1473
                if (owner == null) {
2✔
1474
                        if (bnd == null) {
2!
1475
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1476
                        } else {
1477
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1478
                        }
1479
                }
1480

1481
                // --------------- recover from name ?
1482
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9!
1483
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
1484
                                fmx = candidate;
×
1485
                                break;
×
1486
                        }
1487
                }
×
1488

1489
                if (fmx == null) {
2!
1490
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7✔
1491
                        fmx.setTypeContainer(owner);
3✔
1492
                }
1493

1494
                if (bnd != null) {
2!
1495
                        setVisibility(fmx, bnd.getModifiers());
5✔
1496
                }
1497

1498
                return fmx;
2✔
1499
        }
1500

1501
        /**
1502
         * helper method, we know the type exists, ensureFamixEnum will recover it
1503
         */
1504
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1505
                return ensureFamixEnum(bnd, name, owner);
6✔
1506
        }
1507

1508
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1509
                EnumValue fmx;
1510

1511
                // --------------- to avoid useless computations if we can
1512
                fmx = (EnumValue)getEntityByKey(bnd);
5✔
1513
                if (fmx != null) {
2✔
1514
                        return fmx;
2✔
1515
                }
1516

1517
                // --------------- name
1518
                if (name == null) {
2!
1519
                        if (bnd == null) {
×
1520
                                return null;
×
1521
                        }
1522
                        else {
1523
                                name = bnd.getName();
×
1524
                        }
1525
                }
1526

1527
                // --------------- owner
1528
                if (owner == null) {
2✔
1529
                        if (bnd == null) {
2!
1530
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1531
                        }
1532
                        else {
1533
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7✔
1534
                        }
1535
                }
1536

1537
                // --------------- recover from name ?
1538
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9!
1539
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
1540
                                fmx = candidate;
×
1541
                                break;
×
1542
                        }
1543
                }
×
1544
                if (fmx == null) {
2!
1545
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7✔
1546
                        fmx.setParentEnum(owner);
3✔
1547
                }
1548

1549
        fmx.setParentEnum(owner);
3✔
1550

1551
        return fmx;
2✔
1552
        }
1553

1554
    /**
1555
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1556
         */
1557
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1558
                AnnotationType fmx;
1559

1560
                // --------------- to avoid useless computations if we can
1561
                fmx = (AnnotationType)getEntityByKey(bnd);
5✔
1562
                if (fmx != null) {
2✔
1563
                        return fmx;
2✔
1564
                }
1565

1566
                // --------------- name
1567
                if (name == null) {
2✔
1568
                        if (bnd == null) {
2!
1569
                                return null;
×
1570
                        }
1571
                        else {
1572
                                name = bnd.getName();
3✔
1573
                        }
1574
                }
1575

1576
                // --------------- owner
1577
                if (owner == null) {
2✔
1578
                        if (bnd == null) {
2!
1579
                                owner = ensureFamixPackageDefault();
×
1580
                        }
1581
                        else {
1582
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1583
                                if (parentPckg != null) {
2!
1584
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1585
                                } else {
1586
                                        owner = this.ensureFamixPackageDefault();
×
1587
                                }
1588
                        }
1589
                }
1590

1591
                // --------------- recover from name ?
1592
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13✔
1593
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7✔
1594
                                fmx = candidate;
2✔
1595
                                break;
1✔
1596
                        }
1597
                }
1✔
1598

1599
                // --------------- create
1600
                if (fmx == null) {
2✔
1601
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7✔
1602
                        fmx.setAnnotationTypesContainer(owner);
3✔
1603
                }
1604

1605
                if (bnd != null) {
2!
1606
                        // Not supported in Famix
1607

1608
                        // setVisibility(fmx, bnd.getModifiers());
1609
                }
1610

1611
                return fmx;
2✔
1612
        }
1613

1614
        /**
1615
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1616
         */
1617
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1618
                return ensureFamixAnnotationType(bnd, name, owner);
6✔
1619
        }
1620

1621
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1622
                AnnotationTypeAttribute fmx = null;
2✔
1623

1624
                // --------------- to avoid useless computations if we can
1625
                fmx = (AnnotationTypeAttribute)getEntityByKey(bnd);
5✔
1626
                if (fmx != null) {
2✔
1627
                        return fmx;
2✔
1628
                }
1629

1630
                // --------------- name
1631
                if (name == null) {
2!
1632
                        if (bnd == null) {
×
1633
                                return null;
×
1634
                        }
1635
                        else {
1636
                                name = bnd.getName();
×
1637
                        }
1638
                }
1639

1640
                // --------------- owner
1641
                if (owner == null) {
2!
1642
                        if (bnd == null) {
×
1643
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1644
                        }
1645
                        else {
1646
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
1647
                                if (parentType != null) {
×
1648
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1649
                                }
1650
                                else  {
1651
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1652
                                }
1653
                        }
1654
                }
1655

1656
                // --------------- recover from name ?
1657
                for (AnnotationTypeAttribute candidate : getEntityByName(AnnotationTypeAttribute.class, name) ) {
13✔
1658
                        // JDT treats annotation type attributes as methods ...
1659
                        // checkAndMapMethod wants a signature as 2nd argument so we add empty param list
1660
                        if ( (bnd != null) && matchAndMapMethod(bnd, name+"()", null, owner, candidate) ) {
11!
1661
                                fmx = candidate;
×
1662
                                break;
×
1663
                        }
1664
                        // if the binding is null, the annotationTypeAttribute migth have been created
1665
                        else if ( (bnd == null) && matchAndMapVariable(null, name, owner, candidate)) {
2!
1666
                                fmx = candidate;
×
1667
                                break;
×
1668
                        }
1669
                }
1✔
1670

1671
                if (fmx == null) {
2!
1672
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7✔
1673
                        fmx.setParentType(owner);
3✔
1674
                }
1675

1676
                if (bnd != null) {
2!
1677
                        // Not suopp
1678

1679
                        // setVisibility(fmx, bnd.getModifiers());
1680
                }
1681

1682
                return fmx;
2✔
1683
        }
1684

1685
        /**
1686
         * helper method, we know the attribute exists, ensureFamixAnnotationTypeAttribute will recover it
1687
         */
1688
        public AnnotationTypeAttribute getFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1689
                return ensureFamixAnnotationTypeAttribute( bnd, name, owner);
6✔
1690
        }
1691
        
1692
        
1693
        /**
1694
         * Returns a FAMIX Wildcard with its bounds
1695
         * @param bnd
1696
         * @param name
1697
         * @param owner
1698
         * @return
1699
         */
1700
        public Wildcard ensureFamixWildcardType(ITypeBinding bnd, String name, TParametricEntity owner, TWithTypes ctxt) {
1701
                Wildcard fmx = this.ensureFamixEntity(Wildcard.class, bnd, bnd.getName());
8✔
1702
                if(bnd.getBound() != null) {
3✔
1703
                        Type bound = this.ensureFamixType(bnd.getBound());
5✔
1704
                        if(bnd.isUpperbound()) {
3✔
1705
                                fmx.setUpperBound(bound);
3✔
1706
                                bound.addUpperBoundedWildcards(fmx);
4✔
1707
                        }else{
1708
                                fmx.setLowerBound(bound);
3✔
1709
                                bound.addLowerBoundedWildcards(fmx);
3✔
1710
                        }
1711
                }
1712
                return fmx;
2✔
1713
        }
1714

1715
        /**
1716
         * Returns a Famix TypeParameter (created by a Famix ParametricEntity) with the given <b>name</b>, creating it if it does not exist yet
1717
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public
1718
         * @param name -- the name of the Famix TypeParameter
1719
         * @return the Famix TypeParameter or null in case of a Famix error
1720
         */
1721
        public TypeParameter ensureFamixTypeParameter(ITypeBinding bnd,        String name, TWithTypes owner) {
1722
                TypeParameter fmx;
1723

1724
                // --------------- to avoid useless computations if we can
1725
                fmx = (TypeParameter)getEntityByKey(bnd);
5✔
1726
                if (fmx != null) {
2✔
1727
                        return fmx;
2✔
1728
                }
1729

1730
                // --------------- name
1731
                if (name == null) {
2✔
1732
                        if (bnd == null) {
2!
1733
                                return null;
×
1734
                        }
1735
                        else {
1736
                                name = bnd.getName();
3✔
1737
                        }
1738
                }
1739

1740
                // --------------- owner
1741
                if (owner == null && bnd != null) {
2!
1742
            if (bnd.getDeclaringClass() != null) {
×
1743
                owner = this.ensureFamixType(bnd.getDeclaringClass());
×
1744
            } else if(bnd.getDeclaringMethod() != null) {
×
1745
                owner = this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1746
            }
1747
                }
1748

1749
                // --------------- recover from name ?
1750
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13✔
1751
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8✔
1752
                                fmx = (TypeParameter) candidate;
3✔
1753
                                break;
1✔
1754
                        }
1755
                }
1✔
1756

1757
                // --------------- create
1758
                if (fmx == null) {
2✔
1759
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7✔
1760
                        if(bnd != null && bnd.getSuperclass() != null) {
5!
1761
                                Type upperBound = ensureFamixType(bnd.getSuperclass());
5✔
1762
                                fmx.setUpperBound(upperBound);
3✔
1763
                        }
1764
                        if(bnd != null) {
2✔
1765
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17✔
1766
                    Type upperBound = ensureFamixType(intbnd);
4✔
1767
                    fmx.setUpperBound(upperBound);
3✔
1768
                }
1769
            }
1770
                        fmx.setTypeContainer(owner);
3✔
1771
                }
1772

1773
                return fmx;
2✔
1774
        }
1775

1776
        /**
1777
         * Checks whether the existing unmapped Famix Namespace matches the binding.
1778
         * Checks that the candidate has the same name as the JDT bound package, and checks recursively that owners also match.
1779
         *
1780
         * @param bnd       -- a JDT binding that we are trying to match to the candidate
1781
         * @param name      of the package
1782
         * @param owner     of the package
1783
         * @param candidate -- a Famix Entity
1784
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1785
         */
1786
        private boolean matchAndMapPackage(IPackageBinding bnd, String name, Package owner, NamedEntity candidate) {
1787
                if (!(candidate instanceof Package)) {
3!
1788
                        return false;
×
1789
                }
1790

1791
                // check whether bnd and candidate are already bound
1792
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1793
                if (res == CheckResult.MATCH) {
3✔
1794
                        return true;
2✔
1795
                } else if (res == CheckResult.FAIL) {
3!
1796
                        return false;
×
1797
                }
1798

1799
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7✔
1800
                        return false;
2✔
1801
                }
1802

1803
                // names match, not need to look at owner because names of Namespaces are their fully qualified name
1804
                conditionalMapToKey(bnd, candidate);
4✔
1805
                return true;
2✔
1806
        }
1807

1808
        /**
1809
         * Checks whether the existing unmapped Famix Type matches the binding.
1810
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1811
         * We also check that the actual class of the candidate matches (can be a sub-class of FamixType).
1812
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1813
         * @param name of the type
1814
         * @param owner of the type
1815
         * @param candidate -- a Famix NamedEntity (Class, Type, PrimitiveType, Enum, AnnotationType)
1816
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1817
         */
1818
        private <T extends TWithTypes & TNamedEntity> boolean matchAndMapType(ITypeBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
1819
                if (! (candidate instanceof Type) ) {
3!
1820
                        return false;
×
1821
                }
1822

1823
                // check whether bnd and candidate are already bound
1824
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1825
                if (res == CheckResult.MATCH) {
3✔
1826
                        return true;
2✔
1827
                }
1828
                else if (res == CheckResult.FAIL) {
3✔
1829
                        return false;
2✔
1830
                }
1831

1832
                if ( (bnd != null) && (bnd.isArray()) ) {
5!
1833
                                bnd = bnd.getElementType();
×
1834
                }
1835

1836
                // checking names
1837
                if ( (bnd != null) && (bnd.isParameterizedType() || bnd.isRawType()) ) {
8!
1838
                        name = bnd.getErasure().getName();
×
1839
                }
1840
                else if (bnd != null) {
2✔
1841
                        name = bnd.getName();
3✔
1842
                }
1843
                // else name = name
1844
                if (checkNameMatch(null, name, candidate) == CheckResult.FAIL) {
7✔
1845
                        return false;
2✔
1846
                }
1847

1848
                // special case of primitive types
1849
                if (candidate instanceof PrimitiveType) {
3!
1850
                        if ( (bnd != null) && bnd.isPrimitive() ) {
×
1851
                                // names are equal so it's OK
1852
                                conditionalMapToKey(bnd, candidate);
×
1853
                                return true;
×
1854
                        }
1855
                        else if ( (bnd == null) && (owner == null) ) {
×
1856
                                return true;
×
1857
                        }
1858
                }
1859

1860
                // check owners without bnd
1861
                if (bnd == null) {
2✔
1862
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1863
                }
1864

1865
                // check owners with bnd
1866
                // type is an annotation
1867
                if (bnd.isAnnotation() && (candidate instanceof AnnotationType)) {
6!
1868
                        if (matchAndMapPackage(bnd.getPackage(), owner.getName(), (Package) Util.getOwner(owner), Util.getOwner(candidate))) {
13!
1869
                                conditionalMapToKey(bnd, candidate);
4✔
1870
                                return true;
2✔
1871
                        } else {
1872
                                return false;
×
1873
                        }
1874
                }
1875

1876
                // check owners with bnd
1877
                // type is a Parameterized type
1878
                if ((bnd.isParameterizedType() || bnd.isRawType()) && (candidate instanceof ParametricClass)) {
6!
1879
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1880
                }
1881

1882
                // check owners with bnd
1883
                // type is an Enum
1884
                if (bnd.isEnum() && (candidate instanceof Enum)) {
3!
1885
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1886
                }
1887

1888
                // check owners with bnd
1889
                // type is something elae (a class or interface)
1890
                // Annotation are interfaces too, so we should check this one after isAnnotation
1891
                if ( bnd.isClass()) {
3!
1892
                        return matchAndMapClass(bnd, name, owner, (Type) candidate);
×
1893
                }
1894

1895
                if(bnd.isInterface()) {
3!
1896
                        return matchAndMapInterface(bnd, name, owner, (Type) candidate);
×
1897
                }
1898

1899
                return false;
2✔
1900
        }
1901

1902
        /**
1903
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1904
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1905
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1906
         * @param name of the class
1907
         * @param owner of the class
1908
         * @param candidate -- a Famix Entity
1909
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1910
         */
1911
        private boolean matchAndMapClass(ITypeBinding bnd, String name, TNamedEntity owner, TType candidate) {
1912
                if (!(candidate instanceof Class)) {
3!
1913
                        return false;
×
1914
                }
1915

1916
                // check whether bnd and candidate are already bound
1917
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1918
                if (res == CheckResult.MATCH) {
3!
1919
                        return true;
×
1920
                } else if (res == CheckResult.FAIL) {
3✔
1921
                        return false;
2✔
1922
                }
1923

1924
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
1925
                        return false;
×
1926
                }
1927

1928
                // checking owner
1929
                return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1930
        }
1931

1932
        /**
1933
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1934
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1935
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1936
         * @param name of the class
1937
         * @param owner of the class
1938
         * @param candidate -- a Famix Entity
1939
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1940
         */
1941
        private boolean matchAndMapInterface(ITypeBinding bnd, String name, TNamedEntity owner, Type candidate) {
1942
                if (!(candidate instanceof Interface)) {
3!
1943
                        return false;
×
1944
                }
1945

1946
                // check whether bnd and candidate are already bound
1947
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1948
                if (res == CheckResult.MATCH) {
3!
1949
                        return true;
×
1950
                } else if (res == CheckResult.FAIL) {
3✔
1951
                        return false;
2✔
1952
                }
1953

1954
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
1955
                        return false;
×
1956
                }
1957

1958
                // checking owner
1959
                return matchAndMapTypeOwner(bnd, owner, candidate);
6✔
1960
        }
1961

1962
        /**
1963
         * Checks whether the existing unmapped Famix "Method" matches the binding.
1964
         * Checks that the candidate has the same name and same signature as the JDT bound method, and checks recursively that owners also match.
1965
         * Note that AnnotationTypeAttribute are treated as methods by JDT, so they are checked here.
1966
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1967
         * @param sig -- signature of the method
1968
         * @param retTyp -- return type of the method
1969
         * @param owner of the method
1970
         * @param candidate -- a Famix Entity (regular Method or AnnotationTypeAttribute)
1971
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1972
         */
1973
        private  boolean matchAndMapMethod(IMethodBinding bnd, String sig, TType retTyp, TNamedEntity owner, NamedEntity candidate) {
1974
                if (! (candidate instanceof Method) ) {
3✔
1975
                        return false;
2✔
1976
                }
1977

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

1987
                // checking names
1988
                String name = (sig != null) ? sig.substring(0, sig.indexOf('(')) : null;
10!
1989
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
1990
                        return false;
×
1991
                }
1992

1993
                // for methods, the name is not enough, we must test the signature also
1994
                // but not for AnnotationTypeAttribute
1995

1996
                        if (bnd != null) {
2✔
1997
                                sig = bnd.getName() + "(" + signatureParamsFromBinding(bnd) + ")";
7✔
1998
                        }
1999
                        if (! ((Method) candidate).getSignature().equals(sig)) {
6✔
2000
                                return false;
2✔
2001
                        }
2002

2003
                        // and still for method, must also check the return type
2004
                        if (bnd != null) {
2✔
2005
                                if (bnd.isConstructor()) {
3✔
2006
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
4!
2007
                                                return false;
×
2008
                                        }
2009
                                        // else OK for now
2010
                                }
2011
                                else { // not a constructor
2012
                                        if ( ((Method) candidate).getDeclaredType() == null ) {
4!
2013
                                                return false;
×
2014
                                        }
2015
                                        else if (! matchAndMapType(bnd.getReturnType(), null, null, ((Method) candidate).getDeclaredType()) ) {
10!
2016
                                                return false;
×
2017
                                        }
2018
                                        // else OK for now
2019
                                }
2020
                        }
2021
                        else {  // bnd == null
2022
                                if (retTyp == null) { // similar to (bnd.isConstructor())
2!
2023
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
4✔
2024
                                                return false;
2✔
2025
                                        }
2026
                                        // else OK for now
2027
                                } else { // (ret != null)  i.e. not a constructor
2028
                                        if (((Method) candidate).getDeclaredType() == null) {
×
2029
                                                return false;
×
2030
                                        } else if (!matchAndMapType(null, retTyp.getName(), Util.getOwner(retTyp), (NamedEntity) ((Method) candidate).getDeclaredType())) {
×
2031
                                                return false;
×
2032
                                        }
2033
                                        // else OK for now
2034
                                }
2035
                        }
2036

2037

2038
                // check owner
2039
                if (matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, Util.getOwner(candidate)) == CheckResult.MATCH) {
13✔
2040
                        conditionalMapToKey(bnd, candidate);
4✔
2041
                        return true;
2✔
2042
                } else {
2043
                        return false;
2✔
2044
                }
2045
        }
2046

2047
        /**
2048
         * Checks whether the candidate (an existing unmapped Famix "Variable" like Attribute, Parameter, ...) matches the binding.
2049
         * Checks that the candidate has the same name as the JDT bound variable, and checks recursively that owners also match.
2050
         * The Famix candidate is a NamedEntity and not a StructuralEntity to allow dealing with Famix EnumValue that JDT treats as variables
2051
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2052
         * @param name of the variable
2053
         * @param owner of the variable
2054
         * @param candidate -- a Famix Entity (a StructuralEntity or an EnumValue)
2055
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2056
         */
2057
        private boolean matchAndMapVariable(IVariableBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
2058
                if (!(candidate instanceof TStructuralEntity)) {
3!
2059
                        return false;
×
2060
                }
2061

2062
                // check whether bnd and candidate are already bound
2063
                CheckResult keyMatch = checkKeyMatch(bnd, candidate);
5✔
2064
                if (keyMatch == CheckResult.MATCH) {
3!
2065
                        return true;
×
2066
                } else if (keyMatch == CheckResult.FAIL) {
3✔
2067
                        return false;
2✔
2068
                }
2069

2070
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
2071
                        return false;
×
2072
                }
2073

2074
                // check owner
2075
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3✔
2076

2077
                // local variable or parameter ?
2078
                // owner is a Method? (for example in case of an anonymous class)
2079
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidateOwner);
11✔
2080
                if (res == CheckResult.FAIL) {
3✔
2081
                        return false;
2✔
2082
                } else if (res == CheckResult.MATCH) {
3!
2083
                        conditionalMapToKey(bnd, candidate);
×
2084
                        return true;
×
2085
                }
2086

2087
                // check owner
2088
                // <anArray>.length field?
2089
                if (name.equals("length")) {
4!
2090
                        boolean isArrayLengthField = ((bnd != null) && (bnd.getDeclaringClass() == null)) ||
×
2091
                                                                                 ((bnd == null) && (owner.getName().equals(EntityDictionary.ARRAYS_NAME)));
×
2092
                        if (isArrayLengthField) {
×
2093
                                if (candidateOwner.getName().equals(EntityDictionary.ARRAYS_NAME)) {
×
2094
                                        conditionalMapToKey(bnd, candidate);
×
2095
                                        return true;
×
2096
                                }
2097
                                else {
2098
                                        return false;
×
2099
                                }
2100
                        }
2101
                }
2102

2103
                // check owner
2104
                // "normal" field?
2105
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2106
                if (res == CheckResult.MATCH) {
3!
2107
                        conditionalMapToKey(bnd, candidate);
4✔
2108
                        return true;
2✔
2109
                }
2110
                return false;
×
2111
        }
2112

2113
        /**
2114
         * Checks whether the existing unmapped Famix Type's parent (or owner) matches the binding's owner.
2115
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
2116
         * @param bnd -- a JDT binding whose owner we are trying to match to the candidate's owner
2117
         * @param owner -- the owner of the type
2118
         * @param candidate -- a Famix Entity
2119
         * @return whether we found a match (if <b>true</b>, the mapping is recorded)
2120
         */
2121
        private boolean matchAndMapTypeOwner(ITypeBinding bnd, TNamedEntity owner, Type candidate) {
2122
                ContainerEntity candidateOwner = Util.getOwner(candidate);
4✔
2123

2124
                // owner is a Method? (for example in case of an anonymous class)
2125
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11✔
2126
                if (res == CheckResult.MATCH) {
3!
2127
                        conditionalMapToKey(bnd, candidate);
×
2128
                        return true;
×
2129
                } else if (res == CheckResult.FAIL) {
3!
2130
                        return false;
×
2131
                }
2132

2133
                // owner is a class ?
2134
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2135
                if (res == CheckResult.MATCH) {
3✔
2136
                        conditionalMapToKey(bnd, candidate);
4✔
2137
                        return true;
2✔
2138
                }
2139
                else if (res == CheckResult.FAIL) {
3✔
2140
                        return false;
2✔
2141
                }
2142

2143
                // owner must be a package
2144
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12✔
2145
                        conditionalMapToKey(bnd, candidate);
4✔
2146
                        return true;
2✔
2147
                }
2148
                return false;
2✔
2149
        }
2150

2151
        /**
2152
         * Check whether the owner of candidates is a method macthinf either methBnd or owner
2153
         * @param methBnd
2154
         * @param owner
2155
         * @param candidateOwner
2156
         * @return a {@link CheckResult}
2157
         */
2158
        private  <T extends TNamedEntity> CheckResult matchAndMapOwnerAsMethod(IMethodBinding methBnd, T owner, T candidateOwner) {
2159
                if ((methBnd != null) || (owner instanceof Method)) {
5!
2160
                        if (!(candidateOwner instanceof Method)) {
3!
2161
                                return CheckResult.FAIL;
×
2162
                        }
2163

2164
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7!
2165
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7!
2166
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8!
2167

2168
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9!
2169
                                return CheckResult.MATCH;
×
2170
                        } else {
2171
                                return CheckResult.FAIL;
2✔
2172
                        }
2173
                }
2174
                return CheckResult.UNDECIDED;
2✔
2175
        }
2176

2177
        /**
2178
         * @param typBnd
2179
         * @param owner
2180
         * @param candidateOwner
2181
         * @return a {@link CheckResult}
2182
         */
2183
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2184
                if ((typBnd != null) || (owner instanceof Type)) {
5✔
2185
                        if (!(candidateOwner instanceof Type)) {
3✔
2186
                                return CheckResult.FAIL;
2✔
2187
                        }
2188

2189
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6!
2190
                        String ownerName = (owner != null) ? owner.getName() : null;
6!
2191

2192
                        if (matchAndMapType(typBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2193
                                return CheckResult.MATCH;
2✔
2194
                        } else {
2195
                                return CheckResult.FAIL;
2✔
2196
                        }
2197
                }
2198
                return CheckResult.UNDECIDED;
2✔
2199
        }
2200

2201
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2202
                if ((pckgBnd != null) || (owner instanceof Package)) {
5!
2203
                        if (!(candidateOwner instanceof Package)) {
3!
2204
                                return CheckResult.FAIL;
×
2205
                        }
2206

2207
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7!
2208
                        String ownerName = (owner != null) ? owner.getName() : null;
6!
2209

2210
                        if (matchAndMapPackage(pckgBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2211
                                return CheckResult.MATCH;
2✔
2212
                        } else {
2213
                                return CheckResult.FAIL;
2✔
2214
                        }
2215
                }
2216
                return CheckResult.UNDECIDED;
×
2217
        }
2218

2219
        /**
2220
         * Checks whether the name and the candidate matches the name of the entity (given either by 'bnd' or 'name')<br>
2221
         * 'name' and 'bnd' cannot be null together
2222
         * @param bnd -- binding associated with the entity may be null
2223
         * @param name -- name of the entity may be null
2224
         * @param candidate
2225
         * @return true if names match, false if not
2226
         */
2227
        private CheckResult checkNameMatch(IBinding bnd, String name, TNamedEntity candidate) {
2228
                if ( (bnd != null) && (! bnd.getName().equals(candidate.getName())) ) {
8!
2229
                        return CheckResult.FAIL;
×
2230
                }
2231
                else if ( (bnd == null) && (name != null) && (! name.equals(candidate.getName())) ) {
9!
2232
                        return CheckResult.FAIL;
2✔
2233
                }
2234
                else {
2235
                        return CheckResult.MATCH;
2✔
2236
                }
2237
        }
2238

2239
        /**
2240
         * Check whether key and candidate are already bound together, whether either is bound to something else, or whether none is bound
2241
         * @param key
2242
         * @param candidate
2243
         * @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>
2244
         */
2245
        private CheckResult checkKeyMatch(IBinding key, TNamedEntity candidate) {
2246
                if (key == null) {
2✔
2247
                        return CheckResult.UNDECIDED;
2✔
2248
                }
2249

2250
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5✔
2251
                if (bound == candidate) {
3✔
2252
                        return CheckResult.MATCH;
2✔
2253
                }
2254
                else if (bound != null) {
2✔
2255
                        return CheckResult.FAIL;
2✔
2256
                }
2257
                else if (getEntityKey(candidate) != null) {
4✔
2258
                        // candidate already bound, and not to this binding
2259
                        return CheckResult.FAIL;
2✔
2260
                }
2261
                else {
2262
                        return CheckResult.UNDECIDED;
2✔
2263
                }
2264
        }
2265

2266
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2267
                if (bnd != null) {
2✔
2268
                        mapEntityToKey(bnd, ent);
4✔
2269
                }
2270
        }
1✔
2271

2272
        public Method ensureFamixMethod(IMethodBinding bnd) {
2273
                return ensureFamixMethod(
8✔
2274
                                bnd,
2275
                                /*name*/null,
2276
                                /*paramsType*/null,
2277
                                /*returnType*/null,
2278
                                /*owner*/null,
2279
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6✔
2280
        }
2281

2282
        /**
2283
         * Returns a Famix Method associated with the IMethodBinding. The Entity is created if it does not exist.
2284
         * The Entity is created if it does not exist.
2285
         * @param name -- the name of the Famix Method (MUST NOT be null, but this is not checked)
2286
         * @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)
2287
         * @param owner -- type defining the method (should not be null, but it will work if it is)
2288
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2289
         */
2290
        public Method ensureFamixMethod(IMethodBinding bnd, String name, Collection<String> paramTypes, TType ret, TWithMethods owner, int modifiers) {
2291
                Method fmx;
2292
                String signature;
2293
                boolean delayedRetTyp;
2294

2295
                // --------------- to avoid useless computations if we can
2296
                fmx = (Method)getEntityByKey(bnd);
5✔
2297
                if (fmx != null) {
2✔
2298
                        return fmx;
2✔
2299
                }
2300

2301
                // --------------- name
2302
                if (name == null) {
2✔
2303
                        if (bnd == null) {
2✔
2304
                                return null;
2✔
2305
                        }
2306
                        else {
2307
                                name = bnd.getName();
3✔
2308
                        }
2309
                }
2310

2311
                // --------------- signature
2312
                signature = name + "(";
3✔
2313
                 if (bnd != null) {
2✔
2314
                    signature += signatureParamsFromBinding(bnd);
7✔
2315
                }
2316
        else if (paramTypes != null) {
2!
2317
                        signature += signatureParamsFromStringCollection(paramTypes);
7✔
2318
                }
2319
                else {
2320
                        signature += "???";
×
2321
                }
2322
                signature += ")";
3✔
2323

2324
                // --------------- return type
2325
                delayedRetTyp = false;
2✔
2326
                ITypeBinding retTypBnd = null;
2✔
2327
                if (ret == null) {
2!
2328
                        if (bnd != null) {
2✔
2329
                // must create the return type
2330
                // but for method like "<T> T mtd()" where T belongs to mtd and mtd returns T,
2331
                // we need T to create the method and the method to create T ...
2332
                // so we need to test the situation and deal with it
2333
                retTypBnd = bnd.getReturnType();
3✔
2334
                if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9✔
2335
                    delayedRetTyp = true;
3✔
2336
                }
2337
                else {
2338
                        ret = this.referredType(retTypBnd, fmx);
5✔
2339
                }
2340
                        }
2341
                }
2342

2343
                // --------------- owner
2344
                if (owner == null) {
2✔
2345
                        if (bnd == null) {
2✔
2346
                                owner = ensureFamixClassStubOwner();
4✔
2347
                        }
2348
                        else {
2349
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4✔
2350
                                if (classBnd != null) {
2!
2351
                                        owner = ensureFamixType(classBnd);
5✔
2352
                                }
2353
                                else {
2354
                                        owner = ensureFamixClassStubOwner();
×
2355
                                }
2356
                        }
2357
                }
2358

2359
                // --------------- recover from name ?
2360
                for (Method candidate : this.getEntityByName(Method.class, name)) {
13✔
2361
                        if (matchAndMapMethod(bnd, signature, ret, (TNamedEntity) owner, candidate)) {
9✔
2362
                                fmx = candidate;
2✔
2363
                                break;
1✔
2364
                        }
2365
                }
1✔
2366

2367
                if (fmx == null) {
2✔
2368
                        if(bnd != null && bnd.isGenericMethod()) {
5✔
2369
                                fmx = ensureFamixEntity(ParametricMethod.class, bnd, name);
7✔
2370
                                for(ITypeBinding param: bnd.getTypeParameters()) {
18✔
2371
                                        TypeParameter fmxParam = this.ensureFamixTypeParameter(param, null, fmx);
6✔
2372
                                        fmxParam.setGenericEntity((ParametricMethod)fmx);
4✔
2373
                                }
2374
                        // Parameterized method binding = when the method is the target of an invocation.
2375
                        } else if (bnd != null && bnd.isParameterizedMethod()) {
5!
2376
                                fmx = this.ensureFamixMethod(bnd.getMethodDeclaration());
×
2377
                        } else {
2378
                if (bnd != null && bnd.isConstructor()) {
5✔
2379
                    fmx = ensureFamixEntity(Initializer.class, bnd, name);
8✔
2380
                } else {
2381
                    fmx = ensureFamixEntity(Method.class, bnd, name);
7✔
2382
                }
2383
            }
2384

2385
                        fmx.setSignature(signature);
3✔
2386
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
7✔
2387
                        ensureFamixEntityTyping(returnTypeBnd, fmx, ret);
6✔
2388
                        fmx.setParentType(owner);
3✔
2389
                }
2390

2391
                if (fmx != null) {
2!
2392
                        setMethodModifiers(fmx, modifiers);
4✔
2393
                }
2394

2395
        //If it has the #default keywork, we mark it as default implementation
2396
        if (Modifier.isDefault(modifiers)) {
3✔
2397
            fmx.setKind(DEFAULT_IMPLEMENTATION_KIND_MARKER);
3✔
2398
        }
2399

2400
        if (delayedRetTyp) {
2✔
2401
                        int retTypModifiers = retTypBnd.getModifiers();
3✔
2402
                        ITypeBinding returnTypeBnd = bnd.getReturnType();
3✔
2403
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13✔
2404
                }
2405

2406
                return fmx;
2✔
2407
        }
2408

2409

2410
        /**
2411
         * Creates or recovers the initializer method containing the attribute initializations of a type.
2412
         * @param owner Type containing the initializer
2413
         * @param isStatic Modifier of the initializer. A type can have 2 initializers for attribute initialization: 1 static and 1 not.
2414
         * @param isInitializationBlock True if the entity is an initialization block. False for the artificial method containing all field initializations.
2415
         * @return the FamixInitializer
2416
         */
2417
        public Initializer ensureFamixInitializer(TWithMethods owner, Boolean isStatic, Boolean isInitializationBlock) {
2418
                Initializer fmx = null;
2✔
2419

2420
                if (owner != null) {
2!
2421
                        Optional<TMethod> existingInitializer = owner.getMethods().stream()
6✔
2422
                                        .filter(meth ->
1✔
2423
                                                        ((Method) meth).getIsInitializer() &&
8✔
2424
                                                        ((Method) meth).getIsConstructor().equals(false) &&
7✔
2425
                                                        ((Method) meth).getIsClassSide().equals(isStatic) &&
6✔
2426
                                                        ((Initializer) meth).getIsInitializationBlock().equals(isInitializationBlock))
7✔
2427
                                        .findFirst();
2✔
2428
                        if (existingInitializer.isPresent()) {
3✔
2429
                                fmx = (Initializer) existingInitializer.get();
4✔
2430
                        }
2431
                }
2432

2433
                if (fmx == null) {
2✔
2434
                        fmx = new Initializer();
4✔
2435
                        fmx.setName(INIT_BLOCK_NAME);
3✔
2436
                        fmx.setSignature(INIT_BLOCK_NAME + "()" );
3✔
2437
                        fmx.setVisibility(MODIFIER_PRIVATE);
3✔
2438
                        fmx.setParentType(owner);
3✔
2439
                        fmx.setIsClassSide(isStatic);
3✔
2440
                        fmx.setIsInitializationBlock(isInitializationBlock);
3✔
2441
                }
2442

2443
                return fmx;
2✔
2444
        }
2445

2446

2447
        public Initializer ensureImplicitConstructor(TWithMethods owner, String name, Collection<String> parameterTypesNames) {
2448
                Initializer fmx = null;
2✔
2449

2450
                if (owner != null) {
2!
2451
                        Optional<TMethod> existingInitializer = owner.getMethods().stream()
5✔
2452
                                        .filter(meth ->
1✔
2453
                                                        ((Method) meth).getIsInitializer() &&
8✔
2454
                                                                        ((Method) meth).getIsConstructor()
4✔
2455
                                                                        && meth.getParameters().size() == parameterTypesNames.size()
6✔
2456
                                                                        && (parameterTypesNames.stream().allMatch(parameterName -> meth.getSignature().contains(parameterName))) )
13!
2457
                                        .findFirst();
2✔
2458
                        if (existingInitializer.isPresent()) {
3✔
2459
                                fmx = (Initializer) existingInitializer.get();
4✔
2460
                        }
2461
                }
2462

2463
                if (fmx == null) {
2✔
2464
                        fmx = ensureFamixEntity(Initializer.class, null, name);
7✔
2465
                        fmx.setParentType(owner);
3✔
2466
                        fmx.setSignature(name + "()");
4✔
2467

2468
                }
2469

2470
                return fmx;
2✔
2471
        }
2472

2473
        /**
2474
         * Creates or recovers a stub Famix Method
2475
         * @param name of the method
2476
         * @return the Famix Method
2477
         */
2478
        public Method ensureFamixStubMethod(String name) {
2479
                return ensureFamixMethod(null, name, /*paramType*/null, /*returnType*/null, ensureFamixClassStubOwner(), /*modifiers*/0);
×
2480
        }
2481

2482
        public void setAttributeModifiers(Attribute fmx, int mod) {
2483
                setCommonModifiers(fmx, mod);
4✔
2484
                fmx.setIsTransient(Modifier.isTransient(mod));
5✔
2485
                fmx.setIsVolatile(Modifier.isVolatile(mod));
5✔
2486
        }
1✔
2487

2488
        public void setMethodModifiers(Method fmx, int mod) {
2489
                setCommonModifiers(fmx, mod);
4✔
2490
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2491
                fmx.setIsSynchronized(Modifier.isSynchronized(mod));
5✔
2492
        }
1✔
2493

2494
        public void setClassModifiers(Class fmx, int mod) {
2495
                setCommonModifiers(fmx, mod);
4✔
2496
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2497
        }
1✔
2498

2499
        public void setInterfaceModifiers(Interface fmx, int mod) {
2500
                setCommonModifiers(fmx, mod);
4✔
2501
        }
1✔
2502

2503
        private void setCommonModifiers(Entity fmx, int mod) {
2504
                setVisibility((THasVisibility)fmx, mod);
5✔
2505
                ((TCanBeClassSide)fmx).setIsClassSide(Modifier.isStatic(mod));
6✔
2506
                ((TCanBeFinal)fmx).setIsFinal(Modifier.isFinal(mod));
6✔
2507
        }
1✔
2508

2509
        /**
2510
         * Sets the visibility of a FamixNamedEntity
2511
         *
2512
         * @param fmx -- the FamixNamedEntity
2513
         * @param mod -- a description of the modifiers as understood by org.eclipse.jdt.core.dom.Modifier
2514
         */
2515
        public void setVisibility(THasVisibility fmx, int mod) {
2516
                if (Modifier.isPublic(mod)) {
3✔
2517
                        fmx.setVisibility(MODIFIER_PUBLIC);
4✔
2518
                } else if (Modifier.isPrivate(mod)) {
3✔
2519
                        fmx.setVisibility(MODIFIER_PRIVATE);
4✔
2520
                } else if (Modifier.isProtected(mod)) {
3✔
2521
                        fmx.setVisibility(MODIFIER_PROTECTED);
4✔
2522
                } else {
2523
                        fmx.setVisibility(MODIFIER_PACKAGE);
3✔
2524
                }
2525
        }
1✔
2526

2527
        /**
2528
         * Returns a Famix Attribute associated with the IVariableBinding.
2529
         * The Entity is created if it does not exist.<br>
2530
         * @param name -- the name of the FAMIX Attribute (MUST NOT be null, but this is not checked)
2531
         * @param type -- Famix Type of the Attribute (should not be null, but it will work if it is)
2532
         * @param owner -- type defining the Attribute (should not be null, but it will work if it is)
2533
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2534
         */
2535
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, Type type, TWithAttributes owner) {
2536
                Attribute fmx;
2537

2538
                // --------------- to avoid useless computations if we can
2539
                fmx = (Attribute)getEntityByKey(bnd);
5✔
2540
                if (fmx != null) {
2✔
2541
                        return fmx;
2✔
2542
                }
2543

2544
                // --------------- name
2545
                if (name == null) {
2!
2546
                        if (bnd == null) {
×
2547
                                return null;
×
2548
                        }
2549
                        else {
2550
                                name = bnd.getName();
×
2551
                        }
2552
                }
2553

2554
                // --------------- owner
2555
                if (owner == null) {
2✔
2556
                        if (bnd == null) {
2!
2557
                                return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
×
2558
                        }
2559
                        else {
2560
                                if (bnd.getDeclaringClass() != null && bnd.getDeclaringClass().getErasure() != null) {
7!
2561
                                        // Declaring class is the generic one if the class is parametric.
2562
                                        owner = (TWithAttributes)ensureFamixType(bnd.getDeclaringClass().getErasure());
8✔
2563
                                } else {
2564
                                        return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
2✔
2565
                                }
2566
                        }
2567
                }
2568

2569
                // --------------- recover from name ?
2570
                for (Attribute candidate : getEntityByName(Attribute.class, name)) {
13✔
2571
                        if (matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate)) {
8✔
2572
                                fmx = candidate;
2✔
2573
                                break;
1✔
2574
                        }
2575
                }
1✔
2576

2577
                if (fmx == null) {
2✔
2578
                        fmx = ensureFamixEntity(Attribute.class, bnd, name);
7✔
2579
                        fmx.setParentType( owner);
3✔
2580
                }
2581

2582
        fmx.setParentType(owner);
3✔
2583
        ITypeBinding declaredTypeBinding = (bnd == null) ? null : bnd.getType();
7✔
2584
        ensureFamixEntityTyping(declaredTypeBinding, fmx, type);
6✔
2585
        if (bnd != null) {
2✔
2586
            int mod = bnd.getModifiers();
3✔
2587
            setAttributeModifiers(fmx, mod);
4✔
2588
        }
2589

2590
        return fmx;
2✔
2591
        }
2592

2593
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2594
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2595
        }
2596

2597
        /**
2598
         * helper method, we know the var exists, ensureFamixAttribute will recover it
2599
         */
2600
        public Attribute getFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2601
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2602
        }
2603

2604
        /**
2605
         * Returns a Famix Parameter associated with the IVariableBinding.
2606
         * The Entity is created if it does not exist.<br>
2607
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2608
         */
2609
        public Parameter ensureFamixParameter(IVariableBinding bnd, String name, Type typ, TMethod tMethod) {
2610
                Parameter fmx = null;
2✔
2611

2612
                // --------------- to avoid useless computations if we can
2613
                try {
2614
                        fmx = (Parameter)getEntityByKey(bnd);
5✔
2615
                }catch(Throwable e) {
×
2616
                        e.printStackTrace();
×
2617
                }
1✔
2618
                if (fmx != null) {
2✔
2619
                        return fmx;
2✔
2620
                }
2621

2622
                // --------------- name
2623
                if (name == null) {
2!
2624
                        if (bnd == null) {
×
2625
                                return null;
×
2626
                        }
2627
                        else {
2628
                                name = bnd.getName();
×
2629
                        }
2630
                }
2631

2632
                // --------------- owner
2633
                if (tMethod == null) {
2!
2634
                        if (bnd == null) {
×
2635
                                tMethod = ensureFamixStubMethod("<"+name+"_owner>");
×
2636
                        }
2637
                        else {
2638
                                tMethod = ensureFamixMethod(bnd.getDeclaringMethod());
×
2639
                        }
2640
                }
2641

2642
                // --------------- recover from name ?
2643
                for (Parameter candidate : getEntityByName(Parameter.class, name) ) {
13✔
2644
                        if ( matchAndMapVariable(bnd, name, tMethod, candidate) ) {
7!
2645
                                fmx = candidate;
×
2646
                                break;
×
2647
                        }
2648
                }
1✔
2649

2650
                if (fmx == null) {
2!
2651
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7✔
2652
                }
2653

2654
                if (fmx != null) {
2!
2655
                        fmx.setParentBehaviouralEntity(tMethod);
3✔
2656
                        ITypeBinding declaredTypeBnd = (bnd == null) ? null : bnd.getType();
5!
2657
                        ensureFamixEntityTyping(declaredTypeBnd, fmx, typ);
6✔
2658
                }
2659

2660
                return fmx;
2✔
2661
        }
2662

2663
    /**
2664
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2665
         * The Entity is created if it does not exist.<br>
2666
         * @param name -- the name of the FAMIX LocalVariable
2667
         * @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
2668
         */
2669
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2670
                LocalVariable fmx;
2671

2672
                // --------------- to avoid useless computations if we can
2673
                fmx = (LocalVariable)getEntityByKey(bnd);
5✔
2674
                if (fmx != null) {
2!
2675
                        return fmx;
×
2676
                }
2677

2678
                // --------------- name
2679
                if (name == null) {
2!
2680
                        if (bnd == null) {
×
2681
                                return null;
×
2682
                        }
2683
                        else {
2684
                                name = bnd.getName();
×
2685
                        }
2686
                }
2687

2688
                // --------------- owner
2689
                if (owner == null) {
2!
2690
                        if (bnd == null) {
×
2691
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2692
                        }
2693
                        else {
2694
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2695
                        }
2696
                }
2697

2698
                // --------------- recover from name ?
2699
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13✔
2700
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8!
2701
                                fmx = candidate;
×
2702
                                break;
×
2703
                        }
2704
                }
1✔
2705

2706
                if (fmx == null) {
2!
2707
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7✔
2708
                        fmx.setParentBehaviouralEntity(owner);
3✔
2709
                }
2710

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

2714
        return fmx;
2✔
2715
        }
2716

2717
    /**
2718
         * Returns a FAMIX ImplicitVariable with the given <b>name</b> ("self" or "super") and corresponding to the <b>type</b>.
2719
         * If this ImplicitVariable does not exist yet, it is created
2720
         * @param name -- the name of the FAMIX ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
2721
         * @param type -- the Famix Type for this ImplicitVariable (should not be null)
2722
         * @param tMethod -- the ContainerEntity where the implicit variable appears (should be a method inside <b>type</b>)
2723
         * @return the FAMIX ImplicitVariable or null in case of a FAMIX error
2724
         */
2725
        public ImplicitVariable ensureFamixImplicitVariable(IBinding key, String name, TType type, TMethod tMethod) {
2726
                ImplicitVariable fmx;
2727
                fmx = ensureFamixEntity(ImplicitVariable.class, key, name);
7✔
2728
                fmx.setParentBehaviouralEntity(tMethod);
3✔
2729
                return fmx;
2✔
2730
        }
2731

2732
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2733
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4✔
2734
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7✔
2735
        }
2736

2737
        /**
2738
         * Creates and returns a Famix Comment and associates it with an Entity (ex: for Javadocs)
2739
         * @param jCmt -- the content (String) of the comment 
2740
         * @param owner -- the entity that is commented
2741
         * @return the Famix Comment
2742
         */
2743
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner) {
2744
                Comment cmt = null;
2✔
2745

2746
                if ( (jCmt != null) && (owner != null) ) {
4!
2747
                        
2748
                        cmt = new Comment();
4✔
2749
                        addSourceAnchor(cmt, jCmt);
5✔
2750
                        famixRepoAdd(cmt);
3✔
2751
                        cmt.setCommentedEntity(owner);
3✔
2752
                }
2753

2754
                return cmt;
2✔
2755
        }
2756

2757
        /**
2758
         * Creates and returns a Famix Comment and associates it with an Entity
2759
         * @param jCmt -- the content (String) of the comment 
2760
         * @param owner -- the entity that is commented
2761
         * @param content -- the text of the comment
2762
         * @return the Famix Comment
2763
         */
2764
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner, String content) {
2765
                Comment cmt = null;
2✔
2766

2767
                if ( (jCmt != null) && (owner != null) ) {
4!
2768
                        cmt = new Comment();
4✔
2769
                        cmt.setContent(content );
3✔
2770
                        famixRepoAdd(cmt);
3✔
2771
                        cmt.setCommentedEntity(owner);
3✔
2772
                }
2773

2774
                return cmt;
2✔
2775
        }
2776

2777
        /**
2778
         * Adds location information to a Famix Entity.
2779
         * 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.
2780
         * This method also creates some basic links between the entity and others (e.g. declaring container, return type, ...)
2781
         * @param fmx -- Famix Entity to add the anchor to
2782
         * @param node -- JDT ASTNode, where the information is extracted
2783
         * @return the Famix SourceAnchor added to fmx. May be null in case of incorrect parameter ('fmx' or 'ast' == null)
2784
         */
2785
        public SourceAnchor addSourceAnchor(TSourceEntity fmx, ASTNode node) {
2786
                IndexedFileAnchor fa;
2787

2788
                fa = createIndexedFileAnchor(node);
4✔
2789
                if ((fmx != null) && (fa != null)) {
4!
2790
                        fmx.setSourceAnchor(fa);
3✔
2791
                        famixRepoAdd(fa);
3✔
2792
                }
2793

2794
                return fa;
2✔
2795
        }
2796

2797
        /**
2798
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2799
         */
2800
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2801
                IndexedFileAnchor fa;
2802

2803
                fa = createIndexedFileAnchor(node);
4✔
2804
                if ((fmx != null) && (fa != null)) {
4!
2805

2806
                        // may change the positions
2807
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4✔
2808
                        methodDeclarationModifiers.addAll(node.modifiers());
5✔
2809
                        if (node.getName() != null) {
3!
2810
                                methodDeclarationModifiers.add(node.getName());
5✔
2811
                        }
2812
                        if (node.getReturnType2() != null) {
3✔
2813
                                methodDeclarationModifiers.add(node.getReturnType2());
5✔
2814
                        }
2815
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12✔
2816
                        int end = node.getStartPosition() + node.getLength();
6✔
2817

2818
                        fa.setStartPos(beg);
4✔
2819
                        fa.setEndPos(end);
4✔
2820

2821
                        fmx.setSourceAnchor(fa);
3✔
2822
                        famixRepoAdd(fa);
3✔
2823
                }
2824

2825
                return fa;
2✔
2826
        }
2827

2828
        /**
2829
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2830
         * Information returned in the form of an IndexedFileAnchor
2831
         */
2832
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2833
                IndexedFileAnchor fa;
2834
                
2835
                if (node == null) {
2!
2836
                        return null;
×
2837
                }
2838

2839
                // position in source file
2840
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5✔
2841
                int end = beg + node.getLength() - 1;
7✔
2842

2843
                // find source Compilation Unit
2844
                // there is a special case for the JDT Comment Nodes
2845
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3✔
2846
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5✔
2847
                } else {
2848
                        node = node.getRoot();
3✔
2849
                }
2850

2851
                fa = new IndexedFileAnchor();
4✔
2852
                fa.setStartPos(beg);
4✔
2853
                fa.setEndPos(end);
4✔
2854

2855
                fa.setFileName((String) node.getProperty(SOURCE_FILENAME_PROPERTY));
6✔
2856

2857
                return fa;
2✔
2858
        }
2859

2860
        /**
2861
         * Creates or recovers the Famix Class for "Object".
2862
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2863
         *
2864
         * @return a Famix class for "Object"
2865
         */
2866
        public Class ensureFamixClassObject() {
2867
        // 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...
2868
        Collection<Class> objects = getEntityByName(Class.class, "Object");
5✔
2869

2870
        for (Class entity : objects) {
10✔
2871
                //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2872
                if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7✔
2873
                    return entity;
2✔
2874
                }
2875
        }
1✔
2876

2877
        Class fmx = createFamixEntity(Class.class, "Object");
6✔
2878
        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5✔
2879
                return fmx;
2✔
2880
        }
2881

2882
        /***
2883
         * We treat array types as parametrized types Array<T>.
2884
         * This keeps the meta-model simple: a single way to model different concepts.
2885
         * @return
2886
         */
2887
        public ParametricClass ensureParametricArrayClass() {
2888
                
2889
                Collection<ParametricClass> arrayClasses = getEntityByName(ParametricClass.class, "Array");
5✔
2890
                
2891
                for (ParametricClass entity : arrayClasses) {
10✔
2892
            //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2893
            if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7!
2894
                return entity;
2✔
2895
            }
NEW
2896
                }
×
2897
                
2898
                //Create the parametric class
2899
                ParametricClass arrayClass = createFamixEntity(ParametricClass.class, "Array"); 
6✔
2900

2901
                //And now add the type parameter
2902
                TypeParameter fmxParam = this.ensureFamixTypeParameter(null, "T", arrayClass);
6✔
2903
                fmxParam.setGenericEntity(arrayClass);
3✔
2904
                fmxParam.setIsStub(true);
4✔
2905
                
2906
                //And the class is in java.lang
2907
                arrayClass.setTypeContainer(ensureFamixPackageJavaLang(null));
5✔
2908
                
2909
                return arrayClass;
2✔
2910
        }
2911

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

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

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

2927
                return fmx;
2✔
2928
        }
2929

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

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

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

2957
                return fmx;
×
2958
        }
2959

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

2971
                return ret;
2✔
2972
        }
2973

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

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

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

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

3009
        public String findTypeName(org.eclipse.jdt.core.dom.Type t) {
NEW
3010
                if (t == null) {
×
NEW
3011
                        return null;
×
3012
                }
3013

NEW
3014
                if (t.isPrimitiveType()) {
×
NEW
3015
                        return t.toString();
×
NEW
3016
                } else if (t.isSimpleType()) {
×
NEW
3017
                        String fullName = ((SimpleType) t).getName().getFullyQualifiedName();
×
NEW
3018
                        int i = fullName.lastIndexOf('.');
×
NEW
3019
                        if (i > 0) {
×
NEW
3020
                                return fullName.substring(i+1);
×
3021
                        }
3022
                        else {
NEW
3023
                                return fullName;
×
3024
                        }
NEW
3025
                } else if (t.isQualifiedType()) {
×
NEW
3026
                        return ((QualifiedType) t).getName().getIdentifier();
×
NEW
3027
                } else if (t.isArrayType()) {
×
NEW
3028
                        return findTypeName(((ArrayType) t).getElementType());
×
NEW
3029
                } else if (t.isParameterizedType()) {
×
NEW
3030
                        return findTypeName(((org.eclipse.jdt.core.dom.ParameterizedType) t).getType());
×
3031
                } else { // it is a WildCardType
NEW
3032
                        if (((org.eclipse.jdt.core.dom.WildcardType) t).isUpperBound()) {
×
NEW
3033
                                return findTypeName(((org.eclipse.jdt.core.dom.WildcardType) t).getBound());
×
3034
                        } else {
NEW
3035
                                return EntityDictionary.OBJECT_NAME;
×
3036
                        }
3037
                }
3038
        }
3039

3040
        /**
3041
         * Ensures the proper creation of a FamixType for JDT typ in the given context.
3042
         * Useful for parameterizedTypes, or classInstance.
3043
         *
3044
         * @param isClass we are sure that the type is actually a class
3045
         * @return a famix type or null
3046
         */
3047
        public <T extends TWithTypes & TNamedEntity> TType referredType(org.eclipse.jdt.core.dom.Type typ, T ctxt, boolean isClass) {
3048
                return this.referredType(typ, ctxt, isClass, /*isExcep*/false);
7✔
3049
        }
3050
        
3051
        /**
3052
         * Ensures the proper creation of a FamixType for JDT type in the given context.
3053
         * Useful for parameterizedTypes, or classInstance.
3054
         *
3055
         * @param isClass we are sure that the type is actually a class
3056
         * @return a famix type or null
3057
         */
3058
        public <T extends TWithTypes & TNamedEntity> TType referredType(org.eclipse.jdt.core.dom.Type typ, T ctxt, boolean isClass, boolean isException) {
3059
                if (typ == null) {
2!
NEW
3060
                        return null;
×
3061
                } else if (typ.resolveBinding() != null) {
3!
3062
                        return this.referredType(typ.resolveBinding(), ctxt);
7✔
3063
                }
3064
                // from here, we assume the owner is the context
NEW
3065
                else if (isClass && !isException) {
×
NEW
3066
                        return this.ensureFamixClass(null, findTypeName(typ), /*owner*/ctxt, /*isGeneric*/false,
×
3067
                                        EntityDictionary.UNKNOWN_MODIFIERS);
NEW
3068
                } else if (isException) {
×
3069
                        // return ensure FamixException
NEW
3070
                        return this.ensureFamixException(null, findTypeName(typ), (ContainerEntity) /*owner*/ctxt, /*isGeneric*/false,
×
3071
                                        EntityDictionary.UNKNOWN_MODIFIERS);
3072
                } else {
NEW
3073
                        while (typ.isArrayType()) {
×
NEW
3074
                                typ = ((ArrayType) typ).getElementType();
×
3075
                        }
3076

NEW
3077
                        if (typ.isPrimitiveType()) {
×
NEW
3078
                                return this.ensureFamixPrimitiveType(null, findTypeName(typ));
×
3079
                        } else {
NEW
3080
                                return this.ensureFamixType(null, findTypeName(typ), /*owner*/ctxt, /*container*/ctxt,
×
3081
                                                EntityDictionary.UNKNOWN_MODIFIERS);
3082
                        }
3083
                }
3084
        }
3085
        
3086
        public TType referredType(ITypeBinding bnd, TNamedEntity ctxt) {
3087
                return this.referredType(bnd, ctxt, 0);
6✔
3088
        }
3089
        
3090
        public TType referredType(ITypeBinding bnd, TNamedEntity ctxt, int extraDimensions) {
3091
                TType fmxTyp = null;
2✔
3092

3093
                if (bnd == null) {
2✔
3094
                        return null;
2✔
3095
                }
3096

3097
                String name;
3098
                //Three cases here:
3099
                // - the type binding knows it's an array
3100
                // - the binding is not declared as array, but it has dimensions > 0
3101
                // - the dimension is not in the type but in the variable declaration (thus extra)
3102
                if (bnd.isArray() || bnd.getDimensions() + extraDimensions > 0) {
8✔
3103
                        // We treat array types as parametrized types Array<T>.
3104
                        // This keeps the meta-model simple: a single way to model different concepts.
3105
                        return this.ensureParametricArrayClass();
3✔
3106
                }
3107
                name = bnd.getName();
3✔
3108

3109
                if ( bnd.isParameterizedType() ) {
3✔
3110
                        
3111
                        // remove type parameters from the name even for parameterized interfaces
3112
                        int i = name.indexOf('<');
4✔
3113
                        if (i > 0) {
2!
3114
                                name = name.substring(0, i);
5✔
3115
                        }
3116

3117
                        ITypeBinding parameterizableBnd = bnd.getErasure();
3✔
3118
                        int modifiers = (parameterizableBnd != null) ? parameterizableBnd.getModifiers() : EntityDictionary.UNKNOWN_MODIFIERS;
6!
3119
                        
3120
                        if(parameterizableBnd != null && parameterizableBnd.isInterface()) {
5!
3121
                                fmxTyp = (ParametricInterface) this.ensureFamixInterface(parameterizableBnd, name, /*owner*/null, /*isGeneric*/true, modifiers);
10✔
3122
                        } else {
3123
                                fmxTyp = (ParametricClass) this.ensureFamixClass(parameterizableBnd, name, /*owner*/null, /*isGeneric*/true, modifiers);
9✔
3124
                        }
3125
                } else if ( (name != null) && name.equals("var") ) {
7!
3126
                        fmxTyp = this.ensureFamixUniqEntity(org.moosetechnology.model.famix.famixjavaentities.Type.class, /*binding*/null, EntityDictionary.IMPLICIT_VAR_TYPE_NAME);        
8✔
3127
                } else {
3128
                        fmxTyp = this.ensureFamixType(bnd, name, /*owner*/null, (TWithTypes) ctxt, bnd.getModifiers());
10✔
3129
                }
3130

3131
                return fmxTyp;
2✔
3132
        }
3133

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

© 2026 Coveralls, Inc